Help us understand the problem. What is going on with this article?

mainの無いFortranのコードを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の指定も必要だった。

関連記事

kjunichi
WebRubyがきっかけで、mrubyで実装されたhttp2サーバーのtrusterdに絡んだ事をやってみたり、ElectronのIssue眺めたり、手元で動かしたり、node.js関連。WASMも少々。投稿する記事の内容は個人の意見であり、所属する企業の見解を代表するものではありません。
https://abrakatabura.hatenablog.com/
japan-systems
「2019年に50周年を迎えたIT企業です。最先端の技術により全国の企業、官公庁、自治体に多くの実績があります。」
https://www.japan-systems.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away