Skip to content

Commit 1fd1ad5

Browse files
committed
even when not linking, create stub .rlib files to fool cargo
1 parent 2cc3993 commit 1fd1ad5

File tree

1 file changed

+61
-38
lines changed

1 file changed

+61
-38
lines changed

cargo-miri/bin.rs

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,13 @@ fn xargo_check() -> Command {
136136
Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check")))
137137
}
138138

139-
fn exec(mut cmd: Command) -> ! {
139+
/// Execute the command if it fails, fail this process with the same exit code.
140+
/// Otherwise, continue.
141+
fn exec(mut cmd: Command) {
140142
let exit_status = cmd.status().expect("failed to run command");
141-
std::process::exit(exit_status.code().unwrap_or(-1))
143+
if exit_status.success().not() {
144+
std::process::exit(exit_status.code().unwrap_or(-1))
145+
}
142146
}
143147

144148
fn xargo_version() -> Option<(u32, u32, u32)> {
@@ -451,6 +455,20 @@ fn phase_cargo_rustc(args: env::Args) {
451455
(is_bin || is_test) && !print
452456
}
453457

458+
fn out_filename(prefix: &str, suffix: &str) -> PathBuf {
459+
let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap());
460+
path.push(format!(
461+
"{}{}{}{}",
462+
prefix,
463+
get_arg_flag_value("--crate-name").unwrap(),
464+
// This is technically a `-C` flag but the prefix seems unique enough...
465+
// (and cargo passes this before the filename so it should be unique)
466+
get_arg_flag_value("extra-filename").unwrap_or(String::new()),
467+
suffix,
468+
));
469+
path
470+
}
471+
454472
let verbose = std::env::var_os("MIRI_VERBOSE").is_some();
455473
let target_crate = is_target_crate();
456474

@@ -461,59 +479,57 @@ fn phase_cargo_rustc(args: env::Args) {
461479
// Instead of compiling, we write JSON into the output file with all the relevant command-line flags
462480
// and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase.
463481
let info = CrateRunInfo::collect(args);
482+
// FIXME: Windows might need a ".exe" suffix.
483+
let filename = out_filename("", "");
464484

465-
let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap());
466-
path.push(format!(
467-
"{}{}",
468-
get_arg_flag_value("--crate-name").unwrap(),
469-
// This is technically a `-C` flag but the prefix seems unique enough...
470-
// (and cargo passes this before the filename so it should be unique)
471-
get_arg_flag_value("extra-filename").unwrap_or(String::new()),
472-
));
473485
if verbose {
474-
eprintln!("[cargo-miri rustc] writing run info to {:?}", path.display());
486+
eprintln!("[cargo-miri rustc] writing run info to {:?}", filename.display());
475487
}
476488

477-
let file = File::create(&path)
478-
.unwrap_or_else(|_| show_error(format!("Cannot create {:?}", path.display())));
489+
let file = File::create(&filename)
490+
.unwrap_or_else(|_| show_error(format!("Cannot create {:?}", filename.display())));
479491
let file = BufWriter::new(file);
480492
serde_json::ser::to_writer(file, &info)
481-
.unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", path.display())));
493+
.unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", filename.display())));
482494
return;
483495
}
484496

485497
let mut cmd = miri();
486-
// Forward arguments, but (only for target crates!) remove "link" from "--emit" to make this a check-only build.
487-
let emit_flag = "--emit";
488-
for arg in args {
489-
if target_crate && arg.starts_with(emit_flag) {
490-
// Patch this argument. First, extract its value.
491-
let val = &arg[emit_flag.len()..];
492-
assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument");
493-
let val = &val[1..];
494-
let mut val: Vec<_> = val.split(',').collect();
495-
// Now make sure "link" is not in there, but "metadata" is.
496-
if let Some(i) = val.iter().position(|&s| s == "link") {
497-
val.remove(i);
498-
if !val.iter().any(|&s| s == "metadata") {
499-
val.push("metadata");
498+
let mut emit_link_hack = false;
499+
// Arguments are treated very differently depending on whether this crate is
500+
// for interpretation by Miri, or for use by a build script / proc macro.
501+
if target_crate {
502+
// Forward arguments, butremove "link" from "--emit" to make this a check-only build.
503+
let emit_flag = "--emit";
504+
for arg in args {
505+
if arg.starts_with(emit_flag) {
506+
// Patch this argument. First, extract its value.
507+
let val = &arg[emit_flag.len()..];
508+
assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument");
509+
let val = &val[1..];
510+
let mut val: Vec<_> = val.split(',').collect();
511+
// Now make sure "link" is not in there, but "metadata" is.
512+
if let Some(i) = val.iter().position(|&s| s == "link") {
513+
emit_link_hack = true;
514+
val.remove(i);
515+
if !val.iter().any(|&s| s == "metadata") {
516+
val.push("metadata");
517+
}
500518
}
519+
cmd.arg(format!("{}={}", emit_flag, val.join(",")));
520+
} else {
521+
cmd.arg(arg);
501522
}
502-
cmd.arg(format!("{}={}", emit_flag, val.join(",")));
503-
// FIXME: due to this, the `.rlib` file does not get created and cargo re-triggers the build each time.
504-
} else {
505-
cmd.arg(arg);
506523
}
507-
}
508524

509-
// We make sure to only specify our custom Xargo sysroot for target crates - that is,
510-
// crates which are needed for interpretation by Miri. proc-macros and build scripts
511-
// should use the default sysroot.
512-
if target_crate {
525+
// Use our custom sysroot.
513526
let sysroot =
514527
env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT");
515528
cmd.arg("--sysroot");
516529
cmd.arg(sysroot);
530+
} else {
531+
// For host crates, just forward everything.
532+
cmd.args(args);
517533
}
518534

519535
// We want to compile, not interpret. We still use Miri to make sure the compiler version etc
@@ -524,7 +540,14 @@ fn phase_cargo_rustc(args: env::Args) {
524540
if verbose {
525541
eprintln!("[cargo-miri rustc] {:?}", cmd);
526542
}
527-
exec(cmd)
543+
exec(cmd);
544+
545+
// Create a stub .rlib file if "link" was requested by cargo.
546+
if emit_link_hack {
547+
// FIXME: is "lib" always right?
548+
let filename = out_filename("lib", ".rlib");
549+
File::create(filename).expect("Failed to create rlib file");
550+
}
528551
}
529552

530553
fn phase_cargo_runner(binary: &str, binary_args: env::Args) {

0 commit comments

Comments
 (0)