Bindings for non-system libraries - The bindgen User Guide
Description: `bindgen` automatically generates Rust FFI bindings to C and C++ libraries.

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

Now let’s suppose we want to generate bindings for a non-system library. We will be the same crate setup as the previous tutorial. First let’s create a new directory `hello` with two files inside it. A C source file `hello.c` containing

    int hello() {
        return 42;
    }

and a C header file `hello.h` containing

    int hello();

Given that the library has not been compiled yet, we need to modify the `build.rs` build script to compile the `hello.c` source file into a static library:

    use std::env;
    use std::path::PathBuf;

    fn main() {
        // This is the directory where the `c` library is located.
        let libdir_path = PathBuf::from("hello")
            // Canonicalize the path as `rustc-link-search` requires an absolute
            // path.
            .canonicalize()
            .expect("cannot canonicalize path");

        // This is the path to the `c` headers file.
        let headers_path = libdir_path.join("hello.h");
        let headers_path_str = headers_path.to_str().expect("Path is not a valid string");

        // This is the path to the intermediate object file for our library.
        let obj_path = libdir_path.join("hello.o");
        // This is the path to the static library file.
        let lib_path = libdir_path.join("libhello.a");

        // Tell cargo to look for shared libraries in the specified directory
        println!("cargo:rustc-link-search={}", libdir_path.to_str().unwrap());

        // Tell cargo to tell rustc to link our `hello` library. Cargo will
        // automatically know it must look for a `libhello.a` file.
        println!("cargo:rustc-link-lib=hello");

        // Run `clang` to compile the `hello.c` file into a `hello.o` object file.
        // Unwrap if it is not possible to spawn the process.
        if !std::process::Command::new("clang")
            .arg("-c")
            .arg("-o")
            .arg(&obj_path)
            .arg(libdir_path.join("hello.c"))
            .output()
            .expect("could not spawn `clang`")
            .status
            .success()
        {
            // Panic if the command was not successful.
            panic!("could not compile object file");
        }

        // Run `ar` to generate the `libhello.a` file from the `hello.o` file.
        // Unwrap if it is not possible to spawn the process.
        if !std::process::Command::new("ar")
            .arg("rcs")
            .arg(lib_path)
            .arg(obj_path)
            .output()
            .expect("could not spawn `ar`")
            .status
            .success()
        {
            // Panic if the command was not successful.
            panic!("could not emit library file");
        }

        // The bindgen::Builder is the main entry point
        // to bindgen, and lets you build up options for
        // the resulting bindings.
        let bindings = bindgen::Builder::default()
            // The input header we would like to generate
            // bindings for.
            .header(headers_path_str)
            // Tell cargo to invalidate the built crate whenever any of the
            // included header files changed.
            .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
            // Finish the builder and generate the bindings.
            .generate()
            // Unwrap the Result and panic on failure.
            .expect("Unable to generate bindings");

        // Write the bindings to the $OUT_DIR/bindings.rs file.
        let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs");
        bindings
            .write_to_file(out_path)
            .expect("Couldn't write bindings!");
    }