C++ から Rust の関数を呼び出す方法のメモです。
gcc を利用して、静的リンクで呼び出すケースについてまとめます。
rustc でライブラリを生成する
cargo ではなく rustc でライブラリを生成する方法です。
Rust – 静的リンクライブラリの生成
Rust にて、2つの整数を足し算する add
関数を定義します。
これを C++ から呼び出します。
Filename: libadd.rs
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
コード作成後は、次のコマンドで静的リンクライブラリを生成します。libadd.a
ファイルが生成されます。
$ rustc --crate-type=staticlib libadd.rs -o libadd.a
$ ls libadd.a
libadd.a
ポイントは2つです。
- no_mangle の属性を付与する
- extern “C” を記述する
no_mangle は、関数名に特殊な装飾を指せないための指定です。
通常、言語の独自ルールで関数名がカスタマイズされてしまいますが、これを抑止させます。
extern “C” はバイナリインタフェースを Cルールにするという指定です。
今回の例ではこれがなくてもうまくいくかもしれませんが、関数呼び出し時の引数や戻り値の扱い方に影響します。
C++ – ライブラリの関数を呼び出し
C++ から静的リンクライブラリの add 関数を呼び出します。
こちらでも extern “C” を付与させて、C++ のマングリングを抑止させます。
#include <iostream>
extern "C" int add(int, int);
int main()
{
int n = add(1, 2);
std::cout << n << std::endl;
return 0;
}
g++ でコンパイルすることで実行ファイルを生成します。
また、関数の呼び出しができていることを確認します。
$ g++ main.cc libadd.a -o main && ./main
3
Cargo でライブラリを生成する
Cargo を利用してライブラリを生成する方法です。
プロジェクトの作成
まずは cargo new
でプロジェクトを作成します。
このときオプションに --lib
を付与して、ライブラリ用のプロジェクトを生成させます。
$ cargo new add --lib
Created library `add` package
ソースコードの編集
lib.rs ファイルを編集します。
rustc の例同様に、2つの整数を足し算する add
関数を定義します。
Filename: add/src/lib.rs
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
Cargo.toml の編集
Cargo.toml を開き、lib.crate-type
の定義を追加します。
これで、静的リンクライブラリを生成することを Cargo に指示します。
Filename: add/Cargo.toml
[package]
name = "add"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["staticlib"]
[dependencies]
ビルド
最後にビルドを実行します。
特にオプションを付与しない場合は、target/debug
配下にライブラリが出力されます。
$ cd add
$ cargo build
Compiling add v0.1.0 (/home/gari/sandbox/cpp-ffi/add)
Finished dev [unoptimized + debuginfo] target(s) in 0.18s
$ ls target/debug/libadd.a
target/debug/libadd.a
C++ にリンクさせる
ここまでできたら、あとは rustc のケースと同様です。
libadd.a をコピーして g++ でコンパイルさせると、Rust で定義したメソッドを C++ から呼ぶことができます。
$ g++ main.cc libadd.a -o main && ./main
3
コメント