Skip to content

Commit 358e6a6

Browse files
authored
Merge pull request #296 from JohnTitor/call-rust-code-from-c
Write a basic "call Rust from C" example
2 parents 6c2aeef + 88b2dbc commit 358e6a6

File tree

1 file changed

+68
-18
lines changed

1 file changed

+68
-18
lines changed

src/ffi.md

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,74 @@ the release of these resources (especially in the case of panic).
240240

241241
For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html).
242242

243+
## Calling Rust code from C
244+
245+
You may wish to compile Rust code in a way so that it can be called from C.
246+
This is fairly easy, but requires a few things.
247+
248+
### Rust side
249+
250+
First, we assume you have a lib crate named as `rust_from_c`.
251+
`lib.rs` should have Rust code as following:
252+
253+
```rust
254+
#[no_mangle]
255+
pub extern "C" fn hello_from_rust() {
256+
println!("Hello from Rust!");
257+
}
258+
# fn main() {}
259+
```
260+
261+
The `extern "C"` makes this function adhere to the C calling convention, as discussed above in "[Foreign Calling Conventions]".
262+
The `no_mangle` attribute turns off Rust's name mangling, so that it has a well defined symbol to link to.
263+
264+
Then, to compile Rust code as a shared library that can be called from C, add the following to your `Cargo.toml`:
265+
266+
```toml
267+
[lib]
268+
crate-type = ["cdylib"]
269+
```
270+
271+
(NOTE: We could also use the `staticlib` crate type but it needs to tweak some linking flags.)
272+
273+
Run `cargo build` and you're ready to go on the Rust side.
274+
275+
[Foreign Calling Conventions]: ffi.md#foreign-calling-conventions
276+
277+
### C side
278+
279+
We'll create a C file to call the `hello_from_rust` function and compile it by `gcc`.
280+
281+
C file should look like:
282+
283+
```c
284+
int main() {
285+
hello_from_rust();
286+
return 0;
287+
}
288+
```
289+
290+
We name the file as `call_rust.c` and place it on the crate root.
291+
Run the following to compile:
292+
293+
```sh
294+
gcc call_rust.c -o call_rust -lrust_from_c -L./target/debug
295+
```
296+
297+
`-l` and `-L` tell gcc to find our Rust library.
298+
299+
Finally, we can call Rust code from C with `LD_LIBRARY_PATH` specified:
300+
301+
```sh
302+
$ LD_LIBRARY_PATH=./target/debug ./call_rust
303+
Hello from Rust!
304+
```
305+
306+
That's it!
307+
For more realistic example, check the [`cbindgen`].
308+
309+
[`cbindgen`]: https://github.com/eqrion/cbindgen
310+
243311
## Callbacks from C code to Rust functions
244312

245313
Some external libraries require the usage of callbacks to report back their
@@ -648,24 +716,6 @@ void register(void (*f)(int (*)(int), int)) {
648716
649717
No `transmute` required!
650718
651-
## Calling Rust code from C
652-
653-
You may wish to compile Rust code in a way so that it can be called from C. This is
654-
fairly easy, but requires a few things:
655-
656-
```rust
657-
#[no_mangle]
658-
pub extern "C" fn hello_rust() -> *const u8 {
659-
"Hello, world!\0".as_ptr()
660-
}
661-
# fn main() {}
662-
```
663-
664-
The `extern "C"` makes this function adhere to the C calling convention, as
665-
discussed above in "[Foreign Calling
666-
Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle`
667-
attribute turns off Rust's name mangling, so that it is easier to link to.
668-
669719
## FFI and panics
670720
671721
It’s important to be mindful of `panic!`s when working with FFI. A `panic!`

0 commit comments

Comments
 (0)