はじめに
NimからのFortranの関数の呼び出すためのビルド方法と整数型の利用方法を示す。
注:Fortranでは戻り値がない関数はサブルーチンと呼ぶが本記事では全て関数と記載する。
NimのデフォルトのバックエンドはC言語なので、C言語からFortranを呼び出し方法が参考となる。
本記事ではOSはLinux、コンパイラはgccおよびgfortranを用いる。
関数名について
NimでC言語の関数を呼び出す場合にはimportc
プラグマで呼び出す関数名を指定できる。
Fortranの関数も同様に指定して呼び出せるが、次の2点に気を付ける必要がある。
- Fortarnの関数名に大文字が含まれている場合でもNimでの指定はすべて小文字とする
- Fortran側で
BIND(C)
を用いるか、Nim側の呼び出し名の最後に_
を追加する
Fortranの関数名に大文字が含まれている場合
forran/sub_hello.f90
subroutine Hello() BIND(C)
implicit none
print *, 'Hello World'
end subroutine
main.nim
{.compile("fortran/sub_hello.f90", "-lgfortran").} # 後述
{.passL:"-lgfortran".} # 後述
proc call_hello() {.importc: "hello".} # Helloではなくhelloと指定する
call_hello()
実行
$ nim c -r main.nim
Hello World
BIND(C)
を用いない場合
forran/sub_hello.f90
subroutine hello()
implicit none
print *, 'Hello World'
end subroutine
main.nim
{.compile("fortran/sub_hello.f90", "-lgfortran").} # 後述
{.passL:"-lgfortran".} # 後述
proc call_hello() {.importc: "hello_".} # helloではなくhello_と指定する
call_hello()
実行
$ nim c -r main.nim
Hello World
リンク方法
Fortranとのリンク方法について4つの方法に示す。
- ソースファイルを一緒にビルド
- オブジェクトファイルを一緒にビルド
- 静的ライブラリをリンク
- 動的ライブラリをリンク
各方法に用いるFortranソースは共通とする。
forran/sub_hello.f90
subroutine hello() BIND(C)
implicit none
print *, 'Hello World'
end subroutine
ソースファイルを一緒にビルド
main.nim
# ビルド対象に fortran/sub_hello.f90 を加え、コンパイル時に -lgfortran オプションを追加する
{.compile("fortran/sub_hello.f90", "-lgfortran").}
# リンク時のオプションに -lgfortran を追加する
{.passL: "-lgfortran".}
proc call_hello() {.importc: "hello".}
call_hello()
実行
$ nim c -r main.nim
Hello World
オブジェクトファイルを一緒にビルド
オブジェクトファイルを生成
$ gfortran -c -o fortran/sub_hello.o fortran/sub_hello.f90
main.nim
# fortran/sub_hello をリンク対象に追加する
{.link: "fortran/sub_hello.o".}
# リンク時のオプションに -lgfortran を追加する
{.passL: "-lgfortran".}
proc call_hello() {.importc: "hello".}
call_hello()
実行
$ nim c -r main.nim
Hello World
静的ライブラリをリンク
静的ライブラリを生成
$ gfortran -c -o fortran/sub_hello.o fortran/sub_hello.f90
$ ar rcs -o fortran/libsub_hello.a fortran/sub_hello.o
main.nim
# ./fortran/libsub_hello.a を静的リンク、コンパイル時に -lgfortran オプションを追加する
{.passL: "-L./fortran -lsub_hello -lgfortran".}
proc call_hello() {.importc: "hello".}
call_hello()
実行
$ nim c -r main.nim
Hello World
動的ライブラリをリンク
動的ライブラリを生成
$ gfortran -shared -fpic -o fortran/libsub_hello.so fortran/sub_hello.f90
main.nim
# fortran/libsub_hello.so を動的リンク
proc call_hello() {.dynlib: "fortran/libsub_hello.so",importc: "hello".}
call_hello()
実行
$ nim c -r main.nim
Hello World
戻り値を受け取る
Fortranからinteger型の1
を受け取る。
forran/sub_one.f90
function one() BIND(C)
Use Iso_C_Binding
implicit none
integer :: one
one = 1
end function
main/nim
{.compile("fortran/sub_one.f90", "-lgfortran").}
{.passL: "-lgfortran".}
proc call_one(): int32 {.importc: "one".}
var one:int32
one = call_one()
echo one
実行
$ nim c -r main.nim
1
引数を与える
Fortran関数の引数は基本的に参照渡しのため、以下のどれかが必要となる。
- Fortranの関数を値渡しで定義する
-
ptr
型で渡す -
ref
型で渡す
Fortranの関数を値渡しで定義する
forran/sub_add.f90
function add(a,b) BIND(C)
Use Iso_C_Binding
implicit none
integer(4), value :: a, b ! VALUE属性を付与して値渡しにする
integer(4) :: add
add = a + b
end function
main/nim
{.compile("fortran/sub_add.f90", "-lgfortran").}
{.passL: "-lgfortran".}
proc call_add(a, b: int32): int32 {.importc: "add".}
var sum = call_add(1, 2)
echo sum
実行
$ nim c -r main.nim
3
ptr
型で渡す
forran/sub_add.f90
function add(a,b) BIND(C)
Use Iso_C_Binding
implicit none
integer(4) :: a, b
integer(4) :: add
add = a + b
end function
main/nim
{.compile("fortran/sub_add.f90", "-lgfortran").}
{.passL: "-lgfortran".}
proc call_add(a, b: ptr int32): int32 {.importc: "add".}
var a = 1.int32
var b = 2.int32
var sum = call_add(a.addr, b.addr)
echo sum
実行
$ nim c -r main.nim
3
ref
型で渡す
forran/sub_add.f90
function add(a,b) BIND(C)
Use Iso_C_Binding
implicit none
integer(4) :: a, b
integer(4) :: add
add = a + b
end function
main/nim
{.compile("fortran/sub_add.f90", "-lgfortran").}
{.passL: "-lgfortran".}
proc call_add(a, b: ref int32): int32 {.importc: "add".}
var a = new(int32)
var b = new(int32)
a[] = 1
b[] = 2
var sum = call_add(a, b)
echo sum
実行
$ nim c -r main.nim
3
参考
https://docs.oracle.com/cd/E19957-01/806-4843/Cp11_cfort.html
https://www.nag-j.co.jp/fortran/tips/tips_InteroperabilityWithC.html