|
1 | 1 | use std::env;
|
2 | 2 | use std::fs;
|
3 |
| -use std::path::PathBuf; |
| 3 | +use std::path::{Path, PathBuf}; |
| 4 | +use std::process::Command; |
4 | 5 |
|
5 | 6 | fn main() {
|
| 7 | + // if we are being executed from a `fork_run_action` call (i.e. this is a |
| 8 | + // "fork"), perform the requested action and then return. |
| 9 | + if run_action_if_forked() { |
| 10 | + return; |
| 11 | + } |
| 12 | + |
6 | 13 | let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
7 | 14 | fs::remove_dir_all(&out).unwrap();
|
8 | 15 | fs::create_dir(&out).unwrap();
|
9 | 16 |
|
| 17 | + // The following are builds where we want to capture the output (i.e. stdout and |
| 18 | + // stderr). We do that by re-running _this_ executable and passing in the |
| 19 | + // action as the first argument. |
| 20 | + run_forked_capture_output(&out, "metadata-on"); |
| 21 | + run_forked_capture_output(&out, "metadata-off"); |
| 22 | + |
| 23 | + run_forked_capture_output(&out, "warnings-off"); |
| 24 | + if cc::Build::new().get_compiler().is_like_msvc() { |
| 25 | + // MSVC doesn't output warnings to stderr, so we can't capture them. |
| 26 | + // the test will use this env var to know whether to run the test. |
| 27 | + println!("cargo:rustc-env=TEST_WARNINGS_ON=0"); |
| 28 | + } else { |
| 29 | + println!("cargo:rustc-env=TEST_WARNINGS_ON=1"); |
| 30 | + run_forked_capture_output(&out, "warnings-on"); |
| 31 | + } |
| 32 | + |
10 | 33 | cc::Build::new()
|
11 | 34 | .file("src/foo.c")
|
12 | 35 | .flag_if_supported("-Wall")
|
@@ -104,3 +127,48 @@ fn main() {
|
104 | 127 | let out = String::from_utf8(out).unwrap();
|
105 | 128 | assert!(out.contains("hello world"));
|
106 | 129 | }
|
| 130 | + |
| 131 | +#[track_caller] |
| 132 | +fn run_forked_capture_output(out: &Path, action: &str) { |
| 133 | + let program = env::current_exe().unwrap(); |
| 134 | + let output = Command::new(&program).arg(action).output().unwrap(); |
| 135 | + assert!(output.status.success(), "output: {:#?}", output); |
| 136 | + // we've captured the output and now we write it to a dedicated directory in the |
| 137 | + // build output so our tests can access the output. |
| 138 | + let action_dir = out.join(action); |
| 139 | + fs::create_dir_all(&action_dir).unwrap(); |
| 140 | + fs::write(action_dir.join("stdout"), output.stdout).unwrap(); |
| 141 | + fs::write(action_dir.join("stderr"), output.stderr).unwrap(); |
| 142 | +} |
| 143 | + |
| 144 | +fn run_action_if_forked() -> bool { |
| 145 | + let mut args = env::args(); |
| 146 | + let _program = args.next().unwrap(); |
| 147 | + let action = args.next(); |
| 148 | + match action.as_deref() { |
| 149 | + Some("metadata-on") => build_cargo_metadata(true), |
| 150 | + Some("metadata-off") => build_cargo_metadata(false), |
| 151 | + Some("warnings-on") => build_cargo_warnings(true), |
| 152 | + Some("warnings-off") => build_cargo_warnings(false), |
| 153 | + // No action requested, we're being called from cargo. Proceed with build. |
| 154 | + _ => return false, |
| 155 | + } |
| 156 | + true |
| 157 | +} |
| 158 | + |
| 159 | +fn build_cargo_warnings(warnings: bool) { |
| 160 | + cc::Build::new() |
| 161 | + .cargo_metadata(false) |
| 162 | + .cargo_warnings(warnings) |
| 163 | + .file("src/compile_error.c") |
| 164 | + .try_compile("compile_error") |
| 165 | + .unwrap_err(); |
| 166 | +} |
| 167 | + |
| 168 | +fn build_cargo_metadata(metadata: bool) { |
| 169 | + cc::Build::new() |
| 170 | + .cargo_metadata(metadata) |
| 171 | + .file("src/dummy.c") |
| 172 | + .try_compile("dummy") |
| 173 | + .unwrap(); |
| 174 | +} |
0 commit comments