GoでRustを呼ぶ。そしてRustでGoを呼ぶ。https://qiita.com/momotaro98/items/92e39e214b0e92f454a7
こちらを参考にさせて頂いたが Windows の場合 go の -buildmode=c-archive で作られる lib が mingw 用なり Windows の Rust が使う MSVC 用と合わないので DLL にして回避した。(具体的には crt の関数がないエラーとセクションの形式が合っていないような警告でリンクできない)
細かい事は省くが x64 の msys2 環境で go も Rust もインストール済みの場合の例です。
main.go
package main import "C" //export GoFunc1 func GoFunc1(name string) *C.char { str := name + " ʕ ◔ϖ◔ʔ" return C.CString(str) } func main() {}
go のソースコードから "gofuncs.dll" という名前の dll を作る
go build -buildmode=c-shared -o gofuncs.dll ./main.go
dll で公開している関数を記述した def ファイルを作る (TODO: 自動化, dumpbin.exe からできるはず)
gofuncs.def
LIBRARY gofuncs EXPORTS GoFunc1 @1
lib.exe で DLL からインポートライブラリを作成する
LIBEXE=`cygpath --unix "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC/14.32.31326\bin\Hostx64\x64\lib.exe"` "$LIBEXE" /def:gofuncs.def /out:gofuncs.lib /machine:x64
これでインポートライブラリ gofuncs.lib (MSVC 形式) が作成される
Rust のソースファイル
use std::ffi::{CStr, CString}; use std::os::raw::c_char; extern "C" { fn GoFunc1(name: GoString) -> *const c_char; } #[repr(C)] struct GoString { ptr: *const c_char, len: i64, } fn main() { let src_str = CString::new("I'm a Rustacean").expect("CString::new failed"); let ptr = src_str.as_ptr(); let param = GoString { ptr: ptr, len: src_str.as_bytes().len() as i64, }; let go_func_result = unsafe { GoFunc1(param) }; let c_str = unsafe { CStr::from_ptr(go_func_result) }; let result = c_str.to_str().expect("to_str failed"); println!("{}", result); }
cargo でリンクするライブラリを指定
build.rs
fn main() { let dir = std::env::var("PWD").unwrap(); println!("cargo:rustc-link-search={}", std::path::Path::new(&dir).display()); println!("cargo:rustc-link-lib=gofuncs"); }
これで cargo run すると "I'm a Rustacean ʕ ◔ϖ◔ʔ" と表示される。