use std::io;
use std::path::Path;
extern crate clap;
#[macro_use]
extern crate log;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate syn;
extern crate toml;
use clap::{Arg, ArgMatches, App};
mod logging;
mod bindgen;
use bindgen::{Cargo, Config, Language, Library};
fn apply_config_overrides<'a>(config: &mut Config, matches: &ArgMatches<'a>) {
if let Some(lang) = matches.value_of("lang") {
config.language = match lang {
"C++"=> Language::Cxx,
"c++"=> Language::Cxx,
"C"=> Language::C,
"c"=> Language::C,
_ => {
error!("unknown language specified");
return;
}
};
}
if matches.is_present("d") {
config.parse.parse_deps = true;
}
}
fn load_library<'a>(input: &str, matches: &ArgMatches<'a>) -> Result<Library, String> {
let input = Path::new(input);
if !input.is_dir() {
let mut config = match matches.value_of("config") {
Some(c) => Config::from_file(c).unwrap(),
None => Config::from_root_or_default(input),
};
apply_config_overrides(&mut config, &matches);
return Library::load_src(input, &config);
}
let lib = Cargo::load(input,
matches.value_of("crate"),
true)?;
let mut config = match matches.value_of("config") {
Some(c) => Config::from_file(c).unwrap(),
None => {
let binding_crate_dir = lib.find_crate_dir(&lib.binding_crate_ref());
if let Some(binding_crate_dir) = binding_crate_dir {
Config::from_root_or_default(&binding_crate_dir)
} else {
Config::from_root_or_default(input)
}
}
};
apply_config_overrides(&mut config, &matches);
Library::load_crate(lib, &config)
}
fn main() {
let matches = App::new("cbindgen")
.version(bindgen::VERSION)
.about("Generate C bindings for a Rust library")
.arg(Arg::with_name("v")
.short("v")
.multiple(true)
.help("Enable verbose logging"))
.arg(Arg::with_name("config")
.short("c")
.long("config")
.value_name("PATH")
.help("Specify path to a `cbindgen.toml` config to use"))
.arg(Arg::with_name("lang")
.short("l")
.long("lang")
.value_name("LANGUAGE")
.help("Specify the language to output bindings in")
.possible_values(&["c++", "C++", "c", "C"]))
.arg(Arg::with_name("d")
.short("d")
.long("parse-dependencies")
.help("Whether to parse dependencies when generating bindings"))
.arg(Arg::with_name("INPUT")
.help("A crate directory or source file to generate bindings for")
.required(true)
.index(1))
.arg(Arg::with_name("crate")
.long("crate")
.value_name("CRATE_NAME")
.help("If generating bindings for a crate, the specific crate to generate bindings for")
.required(false))
.arg(Arg::with_name("out")
.short("o")
.long("output")
.value_name("PATH")
.help("The file to output the bindings to")
.required(false))
.get_matches();
match matches.occurrences_of("v") {
0 => logging::WarnLogger::init().unwrap(),
1 => logging::InfoLogger::init().unwrap(),
_ => logging::TraceLogger::init().unwrap(),
}
let input = matches.value_of("INPUT").unwrap();
let library = match load_library(input, &matches) {
Ok(library) => library,
Err(msg) => {
error!("{}", msg);
error!("couldn't generate bindings for {}", input);
return;
}
};
let built = match library.generate() {
Ok(x) => x,
Err(msg) => {
error!("{}", msg);
error!("couldn't generate bindings for {}", input);
return;
},
};
match matches.value_of("out") {
Some(file) => {
built.write_to_file(file);
}
_ => {
built.write(io::stdout());
}
}
}