@@ -46,12 +46,12 @@ pub fn generate(env: &Env, crate_name: &str) {
46
46
47
47
let layout_c = tests. join ( "layout.c" ) ;
48
48
save_to_file ( & layout_c, env. config . make_backup , |w| {
49
- generate_layout_c ( env, & layout_c, w)
49
+ generate_layout_c ( env, & layout_c, w, & ctypes )
50
50
} ) ;
51
51
52
52
let constant_c = tests. join ( "constant.c" ) ;
53
53
save_to_file ( & constant_c, env. config . make_backup , |w| {
54
- generate_constant_c ( env, & constant_c, w)
54
+ generate_constant_c ( env, & constant_c, w, & cconsts )
55
55
} ) ;
56
56
57
57
let abi_rs = tests. join ( "abi.rs" ) ;
@@ -202,58 +202,80 @@ fn generate_manual_h(env: &Env, path: &Path, w: &mut dyn Write) -> io::Result<()
202
202
}
203
203
204
204
#[ allow( clippy:: write_literal) ]
205
- fn generate_layout_c ( env : & Env , path : & Path , w : & mut dyn Write ) -> io:: Result < ( ) > {
205
+ fn generate_layout_c (
206
+ env : & Env ,
207
+ path : & Path ,
208
+ w : & mut dyn Write ,
209
+ ctypes : & [ CType ] ,
210
+ ) -> io:: Result < ( ) > {
206
211
info ! ( "Generating file {:?}" , path) ;
207
212
general:: start_comments ( w, & env. config ) ?;
208
213
writeln ! ( w) ?;
209
214
writeln ! ( w, "#include \" manual.h\" " ) ?;
210
215
writeln ! ( w, "#include <stdalign.h>" ) ?;
211
216
writeln ! ( w, "#include <stdio.h>" ) ?;
217
+ writeln ! ( w) ?;
218
+ writeln ! ( w, "{}" , r"int main() {" ) ?;
212
219
213
- writeln ! (
214
- w,
215
- "{}" ,
216
- r##"
217
- int main() {
218
- printf("%zu\n%zu", sizeof(ABI_TYPE_NAME), alignof(ABI_TYPE_NAME));
219
- return 0;
220
- }"##
221
- )
220
+ for ctype in ctypes {
221
+ writeln ! (
222
+ w,
223
+ " printf(\" %s;%zu;%zu\\ n\" , \" {ctype}\" , sizeof({ctype}), alignof({ctype}));" ,
224
+ ctype = ctype. name
225
+ ) ?;
226
+ }
227
+
228
+ writeln ! ( w, " return 0;" ) ?;
229
+ writeln ! ( w, "{}" , r"}" )
222
230
}
223
231
224
232
#[ allow( clippy:: write_literal) ]
225
- fn generate_constant_c ( env : & Env , path : & Path , w : & mut dyn Write ) -> io:: Result < ( ) > {
233
+ fn generate_constant_c (
234
+ env : & Env ,
235
+ path : & Path ,
236
+ w : & mut dyn Write ,
237
+ cconsts : & [ CConstant ] ,
238
+ ) -> io:: Result < ( ) > {
226
239
info ! ( "Generating file {:?}" , path) ;
227
240
general:: start_comments ( w, & env. config ) ?;
228
241
writeln ! ( w) ?;
229
242
writeln ! ( w, "#include \" manual.h\" " ) ?;
230
243
writeln ! ( w, "#include <stdio.h>" ) ?;
231
-
232
244
writeln ! (
233
245
w,
234
246
"{}" ,
235
247
r####"
236
- int main() {
237
- printf(_Generic((ABI_CONSTANT_NAME),
238
- char *: "###gir test###%s###gir test###\n",
239
- const char *: "###gir test###%s###gir test###\n",
240
- char: "###gir test###%c###gir test###\n",
241
- signed char: "###gir test###%hhd###gir test###\n",
242
- unsigned char: "###gir test###%hhu###gir test###\n",
243
- short int: "###gir test###%hd###gir test###\n",
244
- unsigned short int: "###gir test###%hu###gir test###\n",
245
- int: "###gir test###%d###gir test###\n",
246
- unsigned int: "###gir test###%u###gir test###\n",
247
- long: "###gir test###%ld###gir test###\n",
248
- unsigned long: "###gir test###%lu###gir test###\n",
249
- long long: "###gir test###%lld###gir test###\n",
250
- unsigned long long: "###gir test###%llu###gir test###\n",
251
- double: "###gir test###%f###gir test###\n",
252
- long double: "###gir test###%ld###gir test###\n"),
253
- ABI_CONSTANT_NAME);
254
- return 0;
255
- }"####
256
- )
248
+ #define PRINT_CONSTANT(CONSTANT_NAME) \
249
+ printf("%s;", #CONSTANT_NAME); \
250
+ printf(_Generic((CONSTANT_NAME), \
251
+ char *: "%s", \
252
+ const char *: "%s", \
253
+ char: "%c", \
254
+ signed char: "%hhd", \
255
+ unsigned char: "%hhu", \
256
+ short int: "%hd", \
257
+ unsigned short int: "%hu", \
258
+ int: "%d", \
259
+ unsigned int: "%u", \
260
+ long: "%ld", \
261
+ unsigned long: "%lu", \
262
+ long long: "%lld", \
263
+ unsigned long long: "%llu", \
264
+ double: "%f", \
265
+ long double: "%ld"), \
266
+ CONSTANT_NAME); \
267
+ printf("\n");
268
+ "####
269
+ ) ?;
270
+
271
+ writeln ! ( w, "{}" , r"int main() {" ) ?;
272
+
273
+ for cconst in cconsts {
274
+ writeln ! ( w, " PRINT_CONSTANT({name});" , name = cconst. name, ) ?;
275
+ }
276
+
277
+ writeln ! ( w, " return 0;" ) ?;
278
+ writeln ! ( w, "{}" , r"}" )
257
279
}
258
280
259
281
#[ allow( clippy:: write_literal) ]
@@ -303,23 +325,14 @@ impl Compiler {
303
325
Ok(Compiler { args })
304
326
}
305
327
306
- pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) {
307
- let arg = match val.into() {
308
- None => format!("-D{}", var),
309
- Some(val) => format!("-D{}={}", var, val),
310
- };
311
- self.args.push(arg);
312
- }
313
-
314
328
pub fn compile(&self, src: &Path, out: &Path) -> Result<(), Box<dyn Error>> {
315
329
let mut cmd = self.to_command();
316
330
cmd.arg(src);
317
331
cmd.arg("-o");
318
332
cmd.arg(out);
319
333
let status = cmd.spawn()?.wait()?;
320
334
if !status.success() {
321
- return Err(format!("compilation command {:?} failed, {}",
322
- &cmd, status).into());
335
+ return Err(format!("compilation command {:?} failed, {}", &cmd, status).into());
323
336
}
324
337
Ok(())
325
338
}
@@ -370,8 +383,6 @@ struct Results {
370
383
passed: usize,
371
384
/// Total number of failed tests (including those that failed to compile).
372
385
failed: usize,
373
- /// Number of tests that failed to compile.
374
- failed_to_compile: usize,
375
386
}
376
387
377
388
impl Results {
@@ -381,16 +392,8 @@ impl Results {
381
392
fn record_failed(&mut self) {
382
393
self.failed += 1;
383
394
}
384
- fn record_failed_to_compile(&mut self) {
385
- self.failed += 1;
386
- self.failed_to_compile += 1;
387
- }
388
395
fn summary(&self) -> String {
389
- format!(
390
- "{} passed; {} failed (compilation errors: {})",
391
- self.passed,
392
- self.failed,
393
- self.failed_to_compile)
396
+ format!("{} passed; {} failed", self.passed, self.failed)
394
397
}
395
398
fn expect_total_success(&self) {
396
399
if self.failed == 0 {
@@ -403,118 +406,110 @@ impl Results {
403
406
404
407
#[test]
405
408
fn cross_validate_constants_with_c() {
406
- let tmpdir = Builder::new().prefix("abi").tempdir().expect("temporary directory");
407
- let cc = Compiler::new().expect("configured compiler");
409
+ let mut c_constants: Vec<(String, String)> = Vec::new();
410
+
411
+ for l in get_c_output("constant").unwrap().lines() {
412
+ let mut words = l.trim().split(";");
413
+ let name = words.next().expect("Failed to parse name").to_owned();
414
+ let value = words
415
+ .next()
416
+ .and_then(|s| s.parse().ok())
417
+ .expect("Failed to parse value");
418
+ c_constants.push((name, value));
419
+ }
408
420
409
- assert_eq!("1",
410
- get_c_value(tmpdir.path(), &cc, "1").expect("C constant"),
411
- "failed to obtain correct constant value for 1");
412
-
413
- let mut results : Results = Default::default();
414
- for (i, &(name, rust_value)) in RUST_CONSTANTS.iter().enumerate() {
415
- match get_c_value(tmpdir.path(), &cc, name) {
416
- Err(e) => {
417
- results.record_failed_to_compile();
418
- eprintln!("{}", e);
419
- },
420
- Ok(ref c_value) => {
421
- if rust_value == c_value {
422
- results.record_passed();
423
- } else {
424
- results.record_failed();
425
- eprintln!("Constant value mismatch for {}\nRust: {:?}\nC: {:?}",
426
- name, rust_value, c_value);
427
- }
428
- }
429
- };
430
- if (i + 1) % 25 == 0 {
431
- println!("constants ... {}", results.summary());
421
+ let mut results = Results::default();
422
+
423
+ for ((rust_name, rust_value), (c_name, c_value)) in
424
+ RUST_CONSTANTS.iter().zip(c_constants.iter())
425
+ {
426
+ if rust_name != c_name {
427
+ results.record_failed();
428
+ eprintln!("Name mismatch:\nRust: {:?}\nC: {:?}", rust_name, c_name,);
429
+ continue;
432
430
}
431
+
432
+ if rust_value != c_value {
433
+ results.record_failed();
434
+ eprintln!(
435
+ "Constant value mismatch for {}\nRust: {:?}\nC: {:?}",
436
+ rust_name, rust_value, &c_value
437
+ );
438
+ continue;
439
+ }
440
+
441
+ results.record_passed();
433
442
}
443
+
434
444
results.expect_total_success();
435
445
}
436
446
437
447
#[test]
438
448
fn cross_validate_layout_with_c() {
439
- let tmpdir = Builder::new().prefix("abi").tempdir().expect("temporary directory");
440
- let cc = Compiler::new().expect("configured compiler");
449
+ let mut c_layouts = Vec::new();
450
+
451
+ for l in get_c_output("layout").unwrap().lines() {
452
+ let mut words = l.trim().split(";");
453
+ let name = words.next().expect("Failed to parse name").to_owned();
454
+ let size = words
455
+ .next()
456
+ .and_then(|s| s.parse().ok())
457
+ .expect("Failed to parse size");
458
+ let alignment = words
459
+ .next()
460
+ .and_then(|s| s.parse().ok())
461
+ .expect("Failed to parse alignment");
462
+ c_layouts.push((name, Layout { size, alignment }));
463
+ }
441
464
442
- assert_eq!(Layout {size: 1, alignment: 1},
443
- get_c_layout(tmpdir.path(), &cc, "char").expect("C layout"),
444
- "failed to obtain correct layout for char type");
445
-
446
- let mut results : Results = Default::default();
447
- for (i, &(name, rust_layout)) in RUST_LAYOUTS.iter().enumerate() {
448
- match get_c_layout(tmpdir.path(), &cc, name) {
449
- Err(e) => {
450
- results.record_failed_to_compile();
451
- eprintln!("{}", e);
452
- },
453
- Ok(c_layout) => {
454
- if rust_layout == c_layout {
455
- results.record_passed();
456
- } else {
457
- results.record_failed();
458
- eprintln!("Layout mismatch for {}\nRust: {:?}\nC: {:?}",
459
- name, rust_layout, &c_layout);
460
- }
461
- }
462
- };
463
- if (i + 1) % 25 == 0 {
464
- println!("layout ... {}", results.summary());
465
+ let mut results = Results::default();
466
+
467
+ for ((rust_name, rust_layout), (c_name, c_layout)) in
468
+ RUST_LAYOUTS.iter().zip(c_layouts.iter())
469
+ {
470
+ if rust_name != c_name {
471
+ results.record_failed();
472
+ eprintln!("Name mismatch:\nRust: {:?}\nC: {:?}", rust_name, c_name,);
473
+ continue;
465
474
}
466
- }
467
- results.expect_total_success();
468
- }
469
475
470
- fn get_c_layout(dir: &Path, cc: &Compiler, name: &str) -> Result<Layout, Box<dyn Error>> {
471
- let exe = dir.join("layout");
472
- let mut cc = cc.clone();
473
- cc.define("ABI_TYPE_NAME", name);
474
- cc.compile(Path::new("tests/layout.c"), &exe)?;
476
+ if rust_layout != c_layout {
477
+ results.record_failed();
478
+ eprintln!(
479
+ "Layout mismatch for {}\nRust: {:?}\nC: {:?}",
480
+ rust_name, rust_layout, &c_layout
481
+ );
482
+ continue;
483
+ }
475
484
476
- let mut abi_cmd = Command::new(exe);
477
- let output = abi_cmd.output()?;
478
- if !output.status.success() {
479
- return Err(format!("command {:?} failed, {:?}",
480
- &abi_cmd, &output).into());
485
+ results.record_passed();
481
486
}
482
487
483
- let stdout = str::from_utf8(&output.stdout)?;
484
- let mut words = stdout.trim().split_whitespace();
485
- let size = words.next().unwrap().parse().unwrap();
486
- let alignment = words.next().unwrap().parse().unwrap();
487
- Ok(Layout {size, alignment})
488
+ results.expect_total_success();
488
489
}
489
490
490
- fn get_c_value(dir: &Path, cc: &Compiler, name: &str) -> Result<String, Box<dyn Error>> {
491
- let exe = dir.join("constant");
492
- let mut cc = cc.clone();
493
- cc.define("ABI_CONSTANT_NAME", name);
494
- cc.compile(Path::new("tests/constant.c"), &exe)?;
491
+ fn get_c_output(name: &str) -> Result<String, Box<dyn Error>> {
492
+ let tmpdir = Builder::new().prefix("abi").tempdir()?;
493
+ let exe = tmpdir.path().join(name);
494
+ let c_file = Path::new("tests").join(name).with_extension("c");
495
+
496
+ let cc = Compiler::new().expect("configured compiler");
497
+ cc.compile(&c_file, &exe)?;
495
498
496
499
let mut abi_cmd = Command::new(exe);
497
500
let output = abi_cmd.output()?;
498
501
if !output.status.success() {
499
- return Err(format!("command {:?} failed, {:?}",
500
- &abi_cmd, &output).into());
501
- }
502
-
503
- let output = str::from_utf8(&output.stdout)?.trim();
504
- if !output.starts_with("###gir test###") ||
505
- !output.ends_with("###gir test###") {
506
- return Err(format!("command {:?} return invalid output, {:?}",
507
- &abi_cmd, &output).into());
502
+ return Err(format!("command {:?} failed, {:?}", &abi_cmd, &output).into());
508
503
}
509
504
510
- Ok(String::from(& output[14..(output.len() - 14)]) )
505
+ Ok(String::from_utf8( output.stdout)? )
511
506
}
512
507
513
508
const RUST_LAYOUTS: &[(&str, Layout)] = &["####
514
509
) ?;
515
510
for ctype in ctypes {
516
511
general:: cfg_condition ( w, & ctype. cfg_condition , false , 1 ) ?;
517
- writeln ! ( w, "\t (\" {ctype}\" , Layout {{size: size_of::<{ctype}>(), alignment: align_of::<{ctype}>()}})," ,
512
+ writeln ! ( w, " (\" {ctype}\" , Layout {{size: size_of::<{ctype}>(), alignment: align_of::<{ctype}>()}})," ,
518
513
ctype=ctype. name) ?;
519
514
}
520
515
writeln ! (
@@ -527,7 +522,7 @@ const RUST_CONSTANTS: &[(&str, &str)] = &["##
527
522
for cconst in cconsts {
528
523
writeln ! (
529
524
w,
530
- "\t (\" {name}\" , \" {value}\" )," ,
525
+ " (\" {name}\" , \" {value}\" )," ,
531
526
name = cconst. name,
532
527
value = & general:: escape_string( & cconst. value)
533
528
) ?;
0 commit comments