extern crate bindgen;
#[macro_use]
extern crate log;
extern crate docopt;
#[macro_use]
extern crate rustc_serialize;
extern crate env_logger;
use bindgen::{Builder, LinkType};
use std::io::{self, Write};
use std::fs::File;
use std::process::exit;
const USAGE: &'static str = "
Generate C bindings for Rust.
Usage:
bindgen [options] <file> [-- <clang-args>...]
bindgen [options] (--match=<name> ...) <file> [-- <clang-args>...]
bindgen (-h | --help)
Options:
<clang-args> Options passed directly to clang.
-h, --help Display this help message.
--link=<library> Link to a dynamic library, can be provided multiple times.
<library> is in the format `[kind=]lib`, where `kind` is
one of `static`, `dynamic` or `framework`.
--output=<output> Write bindings to <output> (- is stdout).
[default: -]
--match=<name> Only output bindings for definitions from files
whose name contains <name>
If multiple -match options are provided, files
matching any rule are bound to.
--builtins Output bindings for builtin definitions
(for example __builtin_va_list)
--emit-clang-ast Output the ast (for debugging purposes)
--override-enum-type=<type> Override enum type, type name could be
uchar
schar
ushort
sshort
uint
sint
ulong
slong
ulonglong
slonglong
--use-core Use `core` as a base crate for `Option` and such.
See also `--ctypes-prefix`.
--ctypes-prefix=<prefix> Use this prefix for all the types in the generated
code.
[default: std::os::raw]
--remove-prefix=<prefix> Prefix to remove from all the symbols, like
`libfoo_`. The removal is case-insensitive.
--no-derive-debug Disable `derive(Debug)` for all generated types.
--no-rust-enums Convert C enums to Rust constants instead of enums.
--dont-convert-floats Disables the convertion of C `float` and `double`
to Rust `f32` and `f64`.
--convert-macros Try to convert macros into const definitions
--macro-int-types=<ty,...> When converting macros, convert integers that
would fit in a u8,u16,u32,u64,i8,i16,i32,i64 to
the corresponding named C type, respectively. See
`--override-enum-type` for the type names.
";
#[derive(Debug, RustcDecodable)]
struct Args {
arg_file: String,
arg_clang_args: Vec<String>,
flag_link: Option<String>,
flag_output: String,
flag_match: Vec<String>,
flag_builtins: bool,
flag_emit_clang_ast: bool,
flag_override_enum_type: String,
flag_ctypes_prefix: String,
flag_use_core: bool,
flag_remove_prefix: Option<String>,
flag_no_derive_debug: bool,
flag_no_rust_enums: bool,
flag_dont_convert_floats: bool,
flag_convert_macros: bool,
flag_macro_int_types: Option<String>,
}
fn args_to_opts(args: Args) -> Builder<'static> {
let mut builder = Builder::new(args.arg_file);
builder.emit_ast(args.flag_emit_clang_ast)
.ctypes_prefix(args.flag_ctypes_prefix
.split("::")
.map(String::from)
.collect::<Vec<_>>())
.use_core(args.flag_use_core)
.derive_debug(!args.flag_no_derive_debug)
.rust_enums(!args.flag_no_rust_enums)
.override_enum_ty(args.flag_override_enum_type)
.convert_macros(args.flag_convert_macros);
for arg in args.arg_clang_args {
builder.clang_arg(arg);
}
for flag_match in args.flag_match {
builder.match_pat(flag_match);
}
if let Some(s) = args.flag_remove_prefix {
builder.remove_prefix(s);
}
if let Some(s) = args.flag_macro_int_types {
builder.macro_int_types(s.split(","));
}
if args.flag_builtins {
builder.builtins();
}
if args.flag_dont_convert_floats {
builder.dont_convert_floats();
}
if let Some(link) = args.flag_link {
let mut parts = link.split('=');
let (lib, kind) = match (parts.next(), parts.next()) {
(Some(lib), None) => (lib, LinkType::Dynamic),
(Some(kind), Some(lib)) => {
(lib,
match kind {
"static" => LinkType::Static,
"dynamic" => LinkType::Dynamic,
"framework" => LinkType::Framework,
_ => {
println!("Link type unknown: {}", kind);
exit(1);
}
})
}
_ => {
println!("Wrong link format: {}", link);
exit(1);
}
};
builder.link(lib, kind);
}
builder
}
fn get_output(o: &str) -> Box<Write> {
if o == "-" {
Box::new(io::stdout())
} else {
Box::new(File::create(o).expect(&format!("\"{}\" unwritable", o)))
}
}
pub fn main() {
env_logger::LogBuilder::new().parse("bindgen=warn").init().unwrap();
let args: Args = docopt::Docopt::new(USAGE)
.and_then(|d| d.decode())
.unwrap_or_else(|e| e.exit());
debug!("{:?}", args);
let output = get_output(&args.flag_output);
let builder = args_to_opts(args);
debug!("{:?}", builder);
match builder.generate() {
Ok(bindings) => {
match bindings.write(output) {
Ok(()) => (),
Err(e) => {
error!("Unable to write bindings to file. {}", e);
exit(-1);
}
}
}
Err(()) => exit(-1),
}
}