1
1
extern crate bindgen;
2
2
#[ macro_use] extern crate log;
3
+ extern crate docopt;
4
+ #[ macro_use]
5
+ extern crate rustc_serialize;
3
6
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 ;
10
10
use std:: process:: exit;
11
11
12
+ #[ derive( Debug ) ]
12
13
struct StdLogger ;
13
14
14
15
impl Logger for StdLogger {
@@ -21,161 +22,114 @@ impl Logger for StdLogger {
21
22
}
22
23
}
23
24
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.
29
27
30
- fn parse_args ( args : & [ String ] ) -> ParseResult {
31
- let args_len = args. len ( ) ;
28
+ Usage:
29
+ bindgen [options] <file>
30
+ bindgen (-h | --help)
32
31
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
+ " ;
36
59
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
+ }
40
71
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) ;
119
79
}
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) ;
122
101
}
123
102
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
+ }
158
109
}
159
110
160
111
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) ;
163
124
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 ) ;
178
131
}
179
- }
132
+ } ,
133
+ Err ( ( ) ) => exit ( -1 )
180
134
}
181
135
}
0 commit comments