Rustは比較的簡単にCスタイルのダイナミックライブラリを作って
それを外部から呼び出すことが可能。
今回の検証では以下の言語の呼び出し例を挙げる
- Python
- C
- Haskell
検証環境
OS
OSX Yosemiteで検証
rustのバージョン
> rustc -V
rustc 1.2.0-dev (467e4a668 2015-06-16)
ダイナミックライブラリの作成
以下がミニマルなサンプル
#![crate_type = "dylib"]
#[no_mangle]
pub extern fn repeat_hello(s:i32) {
for _ in 0..s {
println!("Hello");
}
}
上記を hello.rs
で保存し、
コンパイルは通常通り以下のように行う。特にオプションを指定する必要は無い
rustc hello.rs
結果ファイルとしてlibhello.dylib
(OSXの場合)が出来上がる。
以下呼び出しに関してはlibhello.dylibが呼び出し元と同じディレクトリにあると仮定
他言語からの呼び出し例
基本的にはC製のダイナミックライブラリを使うやり方そのまま
pythonからの呼び出し
上記のdylib
をPythonから呼び出すことを考える
ctypesからの呼び出しは簡単
#!/bin/env python3
import ctypes
import argparse
def hello(n):
libhello = ctypes.CDLL("./libhello.dylib")
libhello.repeat_hello.argtypes = (ctypes.c_int32,)
libhello.repeat_hello(n)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("N",type=int)
args = parser.parse_args()
hello(args.N)
実行
> python call.py 5
Hello
Hello
Hello
Hello
Hello
Cからの呼び出し
call.c
を以下のように記述
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void repeat_hello(int32_t i);
int main(int argc, char const *argv[]) {
if(argc<2) {
printf("invalid arg.\n");
exit(1);
}
int32_t i = atoi( argv[1] );
repeat_hello(i);
return 0;
}
以下のようにコンパイル
gcc -L. call.c -o call_from_c -lhello
実行
> ./call_from_c 5
Hello
Hello
Hello
Hello
Hello
Haskellからの呼び出し
import Foreign.C.Types
import System.Environment
import Control.Applicative
foreign import ccall "repeat_hello" repeatHello :: CInt -> IO ()
main :: IO ()
main = do
n <- read.head <$> getArgs :: IO CInt
repeatHello n
コンパイル
ghc -L. -lhello call.hs -o call_from_haskell
実行
> ./call_from_haskell 5
Hello
Hello
Hello
Hello
Hello
cargoを使う場合
cargo.toml
を以下のように記述する。
[lib]
name = "hello"
crate-type = ["dylib"]
cargo build
を行うと./target/debug/libhello.dylib
が出来る。
まとめと今後の課題
rustでダイナミックライブラリの作り方と使い方についてまとめた。
今後の課題は構造体を受け渡す方法(出来るのか?)