1Now let's suppose we want to generate bindings for a non-system library. We 2will be the same crate setup as the previous tutorial. First let's create a new 3directory `hello` with two files inside it. A C source file `hello.c` 4containing 5```c 6int hello() { 7 return 42; 8} 9``` 10and a C header file `hello.h` containing 11```c 12int hello(); 13``` 14 15Given that the library has not been compiled yet, we need to modify the 16`build.rs` build script to compile the `hello.c` source file into a static 17library: 18 19```rust,ignore 20use std::env; 21use std::path::PathBuf; 22 23use bindgen::CargoCallbacks; 24 25fn main() { 26 // This is the directory where the `c` library is located. 27 let libdir_path = PathBuf::from("hello") 28 // Canonicalize the path as `rustc-link-search` requires an absolute 29 // path. 30 .canonicalize() 31 .expect("cannot canonicalize path"); 32 33 // This is the path to the `c` headers file. 34 let headers_path = libdir_path.join("hello.h"); 35 let headers_path_str = headers_path.to_str().expect("Path is not a valid string"); 36 37 // This is the path to the intermediate object file for our library. 38 let obj_path = libdir_path.join("hello.o"); 39 // This is the path to the static library file. 40 let lib_path = libdir_path.join("libhello.a"); 41 42 // Tell cargo to look for shared libraries in the specified directory 43 println!("cargo:rustc-link-search={}", libdir_path.to_str().unwrap()); 44 45 // Tell cargo to tell rustc to link our `hello` library. Cargo will 46 // automatically know it must look for a `libhello.a` file. 47 println!("cargo:rustc-link-lib=hello"); 48 49 // Run `clang` to compile the `hello.c` file into a `hello.o` object file. 50 // Unwrap if it is not possible to spawn the process. 51 if !std::process::Command::new("clang") 52 .arg("-c") 53 .arg("-o") 54 .arg(&obj_path) 55 .arg(libdir_path.join("hello.c")) 56 .output() 57 .expect("could not spawn `clang`") 58 .status 59 .success() 60 { 61 // Panic if the command was not successful. 62 panic!("could not compile object file"); 63 } 64 65 // Run `ar` to generate the `libhello.a` file from the `hello.o` file. 66 // Unwrap if it is not possible to spawn the process. 67 if !std::process::Command::new("ar") 68 .arg("rcs") 69 .arg(lib_path) 70 .arg(obj_path) 71 .output() 72 .expect("could not spawn `ar`") 73 .status 74 .success() 75 { 76 // Panic if the command was not successful. 77 panic!("could not emit library file"); 78 } 79 80 // The bindgen::Builder is the main entry point 81 // to bindgen, and lets you build up options for 82 // the resulting bindings. 83 let bindings = bindgen::Builder::default() 84 // The input header we would like to generate 85 // bindings for. 86 .header(headers_path_str) 87 // Tell cargo to invalidate the built crate whenever any of the 88 // included header files changed. 89 .parse_callbacks(Box::new(CargoCallbacks::new())) 90 // Finish the builder and generate the bindings. 91 .generate() 92 // Unwrap the Result and panic on failure. 93 .expect("Unable to generate bindings"); 94 95 // Write the bindings to the $OUT_DIR/bindings.rs file. 96 let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs"); 97 bindings 98 .write_to_file(out_path) 99 .expect("Couldn't write bindings!"); 100} 101``` 102