@@ -4,7 +4,7 @@ extern crate cc;
4
4
use bindgen:: callbacks:: {
5
5
DeriveInfo , IntKind , MacroParsingBehavior , ParseCallbacks ,
6
6
} ;
7
- use bindgen:: { Builder , EnumVariation } ;
7
+ use bindgen:: { Builder , CargoCallbacks , EnumVariation } ;
8
8
use std:: collections:: HashSet ;
9
9
use std:: env;
10
10
use std:: path:: PathBuf ;
@@ -207,40 +207,59 @@ fn setup_macro_test() {
207
207
208
208
fn setup_extern_test ( ) {
209
209
// GH-1090: https://github.com/rust-lang/rust-bindgen/issues/1090
210
- cc:: Build :: new ( )
211
- . cpp ( true )
212
- . file ( "cpp/extern.c" )
213
- . include ( "include" )
214
- . compile ( "libextern.a" ) ;
210
+ // set output directory under /target so it is easy to clean generated files
215
211
let out_path = PathBuf :: from ( env:: var ( "OUT_DIR" ) . unwrap ( ) ) ;
216
212
let out_rust_file = out_path. join ( "extern.rs" ) ;
217
- let out_rust_file_relative = out_rust_file
218
- . strip_prefix ( std:: env:: current_dir ( ) . unwrap ( ) . parent ( ) . unwrap ( ) )
219
- . unwrap ( ) ;
220
- let out_dep_file = out_path. join ( "extern.d" ) ;
221
213
222
- let bindings = Builder :: default ( )
223
- . rustfmt_bindings ( false )
224
- . header ( "cpp/extern.h" )
225
- . clang_args ( & [ "-x" , "c++" , "-I" , "include" ] )
226
- . depfile ( out_rust_file_relative. display ( ) . to_string ( ) , & out_dep_file)
214
+ let input_header_dir = PathBuf :: from ( "include/" ) . canonicalize ( )
215
+ . expect ( "Cannot canonicalize libdir path" ) ;
216
+ let input_header_file_path = input_header_dir. join ( "extern_stub.h" ) ;
217
+ let input_header_file_path_str = input_header_file_path. to_str ( )
218
+ . expect ( "Path could not be converted to a str" ) ;
219
+
220
+ // generate external bindings with the external .c and .h files
221
+ let bindings = bindgen:: Builder :: default ( )
222
+ . header ( input_header_file_path_str)
223
+ . parse_callbacks ( Box :: new ( CargoCallbacks ) )
227
224
. generate_extern_functions ( true )
225
+ . extern_functions_directory ( out_path. display ( ) . to_string ( ) )
228
226
. generate ( )
229
- . expect ( "Unable to generate extern bindings" ) ;
227
+ . expect ( "Unable to generate bindings" ) ;
230
228
231
- bindings
232
- . write_to_file ( & out_rust_file)
233
- . expect ( "Couldn't write bindings!" ) ;
234
- let observed_deps =
235
- std:: fs:: read_to_string ( out_dep_file) . expect ( "Couldn't read depfile!" ) ;
236
- let expected_deps = format ! (
237
- "{}: /tmp/bindgen/extern.hpp cpp/extern.h include/extern_stub.h" ,
238
- out_rust_file_relative. display( )
239
- ) ;
240
- assert_eq ! (
241
- observed_deps, expected_deps,
242
- "including stub via include dir must produce correct dep path" ,
243
- ) ;
229
+ println ! ( "cargo:rustc-link-lib=extern" ) ; // tell cargo to link libextern
230
+ println ! ( "bindings generated: {}" , bindings) ;
231
+
232
+ let obj_path = out_path. join ( "extern.o" ) ;
233
+ let lib_path = out_path. join ( "libextern.a" ) ;
234
+
235
+ // build the external files to check if they work
236
+ if !std:: process:: Command :: new ( "clang" )
237
+ . arg ( "-c" )
238
+ . arg ( "-o" )
239
+ . arg ( & obj_path)
240
+ . arg ( out_path. join ( "extern.c" ) )
241
+ . arg ( "-include" )
242
+ . arg ( input_header_file_path)
243
+ . output ( )
244
+ . expect ( "`clang` command error" )
245
+ . status
246
+ . success ( ) {
247
+ panic ! ( "Could not compile object file" ) ;
248
+ }
249
+
250
+ if !std:: process:: Command :: new ( "ar" )
251
+ . arg ( "rcs" )
252
+ . arg ( lib_path)
253
+ . arg ( obj_path)
254
+ . output ( )
255
+ . expect ( "`ar` command error" )
256
+ . status
257
+ . success ( ) {
258
+ panic ! ( "Could not emit library file" ) ;
259
+ }
260
+
261
+ bindings. write_to_file ( out_rust_file)
262
+ . expect ( "Cound not write bindings to the Rust file" ) ;
244
263
}
245
264
246
265
fn main ( ) {
0 commit comments