Rustは、その高いパフォーマンスとメモリ安全性を活かして、他のプログラミング言語と連携するための**FFI(Foreign Function Interface)**を提供しています。
FFIを使うことで、RustのコードをCやC++などの他言語から呼び出したり、逆にRustから他言語のコードを呼び出すことが可能です。
この記事では、Rustと他言語の連携方法を学び、FFIの基本的な使い方を紹介します。
FFIとは?
**FFI(Foreign Function Interface)**とは、異なるプログラミング言語間で関数やデータをやり取りするための仕組みです。
Rustでは、特にC言語との連携が強力で、Cの関数を呼び出したり、Rustの関数をC言語から利用することができます。
RustとCの連携のメリット
- 高パフォーマンス: RustはCと同等のパフォーマンスを持つため、既存のCコードにRustを組み込んでも効率が低下しません。
- 安全性: Rustのメモリ安全性を保ちながら、Cの機能を活用できるため、セキュアなシステムの構築に役立ちます。
RustからC言語の関数を呼び出す
RustからC言語の関数を呼び出す場合、C言語で定義された関数のシグネチャをRustで宣言し、それを呼び出せるようにします。
C言語のコード
まず、C言語のコードを用意します。
この例では、単純な add
関数をCで定義し、Rustから呼び出します。
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
RustからCの関数を呼び出す
次に、RustのコードでC言語の add
関数を宣言し、FFIを通じて呼び出します。
Rustのコード
extern "C" {
fn add(a: i32, b: i32) -> i32;
}
fn main() {
let result = unsafe { add(5, 7) };
println!("5 + 7 = {}", result);
}
ポイント:
extern "C"
ブロック内でC言語の関数を宣言します。unsafe
ブロック内で関数を呼び出します。これは、RustがFFI呼び出しをメモリ安全と見なさないためです。
コンパイルとリンク
Cのコードをコンパイルし、Rustのコードとリンクします。
$ gcc -c -o add.o add.c
$ ar rcs libadd.a add.o
$ rustc main.rs -l add -L .
gcc
コマンドでCコードをコンパイルし、Rustのプロジェクトにリンクします。rustc
コマンドでRustコードをCのライブラリとリンクさせてビルドします。
RustをC言語から呼び出す
逆に、Rustの関数をC言語から呼び出すことも可能です。
Rustで関数を #[no_mangle]
属性を使って定義し、Cから利用します。
Rustでの関数定義
Rustで定義した関数をCから呼び出すためには、関数の名前を「マングリング」しないように #[no_mangle]
属性を使います。
#[no_mangle]
pub extern "C" fn multiply(a: i32, b: i32) -> i32 {
a * b
}
ポイント:
#[no_mangle]
属性を使うことで、Rustのコンパイラが関数名を変更しないようにします。extern "C"
を使ってCと互換性のある関数呼び出しを可能にします。
C言語からRustの関数を呼び出す
次に、CのコードからRustの関数を呼び出します。
Cのコード
#include <stdio.h>
extern int multiply(int a, int b);
int main() {
int result = multiply(6, 7);
printf("6 * 7 = %d\n", result);
return 0;
}
コンパイルとリンク
Rustのコードをライブラリとしてコンパイルし、C言語のコードとリンクします。
$ rustc --crate-type=staticlib lib.rs
$ gcc main.c -o main -L . -l lib
これで、C言語からRustの関数を呼び出して利用できます。
Rustと他言語の連携例
Rustは、C以外の言語ともFFIを通じて連携できます。ここでは、Pythonとの連携例を見てみましょう。
RustのコードをPythonから呼び出すために、pyo3
というクレートを使用します。
pyo3
クレートのインストール
まず、pyo3
クレートを使ってRustとPythonを連携させます。
$ cargo new --lib rust_python_example
$ cd rust_python_example
$ echo 'pyo3 = "0.15"' >> Cargo.toml
Rustのコード
以下は、RustでPythonから呼び出す関数を定義した例です。
use pyo3::prelude::*;
#[pyfunction]
fn sum_as_string(a: i64, b: i64) -> PyResult<String> {
Ok((a + b).to_string())
}
#[pymodule]
fn rust_python_example(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
Ok(())
}
PythonからRustの関数を呼び出す
Rustのコードをビルドし、Pythonで使えるライブラリを作成します。
$ maturin develop
その後、PythonからRustの関数を呼び出せます。
import rust_python_example
result = rust_python_example.sum_as_string(10, 20)
print(f"10 + 20 = {result}")
練習問題
練習問題1: RustからC関数の呼び出し
次のステップに従って、RustからC言語の関数を呼び出し、その結果をRustで処理するプログラムを作成してください。
- C言語で
multiply
関数を定義し、2つの整数を掛け算する関数を作成します。 - Rustからその関数を呼び出し、結果を表示するプログラムを実装してください。
まとめ
今回の記事では、RustのFFI(Foreign Function Interface)を使って他言語と連携する方法について学びました。
Rustは、CやPythonなどの他のプログラミング言語と簡単に連携できるため、既存のシステムにRustを組み込んでパフォーマンスを向上させることが可能です。
Rustで提供されていないライブラリや機能が必要な場合でも、Cのライブラリを使うことで、Rustのライブラリ不足を補うことができます。
これにより、Rustのエコシステムにまだ存在しない特定の機能やライブラリも、C言語や他の言語の豊富な資産を活用することで解決できるようになります。