Add the bindgen Users Guide

This commit adds a Users Guide, built with [mdbook][] (the same tool used
by *The Rust Book*).

It moves all the user documentation from the README.md into the Users Guide. It
leaves the README.md as a splash page featuring an example of what `bindgen` is
and does, a link to the Users Guide, a link to the docs.rs/bindgen API reference
documentation, and a link to CONTRIBUTING.md.

It ensures that the Users Guide builds with `mdbook`, and all code snippets
within it build as doctests and pass, on every CI run.

Finally, it builds and uploads the Users Guide every time CI passes on the
master branch.

[mdbook]: https://github.com/azerupi/mdBook
This commit is contained in:
Nick Fitzgerald
2017-04-26 17:39:10 -04:00
parent 5f6791dd96
commit abab29ea7f
26 changed files with 775 additions and 208 deletions
+8
View File
@@ -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
+26 -208
View File
@@ -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
void cool_function(int i, char c, CoolStruct* cs);
```
If you use MacPorts:
```
$ port install clang-3.9
```
##### Debian-based Linuxes
```
# 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;
#[repr(C)]
pub struct CoolStruct {
pub x: ::std::os::raw::c_int,
pub y: ::std::os::raw::c_int,
}
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"));
extern "C" {
pub fn cool_function(i: ::std::os::raw::c_int,
c: ::std::os::raw::c_char,
cs: *mut CoolStruct);
}
```
In `src/main.rs`:
## Users Guide
```rust
include!(concat!(env!("OUT_DIR"), "/example.rs"));
```
[📚 Read the `bindgen` users guide here! 📚](https://servo.github.io/rust-bindgen)
### Command Line Usage
## API Reference
```
$ cargo install bindgen
```
[API reference documentation is on docs.rs](https://docs.rs/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`.
## Contributing
### 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>
```
#### `replaces`
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`.
#### `nocopy`
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)
+1
View File
@@ -0,0 +1 @@
book
+3
View File
@@ -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."
+20
View File
@@ -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)
+26
View File
@@ -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 {
// ...
};
```
+1
View File
@@ -0,0 +1 @@
# Chapter 1
+27
View File
@@ -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
```
+27
View File
@@ -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.
@@ -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.
+34
View File
@@ -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);
}
```
+22
View File
@@ -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`.
+20
View File
@@ -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;
// ...
};
```
+26
View File
@@ -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 {
// ...
};
```
+27
View File
@@ -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).
+67
View File
@@ -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
+12
View File
@@ -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
+9
View File
@@ -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"
```
+20
View File
@@ -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
+58
View File
@@ -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
+57
View File
@@ -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
```
+169
View File
@@ -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
```
+13
View File
@@ -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
+31
View File
@@ -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.
+33
View File
@@ -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
+10
View File
@@ -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