Fortran
clang
flang

mainの無いFortanのコードをCのコードから呼び出して動かす

今回の環境

Cの処理系: clang
Fortranの処理系: Flang
OS: Linux

Fortranのコード

以下の様なFortranのコードを試した。

arraytest.f90
function array_1d(b,c) bind(c, name = 'array_1d')
      implicit none
      integer,intent(in),value::b,c
      integer::array_1d,k
      integer a(0:3)
      complex(kind(0d0))::ca(0:100)

      a(0) = b
      a(1) = c
      a(2) = b+c
      a(0) = a(0)*a(2)
      a(1) = a(1)*a(2)
      ca=cmplx(0d0,0d0,kind=8);
      do k=1,3
        ca(k)=k+ca(k)
      enddo
      array_1d= a(1) + a(2) + real(ca(2))
end function

ポイント

bind(c, name = 'array_1d')

でCで参照する際の関数名を明示しておくのが吉。

integer,intent(in),value::b,c

Fortranは参照渡しが基本なので、Cから呼べるように
値渡しを指定する。

Cのコード

先ほどのFortran内のarray_1d関数を呼び出すだけの以下のコードを用意。

#include <stdio.h>

extern int array_1d();

int main(int argc,char**argv) {
   printf("array_1d = %d\n",array_1d());
}

ビルド方法

flang -c arraytest.f90 

-cを指定することで、.oまでの作成になるので、main関数がなくても
flangに怒られなくなる。

clang -c atest.c 
clang -o atest atest.o arraytest.o

そこそこ数値計算するようなケース

次に、以下のコードで試した。

cmplxchk.f90
module m_zeta
contains
function zeta3(sr,si) bind(c, name = 'zeta3')
    implicit none
    complex(kind(0d0)),external ::mymain 
    double precision,value::sr,si
    double precision::zeta3,rr,ri
    complex(kind(0d0))::s,tt

    s = cmplx(sr, si)
    tt= mymain(s)

    rr = real(tt)
    ri = aimag(tt)
    zeta3 = rr + ri
contains

function mymain(s)
  implicit none
  complex(kind(0d0)),intent(in)::s
  complex(kind(0d0))::mymain

  mymain = sin(s)
end function mymain

end function zeta3
end module m_zeta
btest.c
#include <stdio.h>

extern double zeta3(float x,float y);

int main(int argc,char**argv) {
        printf("ans = %lf3.8\n",zeta3(0.5,-14.0));
}
flang -c cmplxchk.f90 
clang -c btest.c
clang -o btest btest.o cmplxchk.f90

と同様にすると、以下の様にリンクに失敗する。

cmplxchk.o: In function `m_zeta_zeta3_mymain':
/root/cmplxchk.f90:23: undefined reference to `__mth_i_cdsin'
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)

そこで、

clang -o btest btest.o cmplxchk.o /root/miniconda3/lib/libflang.a -lm

と、flangのランタイムライブラリとlibm.soを指定すると
無事に実行バイナリが生成される。

ここに挙げたFortranoのコードでは不要であったが
別件で自分が試したケースだと

clang -o btest btest.o zeta4.o /root/miniconda3/lib/libflang.a /root/miniconda3/lib/libflangrti.a -lm

というように、libflang.aの他にlibflangrti.aの指定も必要だった。

関連記事