@@ -192,7 +192,8 @@ impl NginxSource {
192
192
/// Generates Rust bindings for NGINX
193
193
fn generate_binding ( nginx : & NginxSource ) {
194
194
let autoconf_makefile_path = nginx. build_dir . join ( "Makefile" ) ;
195
- let includes: Vec < _ > = parse_includes_from_makefile ( & autoconf_makefile_path)
195
+ let ( includes, defines) = parse_makefile ( & autoconf_makefile_path) ;
196
+ let includes: Vec < _ > = includes
196
197
. into_iter ( )
197
198
. map ( |path| {
198
199
if path. is_absolute ( ) {
@@ -202,12 +203,25 @@ fn generate_binding(nginx: &NginxSource) {
202
203
}
203
204
} )
204
205
. collect ( ) ;
205
- let clang_args: Vec < String > = includes
206
+ let mut clang_args: Vec < String > = includes
206
207
. iter ( )
207
208
. map ( |path| format ! ( "-I{}" , path. to_string_lossy( ) ) )
208
209
. collect ( ) ;
209
210
210
- print_cargo_metadata ( nginx, & includes) . expect ( "cargo dependency metadata" ) ;
211
+ clang_args. append (
212
+ & mut defines
213
+ . iter ( )
214
+ . map ( |( n, ov) | {
215
+ if let Some ( v) = ov {
216
+ format ! ( "-D{n}={v}" )
217
+ } else {
218
+ format ! ( "-D{n}" )
219
+ }
220
+ } )
221
+ . collect ( ) ,
222
+ ) ;
223
+
224
+ print_cargo_metadata ( nginx, & includes, & defines) . expect ( "cargo dependency metadata" ) ;
211
225
212
226
// bindgen targets the latest known stable by default
213
227
let rust_target: bindgen:: RustTarget = env:: var ( "CARGO_PKG_RUST_VERSION" )
@@ -241,22 +255,47 @@ fn generate_binding(nginx: &NginxSource) {
241
255
}
242
256
243
257
/// Reads through the makefile generated by autoconf and finds all of the includes
244
- /// used to compile nginx. This is used to generate the correct bindings for the
245
- /// nginx source code.
246
- fn parse_includes_from_makefile ( nginx_autoconf_makefile_path : & PathBuf ) -> Vec < PathBuf > {
247
- fn extract_include_part ( line : & str ) -> & str {
248
- line. strip_suffix ( '\\' ) . map_or ( line, |s| s. trim ( ) )
249
- }
250
- /// Extracts the include path from a line of the autoconf generated makefile.
251
- fn extract_after_i_flag ( line : & str ) -> Option < & str > {
252
- let mut parts = line. split ( "-I " ) ;
253
- match parts. next ( ) {
254
- Some ( _) => parts. next ( ) . map ( extract_include_part) ,
255
- None => None ,
258
+ /// and definitions used to compile nginx. This is used to generate the correct bindings
259
+ /// for the nginx source code.
260
+ pub fn parse_makefile (
261
+ nginx_autoconf_makefile_path : & PathBuf ,
262
+ ) -> ( Vec < PathBuf > , Vec < ( String , Option < String > ) > ) {
263
+ fn parse_line (
264
+ includes : & mut Vec < String > ,
265
+ defines : & mut Vec < ( String , Option < String > ) > ,
266
+ line : & str ,
267
+ ) {
268
+ let mut words = shlex:: Shlex :: new ( line) ;
269
+
270
+ while let Some ( word) = words. next ( ) {
271
+ if let Some ( inc) = word. strip_prefix ( "-I" ) {
272
+ let value = if inc. is_empty ( ) {
273
+ words. next ( ) . expect ( "-I argument" )
274
+ } else {
275
+ inc. to_string ( )
276
+ } ;
277
+ includes. push ( value) ;
278
+ } else if let Some ( def) = word. strip_prefix ( "-D" ) {
279
+ let def = if def. is_empty ( ) {
280
+ words. next ( ) . expect ( "-D argument" )
281
+ } else {
282
+ def. to_string ( )
283
+ } ;
284
+
285
+ if let Some ( ( name, value) ) = def. split_once ( "=" ) {
286
+ defines. push ( ( name. to_string ( ) , Some ( value. to_string ( ) ) ) ) ;
287
+ } else {
288
+ defines. push ( ( def. to_string ( ) , None ) ) ;
289
+ }
290
+ }
256
291
}
257
292
}
258
293
259
294
let mut includes = vec ! [ ] ;
295
+ let mut cflags_includes = vec ! [ ] ;
296
+
297
+ let mut defines = vec ! [ ] ;
298
+
260
299
let makefile_contents = match read_to_string ( nginx_autoconf_makefile_path) {
261
300
Ok ( path) => path,
262
301
Err ( e) => {
@@ -268,35 +307,36 @@ fn parse_includes_from_makefile(nginx_autoconf_makefile_path: &PathBuf) -> Vec<P
268
307
}
269
308
} ;
270
309
271
- let mut includes_lines = false ;
272
- for line in makefile_contents. lines ( ) {
273
- if !includes_lines {
274
- if let Some ( stripped) = line. strip_prefix ( "ALL_INCS" ) {
275
- includes_lines = true ;
276
- if let Some ( part) = extract_after_i_flag ( stripped) {
277
- includes. push ( part) ;
278
- }
279
- continue ;
280
- }
310
+ let lines = makefile_contents. lines ( ) ;
311
+ let mut line: String = "" . to_string ( ) ;
312
+ for l in lines {
313
+ if let Some ( part) = l. strip_suffix ( "\\ " ) {
314
+ line += part;
315
+ continue ;
281
316
}
282
317
283
- if includes_lines {
284
- if let Some ( part ) = extract_after_i_flag ( line ) {
285
- includes . push ( part ) ;
286
- } else {
287
- break ;
288
- }
318
+ line += l ;
319
+
320
+ if let Some ( tail ) = line . strip_prefix ( "ALL_INCS" ) {
321
+ parse_line ( & mut includes , & mut defines , tail ) ;
322
+ } else if let Some ( tail ) = line . strip_prefix ( "CFLAGS" ) {
323
+ parse_line ( & mut cflags_includes , & mut defines , tail ) ;
289
324
}
325
+
326
+ line. clear ( ) ;
290
327
}
291
328
292
- includes. into_iter ( ) . map ( PathBuf :: from) . collect ( )
329
+ includes. append ( & mut cflags_includes) ;
330
+
331
+ ( includes. into_iter ( ) . map ( PathBuf :: from) . collect ( ) , defines)
293
332
}
294
333
295
334
/// Collect info about the nginx configuration and expose it to the dependents via
296
335
/// `DEP_NGINX_...` variables.
297
336
pub fn print_cargo_metadata < T : AsRef < Path > > (
298
337
nginx : & NginxSource ,
299
338
includes : & [ T ] ,
339
+ defines : & [ ( String , Option < String > ) ] ,
300
340
) -> Result < ( ) , Box < dyn StdError > > {
301
341
// Unquote and merge C string constants
302
342
let unquote_re = regex:: Regex :: new ( r#""(.*?[^\\])"\s*"# ) . unwrap ( ) ;
@@ -311,7 +351,7 @@ pub fn print_cargo_metadata<T: AsRef<Path>>(
311
351
let mut ngx_features: Vec < String > = vec ! [ ] ;
312
352
let mut ngx_os = String :: new ( ) ;
313
353
314
- let expanded = expand_definitions ( includes) ?;
354
+ let expanded = expand_definitions ( includes, defines ) ?;
315
355
for line in String :: from_utf8 ( expanded) ?. lines ( ) {
316
356
let Some ( ( name, value) ) = line
317
357
. trim ( )
@@ -350,6 +390,19 @@ pub fn print_cargo_metadata<T: AsRef<Path>>(
350
390
. expect( "Unicode include paths" )
351
391
) ;
352
392
393
+ println ! (
394
+ "cargo:metadata=cflags={}" ,
395
+ defines
396
+ . iter( )
397
+ . map( |( n, ov) | if let Some ( v) = ov {
398
+ format!( "-D{n}={v}" )
399
+ } else {
400
+ format!( "-D{n}" )
401
+ } )
402
+ . collect:: <Vec <_>>( )
403
+ . join( " " )
404
+ ) ;
405
+
353
406
// A quoted list of all recognized features to be passed to rustc-check-cfg.
354
407
let values = NGX_CONF_FEATURES . join ( "\" ,\" " ) ;
355
408
println ! ( "cargo::metadata=features_check=\" {values}\" " ) ;
@@ -372,7 +425,10 @@ pub fn print_cargo_metadata<T: AsRef<Path>>(
372
425
Ok ( ( ) )
373
426
}
374
427
375
- fn expand_definitions < T : AsRef < Path > > ( includes : & [ T ] ) -> Result < Vec < u8 > , Box < dyn StdError > > {
428
+ fn expand_definitions < T : AsRef < Path > > (
429
+ includes : & [ T ] ,
430
+ defines : & [ ( String , Option < String > ) ] ,
431
+ ) -> Result < Vec < u8 > , Box < dyn StdError > > {
376
432
let path = PathBuf :: from ( env:: var ( "OUT_DIR" ) ?) . join ( "expand.c" ) ;
377
433
let mut writer = std:: io:: BufWriter :: new ( File :: create ( & path) ?) ;
378
434
@@ -418,8 +474,13 @@ RUST_CONF_{flag}=NGX_{flag}
418
474
writer. flush ( ) ?;
419
475
drop ( writer) ;
420
476
421
- Ok ( cc:: Build :: new ( )
422
- . includes ( includes)
423
- . file ( path)
424
- . try_expand ( ) ?)
477
+ let mut builder = cc:: Build :: new ( ) ;
478
+
479
+ builder. includes ( includes) . file ( path) ;
480
+
481
+ for def in defines {
482
+ builder. define ( & def. 0 , def. 1 . as_deref ( ) ) ;
483
+ }
484
+
485
+ Ok ( builder. try_expand ( ) ?)
425
486
}
0 commit comments