🦔

C言語からNimを呼び出す

2021/07/10に公開

目標

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でexportccdeclを指定。
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つにまとめて呼び出す必要がある。

参考

https://nim-lang.org/docs/manual.html
https://nim-lang.org/docs/nimc.html
https://nim-lang.github.io/Nim/backends.html

scrap

https://zenn.dev/hastur/scraps/ad232d8f444370

Discussion