From 64553aa569e781db46dfa5508b8913cdd999091c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 28 Jul 2021 19:32:14 +0900 Subject: [PATCH] Write a basic "call Rust from C" example --- src/ffi.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/src/ffi.md b/src/ffi.md index 825be5a..f3d6c1e 100644 --- a/src/ffi.md +++ b/src/ffi.md @@ -650,21 +650,68 @@ No `transmute` required! ## Calling Rust code from C -You may wish to compile Rust code in a way so that it can be called from C. This is -fairly easy, but requires a few things: +You may wish to compile Rust code in a way so that it can be called from C. +This is fairly easy, but requires a few things. + +### Rust side + +First, we assume you have a lib crate named as `rust_from_c`. +`lib.rs` should have Rust code as following: ```rust #[no_mangle] -pub extern "C" fn hello_rust() -> *const u8 { - "Hello, world!\0".as_ptr() +pub extern "C" fn hello_from_rust() { + println!("Hello from Rust!"); } # fn main() {} ``` -The `extern "C"` makes this function adhere to the C calling convention, as -discussed above in "[Foreign Calling -Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle` -attribute turns off Rust's name mangling, so that it is easier to link to. +The `extern "C"` makes this function adhere to the C calling convention, as discussed above in "[Foreign Calling Conventions]". +The `no_mangle` attribute turns off Rust's name mangling, so that it is easier to link to. + +Then, to compile Rust code as a shared library that can be called from C, add the following to your `Cargo.toml`: + +```toml +[lib] +crate-type = ["cdylib"] +``` + +Run `cargo build` and you're ready to go on the Rust side. + +[Foreign Calling Conventions]: ffi.html#foreign-calling-conventions + +### C side + +We'll create a C file to call the `hello_from_rust` function and compile it by `gcc`. + +C file should look like: + +```c +int main() { + hello_from_rust(); + return 0; +} +``` + +We name the file as `call_rust.c` and place it on the crate root. +Run the following to compile: + +```sh +gcc call_rust.c -o call_rust -lrust_from_c -L./target/debug +``` + +`-l` and `-L` tell gcc to find our Rust library. + +Finally, we can call Rust code from C with `LD_LIBRARY_PATH` specified: + +```sh +LD_LIBRARY_PATH=./target/debug ./call_rust +``` + +That's it! +For more realistic example, check the [`cbindgen`]. + +[`cbindgen`]: https://github.com/eqrion/cbindgen ## FFI and panics