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