summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poveda Ruiz <31802960+pvdrz@users.noreply.github.com>2022-11-01 08:16:41 -0500
committerGitHub <noreply@github.com>2022-11-01 08:16:41 -0500
commit4f92dfb7c59afa01e1e1ac305e9eea60d935d12d (patch)
tree6e367e4ef7da6c7941107363dbb385f3aca3b9fb
parentb3ac3efcf95220db6b32b63832bff15c5a482d97 (diff)
Add tutorial about non-system libraries (#2318)
* add tutorial about non-system libraries * fix broken comment * ignore code snippet
-rw-r--r--book/src/SUMMARY.md1
-rw-r--r--book/src/non-system-libraries.md106
2 files changed, 107 insertions, 0 deletions
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index e7feff95..551ea0d5 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -10,6 +10,7 @@
- [Include the Generated Bindings in `src/lib.rs`](./tutorial-4.md)
- [Write a Sanity Test](./tutorial-5.md)
- [Publish Your Crate!](./tutorial-6.md)
+ - [Bindings for non-system libraries](./non-system-libraries.md)
- [Command Line Usage](./command-line-usage.md)
- [Customizing the Generated Bindings](./customizing-generated-bindings.md)
- [Allowlisting](./allowlisting.md)
diff --git a/book/src/non-system-libraries.md b/book/src/non-system-libraries.md
new file mode 100644
index 00000000..c724a2fc
--- /dev/null
+++ b/book/src/non-system-libraries.md
@@ -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!");
+}
+```
+