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