forked from rust-lang/rust-bindgen
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tutorial about non-system libraries (rust-lang#2318)
* add tutorial about non-system libraries * fix broken comment * ignore code snippet
- Loading branch information
Showing
2 changed files
with
107 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
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 | ||
```c | ||
int hello() { | ||
return 42; | ||
} | ||
``` | ||
and a `c` header file `hello.h` containing | ||
```c | ||
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 | ||
libary: | ||
|
||
```rust,ignore | ||
extern crate bindgen; | ||
use std::env; | ||
use std::path::PathBuf; | ||
use bindgen::CargoCallbacks; | ||
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"); | ||
// Tell cargo to invalidate the built crate whenever the header changes. | ||
println!("cargo:rerun-if-changed={}", headers_path_str); | ||
// 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(CargoCallbacks)) | ||
// 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!"); | ||
} | ||
``` | ||
|