この記事では、RustのForeign Function Interface(FFI)を使用して、C言語の関数をRustから呼び出す方法を解説します。安全性や手順に焦点を当て、CとRustの統合を探求します。
FFIとは?
RustにおけるFFI(Foreign Function Interface)は、他のプログラミング言語(主にCやC++)で書かれたコードをRustから呼び出すための仕組みです。Rustは安全で制御された言語であり、CやC++といった低レベルの言語とのインターフェースを提供するために、FFIをサポートしています。
先に提供されたコードを振り返ってみると、Rustのプログラム内でC言語の関数を使用することを試みています。C言語の関数をRustから呼び出す際には、以下のステップを踏む必要があります。
- C言語のコードをラップする: C言語のコードを、Rustから呼び出せる形にラップします。ラップされた関数はRustのFFIに従って定義されます。
- Rustのコード内でラップした関数を使用: ラップしたC言語の関数を、Rustのコード内で呼び出します。
#[link(name = "mycalc", kind = "static")]
extern "C" {
fn mul(a: i32, b: i32) -> i32;
}
fn main() {
unsafe {
let n = mul(30, 5);
println!("{}", n);
let n = mul(8, 80);
println!("{}", n);
}
}
このコードは、Rustのプログラム内でC言語のmul
関数を呼び出しています。#[link]
属性を使用して、mycalc
静的ライブラリをリンクすることを指定しています。そして、extern "C"
ブロック内で、C言語の関数 mul
を宣言しています。
しかし、このコードのままではmul
関数が正しくリンクされない場合があるため、前述のビルドスクリプトを使用してライブラリをビルドする必要があります。
cc::Build
を使用したビルドスクリプトが提供されており、これによって mycalc.c
ファイルがコンパイルされて mycalc
静的ライブラリが生成されます。その後、Rustのプログラム内で mul
関数を使用して、C言語の関数を呼び出しています。
以上のコードとビルドスクリプトを組み合わせて、C言語の関数をRustから呼び出すことができます。ただし、FFIを使用する際には注意が必要で、特に安全性とポインタ操作に関する問題に注意を払う必要があります。
ビルド関数の設定
提供していただいた mycalc.c
のコードは、関数 mul
を含むものですね。このファイルを静的ライブラリとしてビルドして、Rust プロジェクト内で使用するための手順を説明します。
- まず、プロジェクトのルートディレクトリに
src
フォルダを作成し、その中にmycalc.c
ファイルを配置します。 - プロジェクトのルートディレクトリにある
Cargo.toml
ファイルと同じ階層に、build.rs
というファイルを作成します。以下のようにbuild.rs
ファイルを作成します。 - このビルドスクリプトは、
src
フォルダ内のmycalc.c
ファイルをコンパイルしてmycalc
静的ライブラリを生成します。また、コンパイルが必要な場合にスクリプトが再実行されるように、cargo:rerun-if-changed
メタデータを使用しています。 - プロジェクトのルートディレクトリにある
Cargo.toml
ファイルに、cc
ライブラリのビルド依存関係を追加します。
fn main() {
// Tell Cargo to rerun this script if the mycalc.c file changes
println!("cargo:rerun-if-changed=src/mycalc.c");
// Compile the mycalc.c file into a static library
cc::Build::new() .file("src/mycalc.c") .compile("mycalc");
}
[package]
name = "ffi_mul"
version = "0.1.0"
edition = "2021"
[dependencies]
libc = "0.2"
[build-dependencies]
cc = "1.0" # カスタムビルドスクリプトで cc ライブラリを使用
これらの手順を実行し、mycalc.c
を静的ライブラリとしてビルドするようにプロジェクトを設定してみてください。その後、Rust コード内で mycalc
ライブラリを使用する部分に関する修正を行い、コンパイル・実行してみてください。