summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml8
-rw-r--r--README.md234
-rw-r--r--book/.gitignore1
-rw-r--r--book/book.toml3
-rw-r--r--book/src/SUMMARY.md20
-rw-r--r--book/src/blacklisting.md26
-rw-r--r--book/src/chapter_1.md1
-rw-r--r--book/src/command-line-usage.md27
-rw-r--r--book/src/cpp.md27
-rw-r--r--book/src/customizing-generated-bindings.md28
-rw-r--r--book/src/introduction.md34
-rw-r--r--book/src/library-usage.md22
-rw-r--r--book/src/nocopy.md20
-rw-r--r--book/src/opaque.md26
-rw-r--r--book/src/replacing-types.md27
-rw-r--r--book/src/requirements.md67
-rw-r--r--book/src/tutorial-0.md12
-rw-r--r--book/src/tutorial-1.md9
-rw-r--r--book/src/tutorial-2.md20
-rw-r--r--book/src/tutorial-3.md58
-rw-r--r--book/src/tutorial-4.md57
-rw-r--r--book/src/tutorial-5.md169
-rw-r--r--book/src/tutorial-6.md13
-rw-r--r--book/src/whitelisting.md31
-rwxr-xr-xci/deploy-book.sh33
-rwxr-xr-xci/test-book.sh10
26 files changed, 775 insertions, 208 deletions
diff --git a/.travis.yml b/.travis.yml
index 2def8e3a..f66c7d36 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,6 +38,14 @@ script:
# - ./ci/assert-rustfmt.sh
- BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/assert-docs.sh
- BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/test.sh
+ - ./ci/test-book.sh
+
+after_success:
+ - test "$TRAVIS_PULL_REQUEST" == "false" &&
+ test "$TRAVIS_BRANCH" == "master" &&
+ test "$BINDGEN_FEATURES" == "" &&
+ test "$LLVM_VERSION" == "3.9.0" &&
+ ./ci/deploy-book.sh
notifications:
webhooks: http://build.servo.org:54856/travis
diff --git a/README.md b/README.md
index 9c219ef5..055ac7a7 100644
--- a/README.md
+++ b/README.md
@@ -1,227 +1,45 @@
# `bindgen`
-Automatically generates Rust FFI bindings to C and C++ libraries.
+**`bindgen` automatically generates Rust FFI bindings to C and C++ libraries.**
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+For example, given the C header `cool.h`:
+```c
+typedef struct CoolStruct {
+ int x;
+ int y;
+} CoolStruct;
-- [Usage](#usage)
- - [Requirements](#requirements)
- - [Installing Clang 3.9](#installing-clang-39)
- - [Windows](#windows)
- - [OSX](#osx)
- - [Debian-based Linuxes](#debian-based-linuxes)
- - [Arch](#arch)
- - [From source](#from-source)
- - [Library usage with `build.rs`](#library-usage-with-buildrs)
- - [`build.rs` Tutorial](#buildrs-tutorial)
- - [Simple Example: `./bindgen-integration`](#simple-example-bindgen-integration)
- - [Real World Example: Stylo](#real-world-example-stylo)
- - [Command Line Usage](#command-line-usage)
- - [C++](#c)
- - [Annotations](#annotations)
- - [`opaque`](#opaque)
- - [`hide`](#hide)
- - [`replaces`](#replaces)
- - [`nocopy`](#nocopy)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
-
-## Usage
-
-### Requirements
-
-It is recommended to use Clang 3.9 or greater, however `bindgen` can run with
-older Clangs with some features disabled.
-
-#### Installing Clang 3.9
-
-##### Windows
-
-Download and install the official pre-built binary from
-[LLVM download page](http://releases.llvm.org/download.html).
-
-##### OSX
-
-If you use Homebrew:
-
-```
-$ brew install llvm
-```
-
-If you use MacPorts:
-
-```
-$ port install clang-3.9
-```
-
-##### Debian-based Linuxes
-
+void cool_function(int i, char c, CoolStruct* cs);
```
-# apt-get install llvm-3.9-dev libclang-3.9-dev clang-3.9
-```
-
-Ubuntu 16.10 provides the necessary packages directly. If you are using older
-version of Ubuntu or other Debian-based distros, you may need to add the LLVM
-repos to get version 3.9. See http://apt.llvm.org/.
-
-##### Arch
-
-```
-# pacman -S clang
-```
-
-##### From source
-
-If your package manager doesn't yet offer Clang 3.9, you'll need to build from
-source. For that, follow the instructions
-[here](http://clang.llvm.org/get_started.html).
-
-Those instructions list optional steps. For bindgen:
-
-* Checkout and build clang
-* Checkout and build the extra-clang-tools
-* Checkout and build the compiler-rt
-* You do not need to checkout or build libcxx
-
-### Library usage with `build.rs`
-
-💡 This is the recommended way to use `bindgen`. 💡
-
-#### `build.rs` Tutorial
-
-[Here is a step-by-step tutorial for generating FFI bindings to the `bzip2` C library.][tutorial]
-
-[tutorial]: http://fitzgeraldnick.com/2016/12/14/using-libbindgen-in-build-rs.html
-
-#### Simple Example: `./bindgen-integration`
-
-The [`./bindgen-integration`][integration] directory has an example crate that
-generates FFI bindings in `build.rs` and can be used a template for new
-projects.
-
-[integration]: ./bindgen-integration
-#### Real World Example: Stylo
-
-A real world example is [the Stylo build script][stylo-script] used for
-integrating Servo's layout system into Gecko.
-
-[stylo-script]: https://github.com/servo/servo/blob/master/components/style/build_gecko.rs
-
-In `Cargo.toml`:
-
-```toml
-[package]
-# ...
-build = "build.rs"
-
-[build-dependencies]
-bindgen = "0.20"
-```
-
-In `build.rs`:
+`bindgen` produces Rust FFI code allowing you to call into the `cool` library's
+functions and use its types:
```rust
-extern crate bindgen;
+/* automatically generated by rust-bindgen */
-use std::env;
-use std::path::Path;
-
-fn main() {
- let out_dir = env::var("OUT_DIR").unwrap();
- let _ = bindgen::builder()
- .header("example.h")
- .use_core()
- .generate().unwrap()
- .write_to_file(Path::new(&out_dir).join("example.rs"));
+#[repr(C)]
+pub struct CoolStruct {
+ pub x: ::std::os::raw::c_int,
+ pub y: ::std::os::raw::c_int,
}
-```
-
-In `src/main.rs`:
-
-```rust
-include!(concat!(env!("OUT_DIR"), "/example.rs"));
-```
-
-### Command Line Usage
-
-```
-$ cargo install bindgen
-```
-
-There are a few options documented when running `bindgen --help`. Bindgen is installed to `~/.cargo/bin`. You have to add that directory to your path to use `bindgen`.
-### C++
-
-`bindgen` can handle most C++ features, but not all of them (C++ is hard!)
-
-Notable C++ features that are unsupported or only partially supported:
-
-* Partial template specialization
-* Traits templates
-* SFINAE
-* Instantiating new template specializations
-
-When passing in header files, the file will automatically be treated as C++ if
-it ends in ``.hpp``. If it doesn't, ``-x c++`` can be used to force C++ mode.
-
-You must use whitelisting when working with C++ to avoid pulling in all of the
-`std::*` types, some of which `bindgen` cannot handle. Additionally, you may
-want to blacklist other types that `bindgen` stumbles on, or make `bindgen`
-treat certain types as opaque.
-
-### Annotations
-
-The translation of classes, structs, enums, and typedefs can be adjusted using
-annotations. Annotations are specifically formatted html tags inside doxygen
-style comments.
-
-#### `opaque`
-
-The `opaque` annotation instructs bindgen to ignore all fields defined in
-a struct/class.
-
-```cpp
-/// <div rustbindgen opaque></div>
-```
-
-#### `hide`
-
-The `hide` annotation instructs bindgen to ignore the struct/class/field/enum
-completely.
-
-```cpp
-/// <div rustbindgen hide></div>
+extern "C" {
+ pub fn cool_function(i: ::std::os::raw::c_int,
+ c: ::std::os::raw::c_char,
+ cs: *mut CoolStruct);
+}
```
-#### `replaces`
+## Users Guide
-The `replaces` annotation can be used to use a type as a replacement for other
-(presumably more complex) type. This is used in Stylo to generate bindings for
-structures that for multiple reasons are too complex for bindgen to understand.
+[📚 Read the `bindgen` users guide here! 📚](https://servo.github.io/rust-bindgen)
-For example, in a C++ header:
-
-```cpp
-/**
- * <div rustbindgen replaces="nsTArray"></div>
- */
-template<typename T>
-class nsTArray_Simple {
- T* mBuffer;
-public:
- // The existence of a destructor here prevents bindgen from deriving the Clone
- // trait via a simple memory copy.
- ~nsTArray_Simple() {};
-};
-```
+## API Reference
-That way, after code generation, the bindings for the `nsTArray` type are
-the ones that would be generated for `nsTArray_Simple`.
+[API reference documentation is on docs.rs](https://docs.rs/bindgen)
-#### `nocopy`
+## Contributing
-The `nocopy` annotation is used to prevent bindgen to autoderive the `Copy`
-and `Clone` traits for a type.
+[See `CONTRIBUTING.md` for hacking on `bindgen`!](./CONTRIBUTING.md)
diff --git a/book/.gitignore b/book/.gitignore
new file mode 100644
index 00000000..7585238e
--- /dev/null
+++ b/book/.gitignore
@@ -0,0 +1 @@
+book
diff --git a/book/book.toml b/book/book.toml
new file mode 100644
index 00000000..e94e3046
--- /dev/null
+++ b/book/book.toml
@@ -0,0 +1,3 @@
+title = "The `bindgen` User Guide"
+author = "The Servo project developers"
+description = "`bindgen` automatically generates Rust FFI bindings to C and C++ libraries."
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
new file mode 100644
index 00000000..1a1818f8
--- /dev/null
+++ b/book/src/SUMMARY.md
@@ -0,0 +1,20 @@
+# Summary
+
+- [Introduction](./introduction.md)
+- [Requirements](./requirements.md)
+- [Library Usage with `build.rs`](./library-usage.md)
+ - [Tutorial](./tutorial-0.md)
+ - [Add `bindgen` as a Build Dependency](./tutorial-1.md)
+ - [Create a `wrapper.h` Header](./tutorial-2.md)
+ - [Create a `build.rs` File](./tutorial-3.md)
+ - [Include the Generated Bindings in `src/lib.rs`](./tutorial-4.md)
+ - [Write a Sanity Test](./tutorial-5.md)
+ - [Publish Your Crate!](./tutorial-6.md)
+- [Command Line Usage](./command-line-usage.md)
+- [Customizing the Generated Bindings](./customizing-generated-bindings.md)
+ - [Whitelisting](./whitelisting.md)
+ - [Blacklisting](./blacklisting.md)
+ - [Treating a Type as an Opaque Blob of Bytes](./opaque.md)
+ - [Replacing One Type with Another](./replacing-types.md)
+ - [Preventing the Derivation of `Copy` and `Clone`](./nocopy.md)
+- [Generating Bindings to C++](./cpp.md)
diff --git a/book/src/blacklisting.md b/book/src/blacklisting.md
new file mode 100644
index 00000000..990947ab
--- /dev/null
+++ b/book/src/blacklisting.md
@@ -0,0 +1,26 @@
+# Blacklisting
+
+If you need to provide your own custom translation of some type (for example,
+because you need to wrap one of its fields in an `UnsafeCell`), you can
+explicitly blacklist generation of its definition. Uses of the blacklisted type
+will still appear in other types' definitions. (If you don't want the type to
+appear in the bindings at
+all, [make it opaque](./opaque.html) instead of
+blacklisting it.)
+
+### Library
+
+* [`bindgen::Builder::hide_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.hide_type)
+
+### Command Line
+
+* `--blacklist-type <type>`
+
+### Annotations
+
+```cpp
+/// <div rustbindgen hide></div>
+class Foo {
+ // ...
+};
+```
diff --git a/book/src/chapter_1.md b/book/src/chapter_1.md
new file mode 100644
index 00000000..b743fda3
--- /dev/null
+++ b/book/src/chapter_1.md
@@ -0,0 +1 @@
+# Chapter 1
diff --git a/book/src/command-line-usage.md b/book/src/command-line-usage.md
new file mode 100644
index 00000000..d90eb442
--- /dev/null
+++ b/book/src/command-line-usage.md
@@ -0,0 +1,27 @@
+# Command Line Usage
+
+Install the `bindgen` executable with `cargo`:
+
+```bash
+$ cargo install bindgen
+```
+
+The `bindgen` executable is installed to `~/.cargo/bin`. You have to add that
+directory to your `$PATH` to use `bindgen`.
+
+`bindgen` takes the path to an input C or C++ header file, and optionally an
+output file path for the generated bindings. If the output file path is not
+supplied, the bindings are printed to `stdout`.
+
+If we wanted to generated Rust FFI bindings from a C header named `input.h` and
+put them in the `bindings.rs` file, we would invoke `bindgen` like this:
+
+```bash
+$ bindgen input.h -o bindings.rs
+```
+
+For more details, pass the `--help` flag:
+
+```bash
+$ bindgen --help
+```
diff --git a/book/src/cpp.md b/book/src/cpp.md
new file mode 100644
index 00000000..e0fbecb7
--- /dev/null
+++ b/book/src/cpp.md
@@ -0,0 +1,27 @@
+# Generating Bindings to C++
+
+`bindgen` can handle a surprising number of C++ features, but not all of
+them. When `bindgen` can't translate some C++ construct into Rust, it usually
+comes down to one of two things:
+
+1. Rust has no equivalent language feature
+2. C++ is *hard!*
+
+Notable C++ features that are unsupported or only partially supported, and for
+which `bindgen` *should* generate opaque blobs whenever it finds an occurrence
+of them in a type it is generating bindings for:
+
+* Template specialization
+* Partial template specialization
+* Traits templates
+* SFINAE
+
+When passing in header files, the file will automatically be treated as C++ if
+it ends in `.hpp`. If it doesn't, adding `-x=c++` clang args can be used to
+force C++ mode. You probably also want to use `-std=c++14` or similar clang args
+as well.
+
+You pretty much **must** use [whitelisting](./whitelisting.html) when working
+with C++ to avoid pulling in all of the `std::*` types, many of which `bindgen`
+cannot handle. Additionally, you may want to mark other types
+as [opaque](./opaque.html) that `bindgen` stumbles on.
diff --git a/book/src/customizing-generated-bindings.md b/book/src/customizing-generated-bindings.md
new file mode 100644
index 00000000..aaaaebea
--- /dev/null
+++ b/book/src/customizing-generated-bindings.md
@@ -0,0 +1,28 @@
+# Customizing the Generated Bindings
+
+The translation of classes, structs, enums, and typedefs can be adjusted in a
+few ways:
+
+1. By using the `bindgen::Builder`'s configuration methods, when using `bindgen`
+ as a library.
+
+2. By passing extra flags and options to the `bindgen` executable.
+
+3. By adding an annotation comment to the C/C++ source code. Annotations are
+ specially formatted HTML tags inside doxygen style comments:
+
+ * For single line comments:
+ ```c
+ /// <div rustbindgen></div>
+ ```
+
+ * For multi-line comments:
+ ```c
+ /**
+ * <div rustbindgen></div>
+ */
+ ```
+
+We'll leave the nitty-gritty details to
+the [docs.rs API reference](https://docs.rs/bindgen) and `bindgen --help`, but
+provide higher level concept documentation here.
diff --git a/book/src/introduction.md b/book/src/introduction.md
new file mode 100644
index 00000000..4c5fbd49
--- /dev/null
+++ b/book/src/introduction.md
@@ -0,0 +1,34 @@
+# Introduction
+
+**[`bindgen`](https://github.com/servo/rust-bindgen) automatically generates Rust
+FFI bindings to C and C++ libraries.**
+
+For example, given the C header `cool.h`:
+
+```c
+typedef struct CoolStruct {
+ int x;
+ int y;
+} CoolStruct;
+
+void cool_function(int i, char c, CoolStruct* cs);
+```
+
+`bindgen` produces Rust FFI code allowing you to call into the `cool` library's
+functions and use its types:
+
+```rust
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+pub struct CoolStruct {
+ pub x: ::std::os::raw::c_int,
+ pub y: ::std::os::raw::c_int,
+}
+
+extern "C" {
+ pub fn cool_function(i: ::std::os::raw::c_int,
+ c: ::std::os::raw::c_char,
+ cs: *mut CoolStruct);
+}
+```
diff --git a/book/src/library-usage.md b/book/src/library-usage.md
new file mode 100644
index 00000000..35b53fe4
--- /dev/null
+++ b/book/src/library-usage.md
@@ -0,0 +1,22 @@
+# Library Usage with `build.rs`
+
+💡 This is the recommended way to use `bindgen`. 💡
+
+Often times C and C++ headers will have platform- and architecture-specific
+`#ifdef`s that affect the shape of the Rust FFI bindings we need to create to
+interface Rust code with the outside world. By using `bindgen` as a library
+inside your `build.rs`, you can generate bindings for the current target
+on-the-fly. Otherwise, you would need to generate and maintain
+`x86_64-unknown-linux-gnu-bindings.rs`, `x86_64-apple-darwin-bindings.rs`,
+etc... separate bindings files for each of your supported targets, which can be
+a huge pain. The downside is that everyone building your crate also needs
+`libclang` available to run `bindgen`.
+
+## Library API Documentation
+
+[📚 There is complete API reference documentation on docs.rs 📚](https://docs.rs/bindgen)
+
+## Tutorial
+
+The next section contains a detailed, step-by-step tutorial for using `bindgen`
+as a library inside `build.rs`.
diff --git a/book/src/nocopy.md b/book/src/nocopy.md
new file mode 100644
index 00000000..893f0932
--- /dev/null
+++ b/book/src/nocopy.md
@@ -0,0 +1,20 @@
+# Preventing the Derivation of `Copy` and `Clone`
+
+`bindgen` will attempt to derive the `Copy` and `Clone` traits on a best-effort
+basis. Sometimes, it might not understand that although adding `#[derive(Copy,
+Clone)]` to a translated type definition will compile, it still shouldn't do
+that for reasons it can't know. In these cases, the `nocopy` annotation can be
+used to prevent bindgen to autoderive the `Copy` and `Clone` traits for a type.
+
+```c
+/**
+ * Although bindgen can't know, this struct is not safe to move because pthread
+ * mutexes can't move in memory!
+ *
+ * <div rustbindgen nocopy></div>
+ */
+struct MyMutexWrapper {
+ pthread_mutex_t raw;
+ // ...
+};
+```
diff --git a/book/src/opaque.md b/book/src/opaque.md
new file mode 100644
index 00000000..e1bf600c
--- /dev/null
+++ b/book/src/opaque.md
@@ -0,0 +1,26 @@
+# Treating a Type as an Opaque Blob of Bytes
+
+Sometimes a type definition is simply not translatable to Rust, for example it
+uses
+[C++'s SFINAE](https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error) for
+which Rust has no equivalent. In these cases, it is best to treat all
+occurrences of the type as an opaque blob of bytes with a size and
+alignment. `bindgen` will attempt to detect such cases and do this
+automatically, but other times it needs some explicit help from you.
+
+### Library
+
+* [`bindgen::Builder::opaque_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.opaque_type)
+
+### Command Line
+
+* `--opaque-type <type>`
+
+### Annotation
+
+```cpp
+/// <div rustbindgen opaque></div>
+class Foo {
+ // ...
+};
+```
diff --git a/book/src/replacing-types.md b/book/src/replacing-types.md
new file mode 100644
index 00000000..7426d2ea
--- /dev/null
+++ b/book/src/replacing-types.md
@@ -0,0 +1,27 @@
+# Replacing One Type with Another
+
+The `replaces` annotation can be used to use a type as a replacement for other
+(presumably more complex) type. This is used in Stylo to generate bindings for
+structures that for multiple reasons are too complex for bindgen to understand.
+
+For example, in a C++ header:
+
+```cpp
+/**
+ * <div rustbindgen replaces="nsTArray"></div>
+ */
+template<typename T>
+class nsTArray_Simple {
+ T* mBuffer;
+public:
+ // The existence of a destructor here prevents bindgen from deriving the Clone
+ // trait via a simple memory copy.
+ ~nsTArray_Simple() {};
+};
+```
+
+That way, after code generation, the bindings for the `nsTArray` type are
+the ones that would be generated for `nsTArray_Simple`.
+
+Replacing is only available as an annotation. To replace a C or C++ definition
+with a Rust definition, use [blacklisting](./blacklisting.html).
diff --git a/book/src/requirements.md b/book/src/requirements.md
new file mode 100644
index 00000000..82da9991
--- /dev/null
+++ b/book/src/requirements.md
@@ -0,0 +1,67 @@
+# Requirements
+
+This page lists the requirements for running `bindgen` and how to get them.
+
+## Clang
+
+`bindgen` leverages `libclang` to preprocess, parse, and type check C and C++
+header files.
+
+It is recommended to use Clang 3.9 or greater, however `bindgen` can run with
+older Clangs with some features disabled.
+
+* **If you are generating bindings to C,** 3.7 and 3.8 will probably work OK for
+you.
+
+* **If you are generating bindings to C++,** you almost definitely want 3.9 or
+greater.
+
+### Installing Clang 3.9
+
+#### Windows
+
+Download and install the official pre-built binary from
+[LLVM download page](http://releases.llvm.org/download.html).
+
+#### macOS
+
+If you use Homebrew:
+
+```bash
+$ brew install llvm@3.9
+```
+
+If you use MacPorts:
+
+```bash
+$ port install clang-3.9
+```
+
+#### Debian-based Linuxes
+
+```bash
+# apt-get install llvm-3.9-dev libclang-3.9-dev clang-3.9
+```
+
+Ubuntu 16.10 provides the necessary packages directly. If you are using older
+version of Ubuntu or other Debian-based distros, you may need to add the LLVM
+repos to get version 3.9. See http://apt.llvm.org/.
+
+#### Arch
+
+```bash
+# pacman -S clang
+```
+
+#### From source
+
+If your package manager doesn't yet offer Clang 3.9, you'll need to build from
+source. For that, follow the
+instructions [here](http://clang.llvm.org/get_started.html).
+
+Those instructions list optional steps. For `bindgen`:
+
+* Checkout and build clang
+* Checkout and build the extra-clang-tools
+* You do not need to checkout or build compiler-rt
+* You do not need to checkout or build libcxx
diff --git a/book/src/tutorial-0.md b/book/src/tutorial-0.md
new file mode 100644
index 00000000..adb84308
--- /dev/null
+++ b/book/src/tutorial-0.md
@@ -0,0 +1,12 @@
+# Tutorial
+
+The following tutorial is adapted from [this blog post][tutorial].
+
+What follows is a whirlwind introductory tutorial to using `bindgen` from inside
+`build.rs`. We'll generate bindings to `bzip2` (which is available on most
+systems) on-the-fly.
+
+[**TL;DR?** The full tutorial code is available here.][example]
+
+[tutorial]: http://fitzgeraldnick.com/2016/12/14/using-libbindgen-in-build-rs.html
+[example]: https://github.com/fitzgen/libbindgen-tutorial-bzip2-sys
diff --git a/book/src/tutorial-1.md b/book/src/tutorial-1.md
new file mode 100644
index 00000000..1b109506
--- /dev/null
+++ b/book/src/tutorial-1.md
@@ -0,0 +1,9 @@
+# Add `bindgen` as a Build Dependency
+
+Declare a build-time dependency on `bindgen` by adding it to the
+`[build-dependencies]` section of our crate's `Cargo.toml` metadata file:
+
+```toml
+[build-dependencies]
+bindgen = "0.23"
+```
diff --git a/book/src/tutorial-2.md b/book/src/tutorial-2.md
new file mode 100644
index 00000000..e1e88811
--- /dev/null
+++ b/book/src/tutorial-2.md
@@ -0,0 +1,20 @@
+# Create a `wrapper.h` Header
+
+The `wrapper.h` file will include all the various headers containing
+declarations of structs and functions we would like bindings for. In the
+particular case of `bzip2`, this is pretty easy since the entire public API is
+contained in a single header. For a project like [SpiderMonkey][spidermonkey],
+where the public API is split across multiple header files and grouped by
+functionality, we'd want to include all those headers we want to bind to in this
+single `wrapper.h` entry point for `bindgen`.
+
+Here is our `wrapper.h`:
+
+```c
+#include <bzlib.h>
+```
+
+This is also where we would add any [replacement types](./replacing-types.html),
+if we were using some.
+
+[spidermonkey]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/How_to_embed_the_JavaScript_engine
diff --git a/book/src/tutorial-3.md b/book/src/tutorial-3.md
new file mode 100644
index 00000000..7c081a4d
--- /dev/null
+++ b/book/src/tutorial-3.md
@@ -0,0 +1,58 @@
+# Create a `build.rs` File
+
+First, we have to tell `cargo` that we have a `build.rs` script by adding
+another line to the `Cargo.toml`:
+
+```toml
+[package]
+build = "build.rs"
+```
+
+Second, we create the `build.rs` file in our crate's root. This file is compiled
+and executed before the rest of the crate is built, and can be used to generate
+code at compile time. And of course in our case, we will be generating Rust FFI
+bindings to `bzip2` at compile time. The resulting bindings will be written to
+`$OUT_DIR/bindings.rs` where `$OUT_DIR` is chosen by `cargo` and is something
+like `./target/debug/build/libbindgen-tutorial-bzip2-sys-afc7747d7eafd720/out/`.
+
+```rust,ignore
+extern crate bindgen;
+
+use std::env;
+use std::path::PathBuf;
+
+fn main() {
+ // Tell cargo to tell rustc to link the system bzip2
+ // shared library.
+ println!("cargo:rustc-link-lib=bz2");
+
+ // 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()
+ // Do not generate unstable Rust code that
+ // requires a nightly rustc and enabling
+ // unstable features.
+ .no_unstable_rust()
+ // The input header we would like to generate
+ // bindings for.
+ .header("wrapper.h")
+ // 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());
+ bindings
+ .write_to_file(out_path.join("bindings.rs"))
+ .expect("Couldn't write bindings!");
+}
+```
+
+Now, when we run `cargo build`, our bindings to `bzip2` are generated on the
+fly!
+
+[There's more info about `build.rs` files in the crates.io documentation.][build-rs]
+
+[build-rs]: http://doc.crates.io/build-script.html
diff --git a/book/src/tutorial-4.md b/book/src/tutorial-4.md
new file mode 100644
index 00000000..42aa92fd
--- /dev/null
+++ b/book/src/tutorial-4.md
@@ -0,0 +1,57 @@
+# Include the Generated Bindings in `src/lib.rs`
+
+We can use the `include!` macro to dump our generated bindings right into our
+crate's main entry point, `src/lib.rs`:
+
+```rust,ignore
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+```
+
+Because `bzip2`'s symbols do not follow Rust's style conventions, we suppress a
+bunch of warnings with a few `#![allow(...)]` pragmas.
+
+We can run `cargo build` again to check that the bindings themselves compile:
+
+```bash
+$ cargo build
+ Compiling libbindgen-tutorial-bzip2-sys v0.1.0
+ Finished debug [unoptimized + debuginfo] target(s) in 62.8 secs
+```
+
+And we can run `cargo test` to verify that the layout, size, and alignment of
+our generated Rust FFI structs match what `bindgen` thinks they should be:
+
+```bash
+$ cargo test
+ Compiling libbindgen-tutorial-bzip2-sys v0.1.0
+ Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
+ Running target/debug/deps/bzip2_sys-10413fc2af207810
+
+running 14 tests
+test bindgen_test_layout___darwin_pthread_handler_rec ... ok
+test bindgen_test_layout___sFILE ... ok
+test bindgen_test_layout___sbuf ... ok
+test bindgen_test_layout__bindgen_ty_1 ... ok
+test bindgen_test_layout__bindgen_ty_2 ... ok
+test bindgen_test_layout__opaque_pthread_attr_t ... ok
+test bindgen_test_layout__opaque_pthread_cond_t ... ok
+test bindgen_test_layout__opaque_pthread_mutex_t ... ok
+test bindgen_test_layout__opaque_pthread_condattr_t ... ok
+test bindgen_test_layout__opaque_pthread_mutexattr_t ... ok
+test bindgen_test_layout__opaque_pthread_once_t ... ok
+test bindgen_test_layout__opaque_pthread_rwlock_t ... ok
+test bindgen_test_layout__opaque_pthread_rwlockattr_t ... ok
+test bindgen_test_layout__opaque_pthread_t ... ok
+
+test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured
+
+ Doc-tests libbindgen-tutorial-bzip2-sys
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+```
diff --git a/book/src/tutorial-5.md b/book/src/tutorial-5.md
new file mode 100644
index 00000000..7ff5ffb9
--- /dev/null
+++ b/book/src/tutorial-5.md
@@ -0,0 +1,169 @@
+# Write a Sanity Test
+
+Finally, to tie everything together, let's write a sanity test that round trips
+some text through compression and decompression, and then asserts that it came
+back out the same as it went in. This is a little wordy using the raw FFI
+bindings, but hopefully we wouldn't usually ask people to do this, we'd provide
+a nice Rust-y API on top of the raw FFI bindings for them. However, since this
+is for testing the bindings directly, our sanity test will use the bindings
+directly.
+
+The test data I'm round tripping are some Futurama quotes I got off the internet
+and put in the `futurama-quotes.txt` file, which is read into a `&'static str`
+at compile time via the `include_str!("../futurama-quotes.txt")` macro
+invocation.
+
+Without further ado, here is the test, which should be appended to the bottom of
+our `src/lib.rs` file:
+
+```rust
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::mem;
+
+ #[test]
+ fn round_trip_compression_decompression() {
+ unsafe {
+ let input = include_str!("../futurama-quotes.txt").as_bytes();
+ let mut compressed_output: Vec<u8> = vec![0; input.len()];
+ let mut decompressed_output: Vec<u8> = vec![0; input.len()];
+
+ // Construct a compression stream.
+ let mut stream: bz_stream = mem::zeroed();
+ let result = BZ2_bzCompressInit(&mut stream as *mut _,
+ 1, // 1 x 100000 block size
+ 4, // verbosity (4 = most verbose)
+ 0); // default work factor
+ match result {
+ r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),
+ r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
+ r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
+ r if r == (BZ_OK as _) => {},
+ r => panic!("Unknown return value = {}", r),
+ }
+
+ // Compress `input` into `compressed_output`.
+ stream.next_in = input.as_ptr() as *mut _;
+ stream.avail_in = input.len() as _;
+ stream.next_out = compressed_output.as_mut_ptr() as *mut _;
+ stream.avail_out = compressed_output.len() as _;
+ let result = BZ2_bzCompress(&mut stream as *mut _, BZ_FINISH as _);
+ match result {
+ r if r == (BZ_RUN_OK as _) => panic!("BZ_RUN_OK"),
+ r if r == (BZ_FLUSH_OK as _) => panic!("BZ_FLUSH_OK"),
+ r if r == (BZ_FINISH_OK as _) => panic!("BZ_FINISH_OK"),
+ r if r == (BZ_SEQUENCE_ERROR as _) => panic!("BZ_SEQUENCE_ERROR"),
+ r if r == (BZ_STREAM_END as _) => {},
+ r => panic!("Unknown return value = {}", r),
+ }
+
+ // Finish the compression stream.
+ let result = BZ2_bzCompressEnd(&mut stream as *mut _);
+ match result {
+ r if r == (BZ_PARAM_ERROR as _) => panic!(BZ_PARAM_ERROR),
+ r if r == (BZ_OK as _) => {},
+ r => panic!("Unknown return value = {}", r),
+ }
+
+ // Construct a decompression stream.
+ let mut stream: bz_stream = mem::zeroed();
+ let result = BZ2_bzDecompressInit(&mut stream as *mut _,
+ 4, // verbosity (4 = most verbose)
+ 0); // default small factor
+ match result {
+ r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),
+ r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
+ r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
+ r if r == (BZ_OK as _) => {},
+ r => panic!("Unknown return value = {}", r),
+ }
+
+ // Decompress `compressed_output` into `decompressed_output`.
+ stream.next_in = compressed_output.as_ptr() as *mut _;
+ stream.avail_in = compressed_output.len() as _;
+ stream.next_out = decompressed_output.as_mut_ptr() as *mut _;
+ stream.avail_out = decompressed_output.len() as _;
+ let result = BZ2_bzDecompress(&mut stream as *mut _);
+ match result {
+ r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
+ r if r == (BZ_DATA_ERROR as _) => panic!("BZ_DATA_ERROR"),
+ r if r == (BZ_DATA_ERROR_MAGIC as _) => panic!("BZ_DATA_ERROR"),
+ r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
+ r if r == (BZ_OK as _) => panic!("BZ_OK"),
+ r if r == (BZ_STREAM_END as _) => {},
+ r => panic!("Unknown return value = {}", r),
+ }
+
+ // Close the decompression stream.
+ let result = BZ2_bzDecompressEnd(&mut stream as *mut _);
+ match result {
+ r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
+ r if r == (BZ_OK as _) => {},
+ r => panic!("Unknown return value = {}", r),
+ }
+
+ assert_eq!(input, &decompressed_output[..]);
+ }
+ }
+}
+```
+
+Now let's run `cargo test` again and verify that everying is linking and binding
+properly!
+
+```bash
+$ cargo test
+ Compiling libbindgen-tutorial-bzip2-sys v0.1.0
+ Finished debug [unoptimized + debuginfo] target(s) in 0.54 secs
+ Running target/debug/deps/libbindgen_tutorial_bzip2_sys-1c5626bbc4401c3a
+
+running 15 tests
+test bindgen_test_layout___darwin_pthread_handler_rec ... ok
+test bindgen_test_layout___sFILE ... ok
+test bindgen_test_layout___sbuf ... ok
+test bindgen_test_layout__bindgen_ty_1 ... ok
+test bindgen_test_layout__bindgen_ty_2 ... ok
+test bindgen_test_layout__opaque_pthread_attr_t ... ok
+test bindgen_test_layout__opaque_pthread_cond_t ... ok
+test bindgen_test_layout__opaque_pthread_condattr_t ... ok
+test bindgen_test_layout__opaque_pthread_mutex_t ... ok
+test bindgen_test_layout__opaque_pthread_mutexattr_t ... ok
+test bindgen_test_layout__opaque_pthread_once_t ... ok
+test bindgen_test_layout__opaque_pthread_rwlock_t ... ok
+test bindgen_test_layout__opaque_pthread_rwlockattr_t ... ok
+test bindgen_test_layout__opaque_pthread_t ... ok
+ block 1: crc = 0x47bfca17, combined CRC = 0x47bfca17, size = 2857
+ bucket sorting ...
+ depth 1 has 2849 unresolved strings
+ depth 2 has 2702 unresolved strings
+ depth 4 has 1508 unresolved strings
+ depth 8 has 538 unresolved strings
+ depth 16 has 148 unresolved strings
+ depth 32 has 0 unresolved strings
+ reconstructing block ...
+ 2857 in block, 2221 after MTF & 1-2 coding, 61+2 syms in use
+ initial group 5, [0 .. 1], has 570 syms (25.7%)
+ initial group 4, [2 .. 2], has 256 syms (11.5%)
+ initial group 3, [3 .. 6], has 554 syms (24.9%)
+ initial group 2, [7 .. 12], has 372 syms (16.7%)
+ initial group 1, [13 .. 62], has 469 syms (21.1%)
+ pass 1: size is 2743, grp uses are 13 6 15 0 11
+ pass 2: size is 1216, grp uses are 13 7 15 0 10
+ pass 3: size is 1214, grp uses are 13 8 14 0 10
+ pass 4: size is 1213, grp uses are 13 9 13 0 10
+ bytes: mapping 19, selectors 17, code lengths 79, codes 1213
+ final combined CRC = 0x47bfca17
+
+ [1: huff+mtf rt+rld {0x47bfca17, 0x47bfca17}]
+ combined CRCs: stored = 0x47bfca17, computed = 0x47bfca17
+test tests::round_trip_compression_decompression ... ok
+
+test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured
+
+ Doc-tests libbindgen-tutorial-bzip2-sys
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+```
diff --git a/book/src/tutorial-6.md b/book/src/tutorial-6.md
new file mode 100644
index 00000000..366be421
--- /dev/null
+++ b/book/src/tutorial-6.md
@@ -0,0 +1,13 @@
+# Publish Your Crate!
+
+That's it! Now we can publish our crate on crates.io and we can write a nice,
+Rust-y API wrapping the raw FFI bindings in a safe interface. However, there is
+already a [`bzip2-sys`][bz-sys] crate providing raw FFI bindings, and there is
+already a [`bzip2`][bz] crate providing a nice, safe, Rust-y API on top of the
+bindings, so we have nothing left to do here!
+
+Check out the [full code on Github!][example]
+
+[bz-sys]: https://crates.io/crates/bzip2-sys
+[bz]: https://crates.io/crates/bzip2
+[example]: https://github.com/fitzgen/libbindgen-tutorial-bzip2-sys
diff --git a/book/src/whitelisting.md b/book/src/whitelisting.md
new file mode 100644
index 00000000..1b3eeaf6
--- /dev/null
+++ b/book/src/whitelisting.md
@@ -0,0 +1,31 @@
+# Whitelisting
+
+Whitelisting allows us to be precise about which type, function, and global
+variable definitions `bindgen` generates bindings for. By default, if we don't
+specify any whitelisting rules, everything is considered whitelisted. This may
+not be desirable because of either
+
+* the generated bindings contain a lot of extra defintions we don't plan on using, or
+* the header file contains C++ features for which Rust does not have a
+ corresponding form (such as partial template specialization), and we would
+ like to avoid these definitions
+
+If we specify whitelisting rules, then `bindgen` will only generate bindings to
+types, functions, and global variables that match the whitelisting rules, or are
+transitively used by a definition that matches them.
+
+### Library
+
+* [`bindgen::Builder::whitelisted_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_type)
+* [`bindgen::Builder::whitelisted_function`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_function)
+* [`bindgen::Builder::whitelisted_var`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_function)
+
+### Command Line
+
+* `--whitelist-type <type>`
+* `--whitelist-function <function>`
+* `--whitelist-var <var>`
+
+### Annotations
+
+None.
diff --git a/ci/deploy-book.sh b/ci/deploy-book.sh
new file mode 100755
index 00000000..0c2a2b5f
--- /dev/null
+++ b/ci/deploy-book.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+set -xeu
+cd "$(dirname "$0")/../book"
+
+# Ensure mdbook is installed.
+cargo install mdbook || true
+export PATH="$PATH:~/.cargo/bin"
+
+# Get the git revision we are on.
+rev=$(git rev-parse --short HEAD)
+
+# Build the users guide book and go into the built book's directory.
+rm -rf ./book
+mdbook build
+cd ./book
+
+# Make the built book directory a new git repo, fetch upstream, make a new
+# commit on gh-pages, and push it upstream.
+
+git init
+git config user.name "Travis CI"
+git config user.email "builds@travis-ci.org"
+
+git remote add upstream "https://$GH_TOKEN@github.com/servo/rust-bindgen.git"
+git fetch upstream
+git reset upstream/gh-pages
+
+touch .
+
+git add -A .
+git commit -m "Rebuild users guide at ${rev}"
+git push upstream HEAD:gh-pages
diff --git a/ci/test-book.sh b/ci/test-book.sh
new file mode 100755
index 00000000..30b23318
--- /dev/null
+++ b/ci/test-book.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -xeu
+cd "$(dirname "$0")/../book"
+
+cargo install mdbook || true
+export PATH="$PATH:~/.cargo/bin"
+
+mdbook build
+mdbook test