C言語からNimを呼び出す
目標
Nimで記述したフィボナッチ数列を計算する関数をC言語から呼び出す。
方法
NimをスタティックライブラリとしてビルドしてC言語から呼び出す。
環境
Windows10
C言語: clang version 12.0.1
Nim: Version 1.4.8
コード(Nim)
proc fib*(a: cint): cint {.exportc, cdecl.} =
if a <= 2:
result = 1
else:
result = fib(a - 1) + fib(a - 2)
再帰でフィボナッチ数列を求めるコード。
Nim Backend Integrationから引用。
pragmaでexportc
とcdecl
を指定。
exportc
: C言語に公開する関数であることを宣言。
cdecl
: 呼び出し規約をcdecl
に準拠させる(念のため)
受け取る引数をC準拠にしているのとpragmaを指定した以外は通常の関数と同じ形式。
ビルド(Nim)
nim c --app:staticLib --noMain --header --nimcache:nim-cache fib.nim
C言語から呼び出すのでバックエンドはc
を指定。
スタティックライブラリにビルドしたいので--app:staticLib
を指定。
メイン関数は必要ないので--noMain
でメイン関数の生成を抑制。
--header
でヘッダの生成をOnにする。
後でCから生成したヘッダをインクルードするので見える位置にキャッシュを生成するために--nimcache:nim-cache
で位置を指定。
このコマンドでディレクトリ直下にfib.lib
が生成される。
コード(C)
#include "fib.h"
#include <stdio.h>
int main() {
NimMain();// Nim側の初期化
printf("fib(10) = %d\n", fib(10));
return 0;
}
ビルド(C)
自分の使っているビルドシステムが特殊で参考にならない問題
Cはビルドシステムが色々あるので要点だけ書く。
インクルードディレクトリにNimのビルド時に生成したnim-cache
とNimのインストールディレクトリ内に存在するlib
を指定する。
後はfib.lib
を依存関係に指定してビルドすれば完了。
実行結果
fib(10) = 55
補足
NimMain
の呼び出しは必須で内部的にはGCの初期化とモジュールのトップレベルに書かれたコードの実行などを行う。
単一のNim製ライブラリしか使わない場合は問題ないが複数のNim製ライブラリを使用する場合はNimMain
およびその他の関数が衝突するので何かしらの回避策を講じるか、全てを1つにまとめて呼び出す必要がある。
参考
scrap
Discussion