Skip to content

Commit b6f9f95

Browse files
committed
[main] Use docopt for arguments parsing.
1 parent 6f26197 commit b6f9f95

File tree

4 files changed

+113
-154
lines changed

4 files changed

+113
-154
lines changed

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ keywords = [ "bindings", "ffi", "code-generation" ]
1212
[dependencies]
1313
clang-sys = "~0.6.0"
1414
clippy = { version = "0.0.69", optional = true }
15+
docopt = "~0.6.80"
1516
log = "~0.3.6"
1617
libc = "~0.2.11"
18+
rustc-serialize = "~0.3.19"
1719
syntex_syntax = "~0.32.0"
1820

1921
[features]

Changelog.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
44
This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased]
7+
### Breaking
8+
- New command line interface.
79

810
## [0.17.0] - 2016-05-27
911
### Breaking

src/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod clang;
3030
mod gen;
3131
mod parser;
3232

33-
#[derive(Clone)]
33+
#[derive(Debug, Clone)]
3434
pub struct Builder<'a> {
3535
options: BindgenOptions,
3636
logger: Option<&'a Logger>
@@ -118,7 +118,7 @@ impl<'a> Default for Builder<'a> {
118118
}
119119
}
120120

121-
#[derive(Clone)]
121+
#[derive(Debug, Clone)]
122122
/// Deprecated - use a `Builder` instead
123123
#[doc(hidden)]
124124
pub struct BindgenOptions {
@@ -155,14 +155,14 @@ impl Default for BindgenOptions {
155155
}
156156
}
157157

158-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
158+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
159159
pub enum LinkType {
160160
Static,
161161
Dynamic,
162162
Framework
163163
}
164164

165-
pub trait Logger {
165+
pub trait Logger: std::fmt::Debug {
166166
fn error(&self, msg: &str);
167167
fn warn(&self, msg: &str);
168168
}
@@ -233,6 +233,7 @@ impl Bindings {
233233
}
234234

235235

236+
#[derive(Debug)]
236237
struct DummyLogger;
237238

238239
impl Logger for DummyLogger {

src/main.rs

+104-150
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
extern crate bindgen;
22
#[macro_use] extern crate log;
3+
extern crate docopt;
4+
#[macro_use]
5+
extern crate rustc_serialize;
36

4-
use bindgen::{Bindings, BindgenOptions, LinkType, Logger};
5-
use std::io;
6-
use std::path;
7-
use std::env;
8-
use std::default::Default;
9-
use std::fs;
7+
use bindgen::{Builder, LinkType, Logger};
8+
use std::io::{self, Write};
9+
use std::fs::File;
1010
use std::process::exit;
1111

12+
#[derive(Debug)]
1213
struct StdLogger;
1314

1415
impl Logger for StdLogger {
@@ -21,161 +22,114 @@ impl Logger for StdLogger {
2122
}
2223
}
2324

24-
enum ParseResult {
25-
CmdUsage,
26-
ParseOk(BindgenOptions, Box<io::Write+'static>),
27-
ParseErr(String)
28-
}
25+
const USAGE: &'static str = "
26+
Generate C bindings for Rust.
2927
30-
fn parse_args(args: &[String]) -> ParseResult {
31-
let args_len = args.len();
28+
Usage:
29+
bindgen [options] <file>
30+
bindgen (-h | --help)
3231
33-
let mut options: BindgenOptions = Default::default();
34-
options.derive_debug = false;
35-
let mut out = Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>;
32+
Options:
33+
-h, --help Display this help message.
34+
--link=<library> Link to a dynamic library, can be provided multiple times.
35+
<library> is in the format `[kind=]lib`, where `kind` is
36+
one of `static`, `dynamic` or `framework`.
37+
--output=<output> Write bindings to <output> (- is stdout).
38+
[default: -]
39+
--match=<name> Only output bindings for definitions from files
40+
whose name contains <name>
41+
If multiple -match options are provided, files
42+
matching any rule are bound to.
43+
--builtins Output bindings for builtin definitions
44+
(for example __builtin_va_list)
45+
--emit-clang-ast Output the ast (for debugging purposes)
46+
--override-enum-type=<type> Override enum type, type name could be
47+
uchar
48+
schar
49+
ushort
50+
sshort
51+
uint
52+
sint
53+
ulong
54+
slong
55+
ulonglong
56+
slonglong
57+
--clang-options=<opts> Options to clang.
58+
";
3659

37-
if args_len == 0 {
38-
return ParseResult::CmdUsage;
39-
}
60+
#[derive(Debug, RustcDecodable)]
61+
struct Args {
62+
arg_file: String,
63+
flag_link: String,
64+
flag_output: String,
65+
flag_match: Option<String>,
66+
flag_builtins: bool,
67+
flag_emit_clang_ast: bool,
68+
flag_override_enum_type: String,
69+
flag_clang_options: String,
70+
}
4071

41-
let mut ix: usize = 0;
42-
while ix < args_len {
43-
if args[ix].len() > 2 && &args[ix][..2] == "-l" {
44-
options.links.push((args[ix][2..].to_string(), LinkType::Dynamic));
45-
ix += 1;
46-
} else {
47-
match &args[ix][..] {
48-
"--help" | "-h" => {
49-
return ParseResult::CmdUsage;
50-
}
51-
"-emit-clang-ast" => {
52-
options.emit_ast = true;
53-
ix += 1;
54-
}
55-
"-o" => {
56-
if ix + 1 >= args_len {
57-
return ParseResult::ParseErr("Missing output filename".to_string());
58-
}
59-
let path = path::Path::new(&args[ix + 1]);
60-
match fs::File::create(&path) {
61-
Ok(f) => { out = Box::new(io::BufWriter::new(f)) as Box<io::Write>; }
62-
Err(_) => { return ParseResult::ParseErr(format!("Open {} failed", args[ix + 1])); }
63-
}
64-
ix += 2;
65-
}
66-
"-l" => {
67-
if ix + 1 >= args_len {
68-
return ParseResult::ParseErr("Missing link name".to_string());
69-
}
70-
let parts = args[ix + 1].split('=').collect::<Vec<_>>();
71-
options.links.push(match parts.len() {
72-
1 => (parts[0].to_string(), LinkType::Dynamic),
73-
2 => (parts[1].to_string(), match parts[0] {
74-
"static" => LinkType::Static,
75-
"dynamic" => LinkType::Dynamic,
76-
"framework" => LinkType::Framework,
77-
_ => return ParseResult::ParseErr("Invalid link kind".to_string()),
78-
}),
79-
_ => return ParseResult::ParseErr("Invalid link name".to_string()),
80-
});
81-
ix += 2;
82-
}
83-
"-match" => {
84-
if ix + 1 >= args_len {
85-
return ParseResult::ParseErr("Missing match pattern".to_string());
86-
}
87-
options.match_pat.push(args[ix + 1].clone());
88-
ix += 2;
89-
}
90-
"-builtins" => {
91-
options.builtins = true;
92-
ix += 1;
93-
}
94-
"-no-rust-enums" => {
95-
options.rust_enums = false;
96-
ix += 1;
97-
}
98-
"-derive-debug" => {
99-
options.derive_debug = true;
100-
ix += 1;
101-
}
102-
"-allow-unknown-types" => {
103-
options.fail_on_unknown_type = false;
104-
ix += 1;
105-
}
106-
"-override-enum-type" => {
107-
if ix + 1 >= args_len {
108-
return ParseResult::ParseErr("Missing enum type".to_string());
109-
}
110-
options.override_enum_ty = args[ix + 1].clone();
111-
ix += 2;
112-
}
113-
_ => {
114-
options.clang_args.push(args[ix].clone());
115-
ix += 1;
116-
}
117-
}
118-
}
72+
fn args_to_opts(args: Args, builder: &mut Builder) {
73+
builder.header(args.arg_file)
74+
.emit_ast(args.flag_emit_clang_ast)
75+
.override_enum_ty(args.flag_override_enum_type)
76+
.clang_arg(args.flag_clang_options);
77+
if let Some(s) = args.flag_match {
78+
builder.match_pat(s);
11979
}
120-
121-
return ParseResult::ParseOk(options, out);
80+
if args.flag_builtins {
81+
builder.builtins();
82+
}
83+
let mut parts = args.flag_link.split('=');
84+
let (lib, kind) = match (parts.next(),parts.next()) {
85+
(Some(lib), None) => (lib, LinkType::Dynamic),
86+
(Some(kind), Some(lib)) => (lib, match kind {
87+
"static" => LinkType::Static,
88+
"dynamic" => LinkType::Dynamic,
89+
"framework" => LinkType::Framework,
90+
_ => {
91+
println!("Link type unknown: {}", kind);
92+
exit(1);
93+
},
94+
}),
95+
_ => {
96+
println!("Wrong link format: {}", args.flag_link);
97+
exit(1);
98+
},
99+
};
100+
builder.link(lib, kind);
122101
}
123102

124-
fn print_usage(bin: String) {
125-
let mut s = format!("Usage: {} [OPTIONS] HEADERS...", &bin[..]);
126-
s.push_str(
127-
"
128-
129-
Options:
130-
-h, --help Display help message
131-
-l [KIND=]NAME Link to the specified library NAME. The optional KIND can be one of,
132-
static, dylib, or framework. If omitted, dylib is assumed.
133-
-o FILENAME Write generated bindings to FILENAME (default is stdout)
134-
-match NAME Only output bindings for definitions from files whose names contain
135-
NAME. Can be used multiples times to include files matching any of
136-
the names.
137-
-builtins Output bindings for builtin definitions (for example,
138-
`__builtin_va_list`)
139-
-allow-unknown-types Do not fail if unknown types are encountered; instead treat them as
140-
`void`
141-
-emit-clang-ast Output the AST (for debugging purposes)
142-
-override-enum-type TYPE Override the integer type for enums, where TYPE is one of:
143-
uchar
144-
schar
145-
ushort
146-
sshort
147-
uint
148-
sint
149-
ulong
150-
slong
151-
ulonglong
152-
slonglong
153-
154-
Options other than the above are passed to Clang.
155-
"
156-
);
157-
print!("{}", &s[..]);
103+
fn get_output(o: &str) -> Box<Write> {
104+
if o == "-" {
105+
Box::new(io::stdout())
106+
} else {
107+
Box::new(File::open(o).expect(&format!("\"{}\" unreadable", o)))
108+
}
158109
}
159110

160111
pub fn main() {
161-
let mut bind_args: Vec<_> = env::args().collect();
162-
let bin = bind_args.remove(0);
112+
let args: Args = docopt::Docopt::new(USAGE)
113+
.and_then(|d| d.decode())
114+
.unwrap_or_else(|e| e.exit());
115+
debug!("{:?}", args);
116+
117+
let output = get_output(&args.flag_output);
118+
119+
let logger = StdLogger;
120+
let mut builder = Builder::default();
121+
builder.log(&logger);
122+
args_to_opts(args, &mut builder);
123+
debug!("{:?}", builder);
163124

164-
match parse_args(&bind_args[..]) {
165-
ParseResult::ParseErr(e) => panic!(e),
166-
ParseResult::CmdUsage => print_usage(bin),
167-
ParseResult::ParseOk(options, out) => {
168-
let logger = StdLogger;
169-
match Bindings::generate(&options, Some(&logger as &Logger), None) {
170-
Ok(bindings) => match bindings.write(out) {
171-
Ok(()) => (),
172-
Err(e) => {
173-
logger.error(&format!("Unable to write bindings to file. {}", e)[..]);
174-
exit(-1);
175-
}
176-
},
177-
Err(()) => exit(-1)
125+
match builder.generate() {
126+
Ok(bindings) => match bindings.write(output) {
127+
Ok(()) => (),
128+
Err(e) => {
129+
logger.error(&format!("Unable to write bindings to file. {}", e)[..]);
130+
exit(-1);
178131
}
179-
}
132+
},
133+
Err(()) => exit(-1)
180134
}
181135
}

0 commit comments

Comments
 (0)