vlang コードを .so ビルドし, C/C++ などから呼べるようにする(println や builtin 関数いくつか動くのを確認).


背景

vlang の関数を, C から呼びたい

  • vlang でプロトタイピングして動作確認したのち, C/C++ に組み込みたい
  • vlang で live coding して動作確認したのち, リリース向けでは C/C++ バイナリ単体にしたい

など.

vlang 自体は, 一度 C コードに変換して実行しているため, C/C++ と連携はやりやすいと想像できます.
とりあえず基本的なコードは動きました.

環境

v 0.2 を仮定します(2020/03/31 時点ではまだリリースはされていない. git master branch 利用)

Linux 64bit を仮定します.

0.2 から, モジュールのビルド方法が変わりました. ast パーサなど内部構造を変えたからでしょうか. より汎用的に使えるようになっています.

モジュールをコンパイルする.

通常の C コードと同様な感じでモジュールを作ることができます.

  • .v から .c を生成する
  • C compiler で .so にコンパイルする
// fibrec.v
module fibrec
pub fn fib(n int) int {
  if n <= 2 {
    return 1
  } else {
    return fib(n-1) + fib(n-2)
  }
}
$ ./v -shared -o mymodule.c fibrec/fibrec.v

-shared を付けて, main 関数などが生成されないようにします.

あとは通常の C と同じように扱います.
-fPIC は基本付けておきましょう. 付けないと一部 vlang 関数のコンパイルでうまくいかないです. -lm など必要なライブラリもリンクしておきます.

これで完成です!

python から呼んでみます.

import ctypes

lib = ctypes.cdll.LoadLibrary("./fibrec.so")

arg_int = ctypes.c_int(10)
res = lib.fibrec__fib(arg_int)
print(res)

という感じで python から呼んで試してみましょう!

少なくとも, fibrec に println や組み込み関数の array を追加して, うまく扱えるのを確認しました.

TODO

  • 複数 .v をコンパイルして .so が作れるか確認する
  • ほかの vlang 組み込み関数がコンパイルできるか確認する

以下は, 古い情報です. 記録まで.

===============================================================

環境

v 0.1.25 を仮定します(2020/02/26)

Linux 64bit を仮定します.

Exporting function to library (dll/so) #2379
https://github.com/vlang/v/issues/2379

は, このままではうまくいきません.

module

まず, 普通に .v-shared でビルドすると, main 関数など全部入りになります.

vlang では, module の機能(Java 的な感じ?)がありますので, module の機能を使います.

// fibrec.v
module fibrec
pub fn fib(n int) int {
  if n <= 2 {
    return 1
  } else {
    return fib(n-1) + fib(n-2)
  }
}

フォルダの構成としては, <module>/file.v が想定されます((Java 的な感じ? golang も同等かしら?). フォルダ名をモジュールと合わせる必要がありますが, 実態のコードがあるファイル名は .v であればなんでもいいかもしれません.

$ mkdir fibrec
$ mv fibrec.v fibrec/
./v build module fibrec

とすると, ~/.vmodules/ に .o ができます. パスは変更できないようです.

$ ./v -verbose

として, どのようなコマンドが呼ばれるか確認しましょう.

-shared をつけると, relocatable(-fPIC つき)な <module>.o が生成されます.

$ gcc -o fibrec.so -shared ~/.vmodules/fibrec.o

として, .so を作ります. nm でシンボルを確認しておきます.

python から呼んでみます.

import ctypes

lib = ctypes.cdll.LoadLibrary("./fibrec.so")

arg_int = ctypes.c_int(10)
res = lib.fibrec__fib(arg_int)
print(res)

55 と表示されれば成功です!

制限

println や配列など, builtin や vlib の機能を使うと, シンボルが見つからないエラーになります. vlib のいくつかを .so に取り込む必要があるようですが, 現状 _wyp0 シンボルが重複するなどのエラーになります. より一般的に vlang のコードを .so にするにはまだ開発に時間かかりそうです.

TODO

  • Windows(llvm-mingw など)でうまくいくか確認する
  • vlang の標準ライブラリが使えるようにする
  • vlang を, C/C++ に組み込んでスクリプト実行する(libv みたいなのが作れればいけるか?)