https://qiita.com/snowlt23/items/1696687cca61bfedb1cc で取り上げられていた内容の拡張といった感じ。
ご存知の通り、Nimはいろんな言語との連携が可能です。
今回紹介するのは主にCとNimとで関数を共有する方法です。
注意 :
・コンパイル時「test.nim」の「.nim」は省略可能ですがあえて残しています。
C言語の関数をNimで利用
ファイルから宣言
Cのコードのほうの拡張子は「.h」でもOKです。
一つずつ宣言する
int dfunc(int b){
return b-1; // 引数に1を引いた数を返す
}
int cfunc(int a){
return a*2; // 引数に2を掛けた数を返す
}
このdfunc
とcfunc
をNimで使ってみましょう。
# 宣言
proc function(a:cint):cint{.header:"[CFILE」",importc:"dfunc".}
# 「CFILE」にtest.cのパスを入れる<<絶対パス、またはnimcacheからの相対パス>>
# 例 : {.header:"C:/Code/test.c",importc:"関数名".}
proc cfunc(a:cint):cint{.header:"「CFILE」".}
# 同じ関数名の場合はimportcが省略できる(ここでは{.importc:"cfunc".}が適用される)
echo function(12)
echo cfunc(12)
# ここでは 12
で、test.nim
をビルドします。
> nim c -r test.nim
11
24
ファイルごとにまとめて宣言
push - pop を使うことによりheaderプラグマを省略しています。
# 宣言
{.push header:"../test.c".} # header : ... を省略する
proc function(a:cint):cint{.importc:"dfunc".}
proc cfunc(a:cint):cint
# 関数の中身はさっきと同じ
{.pop.}
echo function(12)
echo cfunc(12)
# 出力もさっきと同じ
ライブラリから宣言
ここでは、Cのファイルは使用しません。
ライブラリから直接関数を持っていきます。
{.push header:"<stdio.h>".} # 標準ライブラリ"stdio.h"
proc printf(a:cstring,b:auto) # {.header:"<stdio.h>".}
proc scanf(x:cstring,y:auto)
{.pop.}
var n:char
scanf("%c",n.addr)
printf("Hi, I am C Library!\ncharacter:%c",n)
これで、C言語で使った時とと同じ挙動が再現されます。
> nim c -r test.nim
> t
Hi, I am C Library!
character:t
Nimの関数をCで利用
ちょっと手間がいります。
proc nitest(a:int):int {.exportc.}=
return a+8 # 引数に8を足した数を返す
# exportc プラグマを忘れずに!
これを、次のようにビルドします。
> nim c --noMain --noLinking --header:test.h test.nim
( test.hのところをtest.c と書いても同じ結果です )
すると、nimcacheにtest.h
という名前のファイルが生成されたはずです。
これをCに使わせます。
#include "test.h"
#include <stdio.h>
int main(){
NimMain();
printf("%d\n",nitest(7)); //ここでは例として 7
}
これを、
> gcc -o test.exe -Inimcache -I"「LibPATH」" nimcache/*.c test.c
LibPATHには、Nimのコンパイラのlibファイルのパスを入れてください。
これでコンパイルできるはずです。
> ./test.exe
15
最後に
もう気づけば真冬ですね。
冬はこたつでNimやろうぜ