Sourcebot logo
    /

    Calling C from Rust

    Public (Read-only)

    Recent Chats

    Sign in to access your chat history.

    How do I call C from Rust? Find some interesting examples in existing repos and include it in your answer

    Answer

    Calling C code from Rust is a common practice, especially when you need to interface with existing C libraries or when you need to write performance-critical code. Rust provides a foreign function interface (FFI) to make this possible.

    Here's how you can call C from Rust:

    1. The extern "C" block

    The extern "C" block is the most direct way to declare C functions in Rust. This tells the Rust compiler that the functions inside the block are defined elsewhere and use the C ABI.

    Here's an example from the ferrocene/ferrocene repository:

    1extern "C" {
    2 fn my_c_function(arg1: i32, arg2: *const c_char) -> c_int;
    3}

    In this example, my_c_function is a C function that takes an integer and a C string as arguments and returns an integer. The c_char and c_int types are from the std::os::raw module and correspond to the C char and int types, respectively.

    2. The cc crate

    The cc crate is a build dependency that makes it easy to compile C, C++, and assembly code from a build.rs script. This is the recommended way to build C code from a Rust project.

    Here's an example from the rust-lang/rust repository build.rs:2-2:

    1fn main() {
    2 cc::Build::new().file("foo.c").compile("foo_c");
    3}

    In this example, the build.rs script compiles the foo.c file and links it to the Rust project. The cc::Build::new() function creates a new build configuration, the file() method adds a C file to the build, and the compile() method compiles the C code and links it to the Rust project.

    3. The bindgen crate

    The bindgen crate is a tool that automatically generates Rust FFI bindings to C and C++ libraries. This is a very useful tool when you need to interface with a large C library.

    Here's an example of how you can use bindgen in your build.rs script:

    1use std::env;
    2use std::path::PathBuf;
    3
    4fn main() {
    5 println!("cargo:rerun-if-changed=wrapper.h");
    6
    7 let bindings = bindgen::Builder::default()
    8 .header("wrapper.h")
    9 .parse_callbacks(Box::new(bindgen::CargoCallbacks))
    10 .generate()
    11 .expect("Unable to generate bindings");
    12
    13 let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    14 bindings
    15 .write_to_file(out_path.join("bindings.rs"))
    16 .expect("Couldn't write bindings!");
    17}
    Show more

    In this example, the build.rs script generates Rust bindings for the C functions declared in the wrapper.h file and writes them to the bindings.rs file. The bindgen::Builder::default() function creates a new builder, the header() method sets the header file to use, the parse_callbacks() method sets the callbacks to use, and the generate() method generates the bindings.

    Interesting examples from existing repos

    Here are some interesting examples of C code being called from Rust in existing repositories:

    • rust-lang/rust: The Rust compiler itself uses the cc crate to compile C code for the LLVM and compiler-rt libraries build.rs:172-172.
    • tikv/tikv: The TiKV project uses the cc crate to compile C++ code for the RocksDB library build.rs:50-50.

    These are just a few examples of how you can call C from Rust. For more information, you can refer to the official Rust documentation on FFI.

    build.rs
    build.rs
    build.rs