メモ: Common LispからRust/Goを呼び出す
17 January 2018
RustはCの共有ライブラリを出力できるそうなのでCommon LispのCFFIから呼べるかどうか試してみた。
参考:
Rustで共有ライブラリをつくる
以下のような内容のfib.rs
ファイルをつくる。
#[no_mangle]
pub extern fn fib(n: u32) -> u32 {
if n <= 1 {
n
} else {
fib(n - 1) + fib(n - 2)
}
}
次のようにビルドすると、libfib.so
ファイルができる。
rustc --crate-type="dylib" fib.rs
Common Lisp側から呼び出す
(ql:quickload :cffi)
;; さきほどビルドした共有ライブラリを読み込む
(cffi:load-foreign-library "/home/wiz/program/rust/libfib.so")
;; ラッパー関数を定義
(cffi:defcfun "fib" :int (n :int))
(time (fib 40))
;; Evaluation took:
;; 1.189 seconds of real time
;; 1.192000 seconds of total run time (1.192000 user, 0.000000 system)
;; 100.25% CPU
;; 4,033,898,326 processor cycles
;; 0 bytes consed
;; => 102334155
普通にできた!!
なおこの場合Common Lispで書いた方が速い
- 使用マクロはここから: 型宣言付きのdefunとletを定義してみる
(defnt (fib2 fixnum) ((n fixnum))
(if (<= n 1)
n
(+ (fib2 (- n 1))
(fib2 (- n 2)))))
(time (fib2 40))
;; Evaluation took:
;; 0.787 seconds of real time
;; 0.788000 seconds of total run time (0.788000 user, 0.000000 system)
;; 100.13% CPU
;; 2,671,326,658 processor cycles
;; 0 bytes consed
;; => 102334155
追記: Rustの最適化オプションを有効化してみる
Rustにも最適化オプションがあるらしい
rustc --crate-type="dylib" -C opt-level=3 fib.rs
として上と同様の手順を踏んでみると、最適化ありのCommon Lisp版より速くなった。
(time (fib 40))
;; Evaluation took:
;; 0.708 seconds of real time
;; 0.712000 seconds of total run time (0.712000 user, 0.000000 system)
;; 100.56% CPU
;; 2,404,129,682 processor cycles
;; 0 bytes consed
追記2: Goでもやってみる
GoにもCの共有ライブラリを出力できるビルドオプションがあるらしい
libgofib.go
package main
import (
"C"
"log"
)
//export fib
func fib(n int) int {
if (n < 2) { return n }
return fib(n - 2) + fib(n - 1)
}
func init() {
log.Println("Loaded!!")
}
func main() {
}
これを以下のようにビルドする。
go build -buildmode=c-shared -o libgofib.so libgofib.go
Common Lispから呼び出す。
(cffi:load-foreign-library "/home/wiz/program/golang/libgofib.so")
(cffi:defcfun "fib" :int (n :int))
(time (fib 40))
;; Evaluation took:
;; 0.733 seconds of real time
;; 0.736000 seconds of total run time (0.736000 user, 0.000000 system)
;; 100.41% CPU
;; 2,485,210,416 processor cycles
;; 0 bytes consed
感想
簡単なC-APIを書けるだけのRust/Go力があればそのコード資産に簡単にアクセスできるというのは非常にうれしい。 Common Lispはそれ自体がかなり速いためにスピードのために外部ライブラリを呼ぶ必要性はあまりないのだが、ユーザ人口が少ないのでライブラリの物量不足になっており、アクセス可能なコード資産が増えるのはいいことである。 反面、外部ライブラリをCommon Lispのプロジェクトに組込むときはビルド時のエラーや依存関係など余計に考えなければならないことが増えるのでそういったところでの苦労が予想される。