Edited at

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

More than 1 year has passed since last update.


今回の環境

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の指定も必要だった。


関連記事