FortranプログラムからC言語で実装された関数を呼ぶ
分散・並列計算機上でのアプリケーション実行環境の研究をしているため、Fortranで書かれたプログラムを実行して性能評価を行うことがたびたびあった。今まではアプリケーションは無修正で評価のためのデータを取得することが出来ていたんだけど、今回Fortranで書かれたプログラムを少し修正して、データ取得用のコードを埋め込む必要が出来た。そのデータ取得のためのプログラム・関数はC言語で実装したもの。FortranプログラムからC言語で実装されたライブラリ内の関数を、関数なりサブルーチンなりで呼び出すことが出来ると言うことは知っていたけど、実際に自分で試してみたのは初めて。その簡単なメモ。
Fortranのmainプログラム
1 program main 2 integer cnt, a, b, ab 3 4 cnt = 5 5 print *, 'before call "print_cnt"' 6 call print_cnt(cnt) 7 print *, 'after call "print_cnt"' 8 9 a = 2 10 b = 3 11 ab = multiply(a, b) 12 print '(I1, " x ", I1, " = ", I1)', a, b, ab 13 end
6行目で呼び出しているサブルーチン(C言語の戻り値のない関数に相当)print_cntと、11行目で実行している関数(C言語の戻り値のある関数に相当)multiplyがCで実装された関数。無事実行されれば以下のように出力される。
before call "print_cnt" print_cnt: 0000 print_cnt: 0001 print_cnt: 0002 print_cnt: 0003 print_cnt: 0004 after call "print_cnt" 2 x 3 = 6
次のようにコンパイルしてオブジェクトファイルを生成。
$ gfortran -g -Wall -c fmain.f
C言語ライブラリ
1 #include <stdio.h> 2 3 void print_cnt(int cnt) 4 { 5 int i; 6 for (i = 0; i < cnt; i++) { 7 printf("print_cnt: %04d\n", i); 8 } 9 } 10 11 int multiply(int a, int b) 12 { 13 return a * b; 14 } 15 16 // function for Fortran subroutine 17 void print_cnt_(int *cnt) 18 { 19 print_cnt(*cnt); 20 } 21 22 // function for Fortran function 23 int multiply_(int *a, int *b) 24 { 25 return multiply(*a, *b); 26 }
14行目までは上記2つの関数の普通の実装。Cプログラムから使われる。17〜20行目がprint_cntをFortranプログラムから呼び出すためのラッパー関数、23〜26行目がmultiplyを呼び出すためのもの。print_cntはFortranでいうところのサブルーチン、multiplyは関数になるけど、C言語でラッパーを実行する点においては違いはない。
注意点として以下の2つ。
ファイル名をclib.c、生成する静的ライブラリ名libclib.aとすると、次のようにして作成できる。
$ gcc -g -Wall -c clib.c $ ar cr libclib.a clib.o $ ranlib libclib.a
実行ファイルの作成
以上で出来たfmain.oとlibclib.aをリンクして、実行ファイルを生成する。
$ gfortran -L. -o fmain fmain.o libclib.a -lclib
実行すれば上のように出力される。