mirror of
https://github.com/rust-lang/cargo
synced 2024-10-31 07:46:57 +00:00
dec9e8cc1b
Signed-off-by: hi-rustin <rustin.liu@gmail.com>
5394 lines
138 KiB
Rust
5394 lines
138 KiB
Rust
//! Tests for build.rs scripts.
|
|
|
|
use cargo_test_support::compare::assert_match_exact;
|
|
use cargo_test_support::install::cargo_home;
|
|
use cargo_test_support::paths::CargoPathExt;
|
|
use cargo_test_support::registry::Package;
|
|
use cargo_test_support::tools;
|
|
use cargo_test_support::{
|
|
basic_manifest, cargo_exe, cross_compile, is_coarse_mtime, project, project_in,
|
|
};
|
|
use cargo_test_support::{rustc_host, sleep_ms, slow_cpu_multiplier, symlink_supported};
|
|
use cargo_util::paths::{self, remove_dir_all};
|
|
use std::env;
|
|
use std::fs;
|
|
use std::io;
|
|
use std::thread;
|
|
|
|
#[cargo_test]
|
|
fn custom_build_script_failed() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file("build.rs", "fn main() { std::process::exit(101); }")
|
|
.build();
|
|
p.cargo("build -v")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]`
|
|
[RUNNING] `[..]/build-script-build`
|
|
[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
|
|
|
|
Caused by:
|
|
process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_script_failed_backtraces_message() {
|
|
// In this situation (no dependency sharing), debuginfo is turned off in
|
|
// `dev.build-override`. However, if an error occurs running e.g. a build
|
|
// script, and backtraces are opted into: a message explaining how to
|
|
// improve backtraces is also displayed.
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file("build.rs", "fn main() { std::process::exit(101); }")
|
|
.build();
|
|
p.cargo("build -v")
|
|
.env("RUST_BACKTRACE", "1")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]`
|
|
[RUNNING] `[..]/build-script-build`
|
|
[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
|
|
note: To improve backtraces for build dependencies, set the \
|
|
CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG=true environment variable [..]
|
|
|
|
Caused by:
|
|
process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
|
|
)
|
|
.run();
|
|
|
|
p.cargo("check -v")
|
|
.env("RUST_BACKTRACE", "1")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `[..]/build-script-build`
|
|
[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
|
|
note: To improve backtraces for build dependencies, set the \
|
|
CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG=true environment variable [..]
|
|
|
|
Caused by:
|
|
process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_script_failed_backtraces_message_with_debuginfo() {
|
|
// This is the same test as `custom_build_script_failed_backtraces_message` above, this time
|
|
// ensuring that the message dedicated to improving backtraces by requesting debuginfo is not
|
|
// shown when debuginfo is already turned on.
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file("build.rs", "fn main() { std::process::exit(101); }")
|
|
.build();
|
|
p.cargo("build -v")
|
|
.env("RUST_BACKTRACE", "1")
|
|
.env("CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG", "true")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]`
|
|
[RUNNING] `[..]/build-script-build`
|
|
[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
|
|
|
|
Caused by:
|
|
process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_vars() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
|
|
[features]
|
|
bar_feat = ["bar/foo"]
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "bar"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
build = "build.rs"
|
|
|
|
[features]
|
|
foo = []
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "pub fn hello() {}");
|
|
|
|
let cargo = cargo_exe().canonicalize().unwrap();
|
|
let cargo = cargo.to_str().unwrap();
|
|
let rustc = paths::resolve_executable("rustc".as_ref())
|
|
.unwrap()
|
|
.canonicalize()
|
|
.unwrap();
|
|
let rustc = rustc.to_str().unwrap();
|
|
let file_content = format!(
|
|
r##"
|
|
use std::env;
|
|
use std::path::Path;
|
|
|
|
fn main() {{
|
|
let _target = env::var("TARGET").unwrap();
|
|
let _ncpus = env::var("NUM_JOBS").unwrap();
|
|
let _dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
|
|
let opt = env::var("OPT_LEVEL").unwrap();
|
|
assert_eq!(opt, "0");
|
|
|
|
let opt = env::var("PROFILE").unwrap();
|
|
assert_eq!(opt, "debug");
|
|
|
|
let debug = env::var("DEBUG").unwrap();
|
|
assert_eq!(debug, "true");
|
|
|
|
let out = env::var("OUT_DIR").unwrap();
|
|
assert!(out.starts_with(r"{0}"));
|
|
assert!(Path::new(&out).is_dir());
|
|
|
|
let _host = env::var("HOST").unwrap();
|
|
|
|
let _feat = env::var("CARGO_FEATURE_FOO").unwrap();
|
|
|
|
let cargo = env::var("CARGO").unwrap();
|
|
if env::var_os("CHECK_CARGO_IS_RUSTC").is_some() {{
|
|
assert_eq!(cargo, r#"{rustc}"#);
|
|
}} else {{
|
|
assert_eq!(cargo, r#"{cargo}"#);
|
|
}}
|
|
|
|
let rustc = env::var("RUSTC").unwrap();
|
|
assert_eq!(rustc, "rustc");
|
|
|
|
let rustdoc = env::var("RUSTDOC").unwrap();
|
|
assert_eq!(rustdoc, "rustdoc");
|
|
|
|
assert!(env::var("RUSTC_WRAPPER").is_err());
|
|
assert!(env::var("RUSTC_WORKSPACE_WRAPPER").is_err());
|
|
|
|
assert!(env::var("RUSTC_LINKER").is_err());
|
|
|
|
assert!(env::var("RUSTFLAGS").is_err());
|
|
let rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
|
|
assert_eq!(rustflags, "");
|
|
}}
|
|
"##,
|
|
p.root()
|
|
.join("target")
|
|
.join("debug")
|
|
.join("build")
|
|
.display(),
|
|
);
|
|
|
|
let p = p.file("bar/build.rs", &file_content).build();
|
|
|
|
p.cargo("build --features bar_feat").run();
|
|
p.cargo("build --features bar_feat")
|
|
// we use rustc since $CARGO is only used if it points to a path that exists
|
|
.env("CHECK_CARGO_IS_RUSTC", "1")
|
|
.env(cargo::CARGO_ENV, rustc)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustflags() {
|
|
let rustflags = "--cfg=special";
|
|
let rustflags_alt = "--cfg=notspecial";
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[build]
|
|
rustflags = ["{}"]
|
|
"#,
|
|
rustflags
|
|
),
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
&format!(
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {{
|
|
// Static assertion that exactly one of the cfg paths is always taken.
|
|
assert!(env::var("RUSTFLAGS").is_err());
|
|
let x;
|
|
#[cfg(special)]
|
|
{{ assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "{}"); x = String::new(); }}
|
|
#[cfg(notspecial)]
|
|
{{ assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "{}"); x = String::new(); }}
|
|
let _ = x;
|
|
}}
|
|
"#,
|
|
rustflags, rustflags_alt,
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("check").run();
|
|
|
|
// RUSTFLAGS overrides build.rustflags, so --cfg=special shouldn't be passed
|
|
p.cargo("check").env("RUSTFLAGS", rustflags_alt).run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_encoded_rustflags() {
|
|
// NOTE: We use "-Clink-arg=-B nope" here rather than, say, "-A missing_docs", since for the
|
|
// latter it won't matter if the whitespace accidentally gets split, as rustc will do the right
|
|
// thing either way.
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
r#"
|
|
[build]
|
|
rustflags = ["-Clink-arg=-B nope", "--cfg=foo"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {{
|
|
assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "-Clink-arg=-B nope\x1f--cfg=foo");
|
|
}}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("check").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustc_wrapper() {
|
|
let wrapper = tools::echo_wrapper();
|
|
let p = project()
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {{
|
|
assert_eq!(
|
|
env::var("RUSTC_WRAPPER").unwrap(),
|
|
env::var("CARGO_RUSTC_WRAPPER_CHECK").unwrap()
|
|
);
|
|
}}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("check")
|
|
.env("CARGO_BUILD_RUSTC_WRAPPER", &wrapper)
|
|
.env("CARGO_RUSTC_WRAPPER_CHECK", &wrapper)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustc_workspace_wrapper() {
|
|
let wrapper = tools::echo_wrapper();
|
|
|
|
// Workspace wrapper should be set for any crate we're operating directly on.
|
|
let p = project()
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {{
|
|
assert_eq!(
|
|
env::var("RUSTC_WORKSPACE_WRAPPER").unwrap(),
|
|
env::var("CARGO_RUSTC_WORKSPACE_WRAPPER_CHECK").unwrap()
|
|
);
|
|
}}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("check")
|
|
.env("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER", &wrapper)
|
|
.env("CARGO_RUSTC_WORKSPACE_WRAPPER_CHECK", &wrapper)
|
|
.run();
|
|
|
|
// But should not be set for a crate from the registry, as then it's not in a workspace.
|
|
Package::new("bar", "0.1.0")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
links = "a"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {{
|
|
assert!(env::var("RUSTC_WORKSPACE_WRAPPER").is_err());
|
|
}}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
bar = "0.1"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("check")
|
|
.env("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER", &wrapper)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustc_linker() {
|
|
if cross_compile::disabled() {
|
|
return;
|
|
}
|
|
let target = cross_compile::alternate();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}]
|
|
linker = "/path/to/linker"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker"));
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// no crate type set => linker never called => build succeeds if and
|
|
// only if build.rs succeeds, despite linker binary not existing.
|
|
p.cargo("build --target").arg(&target).run();
|
|
}
|
|
|
|
// Only run this test on linux, since it's difficult to construct
|
|
// a case suitable for all platforms.
|
|
// See:https://github.com/rust-lang/cargo/pull/12535#discussion_r1306618264
|
|
#[cargo_test]
|
|
#[cfg(target_os = "linux")]
|
|
fn custom_build_env_var_rustc_linker_with_target_cfg() {
|
|
if cross_compile::disabled() {
|
|
return;
|
|
}
|
|
|
|
let target = cross_compile::alternate();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
r#"
|
|
[target.'cfg(target_pointer_width = "32")']
|
|
linker = "/path/to/linker"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker"));
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// no crate type set => linker never called => build succeeds if and
|
|
// only if build.rs succeeds, despite linker binary not existing.
|
|
p.cargo("build --target").arg(&target).run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustc_linker_bad_host_target() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}]
|
|
linker = "/path/to/linker"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// build.rs should fail since host == target when no target is set
|
|
p.cargo("build --verbose")
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/linker [..]`
|
|
[ERROR] linker `[..]/path/to/linker` not found
|
|
"
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustc_linker_host_target() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
target-applies-to-host = false
|
|
[target.{}]
|
|
linker = "/path/to/linker"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker"));
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// no crate type set => linker never called => build succeeds if and
|
|
// only if build.rs succeeds, despite linker binary not existing.
|
|
p.cargo("build -Z target-applies-to-host --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["target-applies-to-host"])
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustc_linker_host_target_env() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}]
|
|
linker = "/path/to/linker"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker"));
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// no crate type set => linker never called => build succeeds if and
|
|
// only if build.rs succeeds, despite linker binary not existing.
|
|
p.cargo("build -Z target-applies-to-host --target")
|
|
.env("CARGO_TARGET_APPLIES_TO_HOST", "false")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["target-applies-to-host"])
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_invalid_host_config_feature_flag() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}]
|
|
linker = "/path/to/linker"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// build.rs should fail due to -Zhost-config being set without -Ztarget-applies-to-host
|
|
p.cargo("build -Z host-config --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["host-config"])
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
error: the -Zhost-config flag requires the -Ztarget-applies-to-host flag to be set
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_linker_host_target_with_bad_host_config() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[host]
|
|
linker = "/path/to/host/linker"
|
|
[target.{}]
|
|
linker = "/path/to/target/linker"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// build.rs should fail due to bad host linker being set
|
|
p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]`
|
|
[ERROR] linker `[..]/path/to/host/linker` not found
|
|
"
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_linker_bad_host() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[host]
|
|
linker = "/path/to/host/linker"
|
|
[target.{}]
|
|
linker = "/path/to/target/linker"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// build.rs should fail due to bad host linker being set
|
|
p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]`
|
|
[ERROR] linker `[..]/path/to/host/linker` not found
|
|
"
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_linker_bad_host_with_arch() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[host]
|
|
linker = "/path/to/host/linker"
|
|
[host.{}]
|
|
linker = "/path/to/host/arch/linker"
|
|
[target.{}]
|
|
linker = "/path/to/target/linker"
|
|
"#,
|
|
target, target
|
|
),
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// build.rs should fail due to bad host linker being set
|
|
p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/arch/linker [..]`
|
|
[ERROR] linker `[..]/path/to/host/arch/linker` not found
|
|
"
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_env_var_rustc_linker_cross_arch_host() {
|
|
let target = rustc_host();
|
|
let cross_target = cross_compile::alternate();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[host.{}]
|
|
linker = "/path/to/host/arch/linker"
|
|
[target.{}]
|
|
linker = "/path/to/target/linker"
|
|
"#,
|
|
cross_target, target
|
|
),
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/target/linker"));
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// build.rs should be built fine since cross target != host target.
|
|
// assertion should succeed since it's still passed the target linker
|
|
p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_linker_bad_cross_arch_host() {
|
|
let target = rustc_host();
|
|
let cross_target = cross_compile::alternate();
|
|
let p = project()
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[host]
|
|
linker = "/path/to/host/linker"
|
|
[host.{}]
|
|
linker = "/path/to/host/arch/linker"
|
|
[target.{}]
|
|
linker = "/path/to/target/linker"
|
|
"#,
|
|
cross_target, target
|
|
),
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
// build.rs should fail due to bad host linker being set
|
|
p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]`
|
|
[ERROR] linker `[..]/path/to/host/linker` not found
|
|
"
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_script_wrong_rustc_flags() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() { println!("cargo::rustc-flags=-aaa -bbb"); }"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"[ERROR] Only `-l` and `-L` flags are allowed in build script of `foo v0.5.0 ([CWD])`: \
|
|
`-aaa -bbb`",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_script_rustc_flags() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "bar"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
|
|
[dependencies.foo]
|
|
path = "foo"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("foo/src/lib.rs", "")
|
|
.file(
|
|
"foo/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-flags=-l nonexistinglib -L /dummy/path1 -L /dummy/path2");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build --verbose")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo [..]
|
|
[RUNNING] `rustc --crate-name build_script_build foo/build.rs [..]
|
|
[RUNNING] `[..]build-script-build`
|
|
[RUNNING] `rustc --crate-name foo foo/src/lib.rs [..]\
|
|
-L dependency=[CWD]/target/debug/deps \
|
|
-L /dummy/path1 -L /dummy/path2 -l nonexistinglib`
|
|
[COMPILING] bar [..]
|
|
[RUNNING] `rustc --crate-name bar src/main.rs [..]\
|
|
-L dependency=[CWD]/target/debug/deps \
|
|
--extern foo=[..]libfoo-[..] \
|
|
-L /dummy/path1 -L /dummy/path2`
|
|
[FINISHED] dev [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_script_rustc_flags_no_space() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "bar"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
|
|
[dependencies.foo]
|
|
path = "foo"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("foo/src/lib.rs", "")
|
|
.file(
|
|
"foo/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-flags=-lnonexistinglib -L/dummy/path1 -L/dummy/path2");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build --verbose")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo [..]
|
|
[RUNNING] `rustc --crate-name build_script_build foo/build.rs [..]
|
|
[RUNNING] `[..]build-script-build`
|
|
[RUNNING] `rustc --crate-name foo foo/src/lib.rs [..]\
|
|
-L dependency=[CWD]/target/debug/deps \
|
|
-L /dummy/path1 -L /dummy/path2 -l nonexistinglib`
|
|
[COMPILING] bar [..]
|
|
[RUNNING] `rustc --crate-name bar src/main.rs [..]\
|
|
-L dependency=[CWD]/target/debug/deps \
|
|
--extern foo=[..]libfoo-[..] \
|
|
-L /dummy/path1 -L /dummy/path2`
|
|
[FINISHED] dev [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_no_build_cmd() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
|
|
|
|
Caused by:
|
|
package `foo v0.5.0 ([CWD])` specifies that it links to `a` but does \
|
|
not have a custom build script
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_duplicates() {
|
|
// this tests that the links_duplicates are caught at resolver time
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
build = "build.rs"
|
|
|
|
[dependencies.a-sys]
|
|
path = "a-sys"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "")
|
|
.file(
|
|
"a-sys/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a-sys"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a-sys/src/lib.rs", "")
|
|
.file("a-sys/build.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build").with_status(101)
|
|
.with_stderr("\
|
|
error: failed to select a version for `a-sys`.
|
|
... required by package `foo v0.5.0 ([..])`
|
|
versions that meet the requirements `*` are: 0.5.0
|
|
|
|
the package `a-sys` links to the native library `a`, but it conflicts with a previous package which links to `a` as well:
|
|
package `foo v0.5.0 ([..])`
|
|
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = \"a\"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
|
|
|
|
failed to select a version for `a-sys` which could resolve this conflict
|
|
").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_duplicates_old_registry() {
|
|
// Test old links validator. See `validate_links`.
|
|
Package::new("bar", "0.1.0")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
links = "a"
|
|
"#,
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
links = "a"
|
|
|
|
[dependencies]
|
|
bar = "0.1"
|
|
"#,
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[UPDATING] `[..]` index
|
|
[DOWNLOADING] crates ...
|
|
[DOWNLOADED] bar v0.1.0 ([..])
|
|
[ERROR] multiple packages link to native library `a`, \
|
|
but a native library can be linked only once
|
|
|
|
package `bar v0.1.0`
|
|
... which satisfies dependency `bar = \"^0.1\"` (locked to 0.1.0) of package `foo v0.1.0 ([..]foo)`
|
|
links to native library `a`
|
|
|
|
package `foo v0.1.0 ([..]foo)`
|
|
also links to native library `a`
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_duplicates_deep_dependency() {
|
|
// this tests that the links_duplicates are caught at resolver time
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
build = "build.rs"
|
|
|
|
[dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.a-sys]
|
|
path = "a-sys"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file("a/build.rs", "")
|
|
.file(
|
|
"a/a-sys/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a-sys"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/a-sys/src/lib.rs", "")
|
|
.file("a/a-sys/build.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build").with_status(101)
|
|
.with_stderr("\
|
|
error: failed to select a version for `a-sys`.
|
|
... required by package `a v0.5.0 ([..])`
|
|
... which satisfies path dependency `a` of package `foo v0.5.0 ([..])`
|
|
versions that meet the requirements `*` are: 0.5.0
|
|
|
|
the package `a-sys` links to the native library `a`, but it conflicts with a previous package which links to `a` as well:
|
|
package `foo v0.5.0 ([..])`
|
|
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = \"a\"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
|
|
|
|
failed to select a version for `a-sys` which could resolve this conflict
|
|
").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn overrides_and_links() {
|
|
let target = rustc_host();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
fn main() {
|
|
assert_eq!(env::var("DEP_FOO_FOO").ok().expect("FOO missing"),
|
|
"bar");
|
|
assert_eq!(env::var("DEP_FOO_BAR").ok().expect("BAR missing"),
|
|
"baz");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}.foo]
|
|
rustc-flags = "-L foo -L bar"
|
|
foo = "bar"
|
|
bar = "baz"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file("a/build.rs", "not valid rust code")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[..]
|
|
[..]
|
|
[..]
|
|
[..]
|
|
[..]
|
|
[RUNNING] `rustc --crate-name foo [..] -L foo -L bar`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn unused_overrides() {
|
|
let target = rustc_host();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "fn main() {}")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}.foo]
|
|
rustc-flags = "-L foo -L bar"
|
|
foo = "bar"
|
|
bar = "baz"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_passes_env_vars() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
fn main() {
|
|
assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar");
|
|
assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
r#"
|
|
use std::env;
|
|
fn main() {
|
|
let lib = env::var("CARGO_MANIFEST_LINKS").unwrap();
|
|
assert_eq!(lib, "foo");
|
|
|
|
println!("cargo::metadata=foo=bar");
|
|
println!("cargo::metadata=bar=baz");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn only_rerun_build_script() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
p.root().move_into_the_past();
|
|
|
|
p.change_file("some-new-file", "");
|
|
p.root().move_into_the_past();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo v0.5.0 ([CWD]): the precalculated components changed
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn rebuild_continues_to_pass_env_vars() {
|
|
let a = project()
|
|
.at("a")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::time::Duration;
|
|
fn main() {
|
|
println!("cargo::metadata=foo=bar");
|
|
println!("cargo::metadata=bar=baz");
|
|
std::thread::sleep(Duration::from_millis(500));
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
a.root().move_into_the_past();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.a]
|
|
path = '{}'
|
|
"#,
|
|
a.root().display()
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
fn main() {
|
|
assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar");
|
|
assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
p.root().move_into_the_past();
|
|
|
|
p.change_file("some-new-file", "");
|
|
p.root().move_into_the_past();
|
|
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn testing_and_such() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "fn main() {}")
|
|
.build();
|
|
|
|
println!("build");
|
|
p.cargo("build -v").run();
|
|
p.root().move_into_the_past();
|
|
|
|
p.change_file("src/lib.rs", "");
|
|
p.root().move_into_the_past();
|
|
|
|
println!("test");
|
|
p.cargo("test -vj1")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo v0.5.0 ([CWD]): the precalculated components changed
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..]`
|
|
[RUNNING] `rustc --crate-name foo [..]`
|
|
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]/foo-[..][EXE]`
|
|
[DOCTEST] foo
|
|
[RUNNING] `rustdoc [..]--test [..]`",
|
|
)
|
|
.with_stdout_contains_n("running 0 tests", 2)
|
|
.run();
|
|
|
|
println!("doc");
|
|
p.cargo("doc -v")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustdoc [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
[GENERATED] [CWD]/target/doc/foo/index.html
|
|
",
|
|
)
|
|
.run();
|
|
|
|
p.change_file("src/main.rs", "fn main() {}");
|
|
println!("run");
|
|
p.cargo("run")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `target/debug/foo[EXE]`
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn propagation_of_l_flags() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
[dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "bar"
|
|
build = "build.rs"
|
|
|
|
[dependencies.b]
|
|
path = "../b"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
r#"fn main() { println!("cargo::rustc-flags=-L bar"); }"#,
|
|
)
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.file("b/build.rs", "bad file")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}.foo]
|
|
rustc-flags = "-L foo"
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v -j1")
|
|
.with_stderr_contains(
|
|
"\
|
|
[RUNNING] `rustc --crate-name a [..] -L bar[..]-L foo[..]`
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc --crate-name foo [..] -L bar -L foo`
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn propagation_of_l_flags_new() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
[dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "bar"
|
|
build = "build.rs"
|
|
|
|
[dependencies.b]
|
|
path = "../b"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.file("b/build.rs", "bad file")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}.foo]
|
|
rustc-link-search = ["foo"]
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v -j1")
|
|
.with_stderr_contains(
|
|
"\
|
|
[RUNNING] `rustc --crate-name a [..] -L bar[..]-L foo[..]`
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc --crate-name foo [..] -L bar -L foo`
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_deps_simple() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
[build-dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
"
|
|
#[allow(unused_extern_crates)]
|
|
extern crate a;
|
|
fn main() {}
|
|
",
|
|
)
|
|
.file("a/Cargo.toml", &basic_manifest("a", "0.5.0"))
|
|
.file("a/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] a v0.5.0 ([CWD]/a)
|
|
[RUNNING] `rustc --crate-name a [..]`
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc [..] build.rs [..] --extern a=[..]`
|
|
[RUNNING] `[..]/foo-[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_deps_not_for_normal() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
[build-dependencies.aaaaa]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
"#[allow(unused_extern_crates)] extern crate aaaaa;",
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
"
|
|
#[allow(unused_extern_crates)]
|
|
extern crate aaaaa;
|
|
fn main() {}
|
|
",
|
|
)
|
|
.file("a/Cargo.toml", &basic_manifest("aaaaa", "0.5.0"))
|
|
.file("a/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v --target")
|
|
.arg(&target)
|
|
.with_status(101)
|
|
.with_stderr_contains("[..]can't find crate for `aaaaa`[..]")
|
|
.with_stderr_contains(
|
|
"\
|
|
[ERROR] could not compile `foo` (lib) due to 1 previous error
|
|
|
|
Caused by:
|
|
process didn't exit successfully: [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_cmd_with_a_build_cmd() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[build-dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
"
|
|
#[allow(unused_extern_crates)]
|
|
extern crate a;
|
|
fn main() {}
|
|
",
|
|
)
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[build-dependencies.b]
|
|
path = "../b"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
"#[allow(unused_extern_crates)] extern crate b; fn main() {}",
|
|
)
|
|
.file("b/Cargo.toml", &basic_manifest("b", "0.5.0"))
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] b v0.5.0 ([CWD]/b)
|
|
[RUNNING] `rustc --crate-name b [..]`
|
|
[COMPILING] a v0.5.0 ([CWD]/a)
|
|
[RUNNING] `rustc [..] a/build.rs [..] --extern b=[..]`
|
|
[RUNNING] `[..]/a-[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name a [..]lib.rs [..]--crate-type lib \
|
|
--emit=[..]link[..] \
|
|
-C metadata=[..] \
|
|
--out-dir [..]target/debug/deps \
|
|
-L [..]target/debug/deps`
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin \
|
|
--emit=[..]link[..]\
|
|
-C metadata=[..] --out-dir [..] \
|
|
-L [..]target/debug/deps \
|
|
--extern a=[..]liba[..].rlib`
|
|
[RUNNING] `[..]/foo-[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..]lib.rs [..]--crate-type lib \
|
|
--emit=[..]link[..]-C debuginfo=2 [..]\
|
|
-C metadata=[..] \
|
|
--out-dir [..] \
|
|
-L [..]target/debug/deps`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn out_dir_is_preserved() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
use std::fs::File;
|
|
use std::path::Path;
|
|
fn main() {
|
|
let out = env::var("OUT_DIR").unwrap();
|
|
File::create(Path::new(&out).join("foo")).unwrap();
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
// Make the file
|
|
p.cargo("build -v").run();
|
|
|
|
// Change to asserting that it's there
|
|
p.change_file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
use std::fs::File;
|
|
use std::path::Path;
|
|
fn main() {
|
|
let out = env::var("OUT_DIR").unwrap();
|
|
File::open(&Path::new(&out).join("foo")).unwrap();
|
|
}
|
|
"#,
|
|
);
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo [..]: the file `build.rs` has changed ([..])
|
|
[COMPILING] foo [..]
|
|
[RUNNING] `rustc --crate-name build_script_build [..]
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
// Run a fresh build where file should be preserved
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[FRESH] foo [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
// One last time to make sure it's still there.
|
|
p.change_file("foo", "");
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo [..]: the precalculated components changed
|
|
[COMPILING] foo [..]
|
|
[RUNNING] `[..]build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn output_separate_lines() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-flags=-L foo");
|
|
println!("cargo::rustc-flags=-l static=foo");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("build -v")
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc [..] build.rs [..]`
|
|
[RUNNING] `[..]/foo-[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..] -L foo -l static=foo`
|
|
[ERROR] could not find native static library [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn output_separate_lines_new() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=foo");
|
|
println!("cargo::rustc-link-lib=static=foo");
|
|
println!("cargo::rustc-link-lib=bar");
|
|
println!("cargo::rustc-link-search=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
// The order of the arguments passed to rustc is important.
|
|
p.cargo("build -v")
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[RUNNING] `rustc [..] build.rs [..]`
|
|
[RUNNING] `[..]/foo-[..]/build-script-build`
|
|
[RUNNING] `rustc --crate-name foo [..] -L foo -L bar -l static=foo -l bar`
|
|
[ERROR] could not find native static library [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn code_generation() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
include!(concat!(env!("OUT_DIR"), "/hello.rs"));
|
|
|
|
fn main() {
|
|
println!("{}", message());
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
fn main() {
|
|
let dst = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
fs::write(dst.join("hello.rs"),
|
|
"
|
|
pub fn message() -> &'static str {
|
|
\"Hello, World!\"
|
|
}
|
|
")
|
|
.unwrap();
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("run")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `target/debug/foo[EXE]`",
|
|
)
|
|
.with_stdout("Hello, World!")
|
|
.run();
|
|
|
|
p.cargo("test").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn release_with_build_script() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v --release").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_script_only() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("build.rs", r#"fn main() {}"#)
|
|
.build();
|
|
p.cargo("build -v")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[ERROR] failed to parse manifest at `[..]`
|
|
|
|
Caused by:
|
|
no targets specified in the manifest
|
|
either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn shared_dep_with_a_build_script() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.a]
|
|
path = "a"
|
|
|
|
[build-dependencies.b]
|
|
path = "b"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "fn main() {}")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/build.rs", "fn main() {}")
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies.a]
|
|
path = "../a"
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn transitive_dep_host() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[build-dependencies.b]
|
|
path = "b"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "fn main() {}")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/build.rs", "fn main() {}")
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[lib]
|
|
name = "b"
|
|
plugin = true
|
|
|
|
[dependencies.a]
|
|
path = "../a"
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
p.cargo("build").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_a_lib_with_a_build_command() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
include!(concat!(env!("OUT_DIR"), "/foo.rs"));
|
|
|
|
/// ```
|
|
/// foo::bar();
|
|
/// ```
|
|
pub fn bar() {
|
|
assert_eq!(foo(), 1);
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
fn main() {
|
|
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
fs::write(out.join("foo.rs"), "fn foo() -> i32 { 1 }").unwrap();
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("test").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_dev_dep_build_script() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dev-dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/build.rs", "fn main() {}")
|
|
.file("a/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("test").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_script_with_dynamic_native_dependency() {
|
|
let build = project()
|
|
.at("builder")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "builder"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[lib]
|
|
name = "builder"
|
|
crate-type = ["dylib"]
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "#[no_mangle] pub extern fn foo() {}")
|
|
.build();
|
|
|
|
let foo = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[build-dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file("build.rs", "extern crate bar; fn main() { bar::bar() }")
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"bar/build.rs",
|
|
r#"
|
|
use std::env;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
fn main() {
|
|
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
let root = PathBuf::from(env::var("BUILDER_ROOT").unwrap());
|
|
let file = format!("{}builder{}",
|
|
env::consts::DLL_PREFIX,
|
|
env::consts::DLL_SUFFIX);
|
|
let src = root.join(&file);
|
|
let dst = out_dir.join(&file);
|
|
fs::copy(src, dst).unwrap();
|
|
if cfg!(target_env = "msvc") {
|
|
fs::copy(root.join("builder.dll.lib"),
|
|
out_dir.join("builder.dll.lib")).unwrap();
|
|
}
|
|
println!("cargo::rustc-link-search=native={}", out_dir.display());
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"bar/src/lib.rs",
|
|
r#"
|
|
pub fn bar() {
|
|
#[cfg_attr(not(target_env = "msvc"), link(name = "builder"))]
|
|
#[cfg_attr(target_env = "msvc", link(name = "builder.dll"))]
|
|
extern { fn foo(); }
|
|
unsafe { foo() }
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
build
|
|
.cargo("build -v")
|
|
.env("CARGO_LOG", "cargo::ops::cargo_rustc")
|
|
.run();
|
|
|
|
let root = build.root().join("target").join("debug");
|
|
foo.cargo("build -v")
|
|
.env("BUILDER_ROOT", root)
|
|
.env("CARGO_LOG", "cargo::ops::cargo_rustc")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn profile_and_opt_level_set_correctly() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert_eq!(env::var("OPT_LEVEL").unwrap(), "3");
|
|
assert_eq!(env::var("PROFILE").unwrap(), "release");
|
|
assert_eq!(env::var("DEBUG").unwrap(), "false");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("bench").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn profile_debug_0() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
|
|
[profile.dev]
|
|
debug = 0
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert_eq!(env::var("OPT_LEVEL").unwrap(), "0");
|
|
assert_eq!(env::var("PROFILE").unwrap(), "debug");
|
|
assert_eq!(env::var("DEBUG").unwrap(), "false");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("build").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn build_script_with_lto() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[profile.dev]
|
|
lto = true
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "fn main() {}")
|
|
.build();
|
|
p.cargo("build").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_duplicate_deps() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
|
|
[build-dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
extern crate bar;
|
|
fn main() { bar::do_nothing() }
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
extern crate bar;
|
|
fn main() { bar::do_nothing() }
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn do_nothing() {}")
|
|
.build();
|
|
|
|
p.cargo("build").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cfg_feedback() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "#[cfg(foo)] fn main() {}")
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#,
|
|
)
|
|
.build();
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cfg_override() {
|
|
let target = rustc_host();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "#[cfg(foo)] fn main() {}")
|
|
.file("build.rs", "")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}.a]
|
|
rustc-cfg = ["foo"]
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cfg_test() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
///
|
|
/// ```
|
|
/// extern crate foo;
|
|
///
|
|
/// fn main() {
|
|
/// foo::foo()
|
|
/// }
|
|
/// ```
|
|
///
|
|
#[cfg(foo)]
|
|
pub fn foo() {}
|
|
|
|
#[cfg(foo)]
|
|
#[test]
|
|
fn test_foo() {
|
|
foo()
|
|
}
|
|
"#,
|
|
)
|
|
.file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}")
|
|
.build();
|
|
p.cargo("test -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] [..] build.rs [..]
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] [..] --cfg foo[..]
|
|
[RUNNING] [..] --cfg foo[..]
|
|
[RUNNING] [..] --cfg foo[..]
|
|
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]/foo-[..][EXE]`
|
|
[RUNNING] `[..]/test-[..][EXE]`
|
|
[DOCTEST] foo
|
|
[RUNNING] [..] --cfg foo[..]",
|
|
)
|
|
.with_stdout_contains("test test_foo ... ok")
|
|
.with_stdout_contains("test test_bar ... ok")
|
|
.with_stdout_contains_n("test [..] ... ok", 3)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cfg_doc() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#,
|
|
)
|
|
.file("src/lib.rs", "#[cfg(foo)] pub fn foo() {}")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"bar/build.rs",
|
|
r#"fn main() { println!("cargo::rustc-cfg=bar"); }"#,
|
|
)
|
|
.file("bar/src/lib.rs", "#[cfg(bar)] pub fn bar() {}")
|
|
.build();
|
|
p.cargo("doc").run();
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
|
|
assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cfg_override_test() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
links = "a"
|
|
"#,
|
|
)
|
|
.file("build.rs", "")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}.a]
|
|
rustc-cfg = ["foo"]
|
|
"#,
|
|
rustc_host()
|
|
),
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
///
|
|
/// ```
|
|
/// extern crate foo;
|
|
///
|
|
/// fn main() {
|
|
/// foo::foo()
|
|
/// }
|
|
/// ```
|
|
///
|
|
#[cfg(foo)]
|
|
pub fn foo() {}
|
|
|
|
#[cfg(foo)]
|
|
#[test]
|
|
fn test_foo() {
|
|
foo()
|
|
}
|
|
"#,
|
|
)
|
|
.file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}")
|
|
.build();
|
|
p.cargo("test -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] `[..]`
|
|
[RUNNING] `[..]`
|
|
[RUNNING] `[..]`
|
|
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]/foo-[..][EXE]`
|
|
[RUNNING] `[..]/test-[..][EXE]`
|
|
[DOCTEST] foo
|
|
[RUNNING] [..] --cfg foo[..]",
|
|
)
|
|
.with_stdout_contains("test test_foo ... ok")
|
|
.with_stdout_contains("test test_bar ... ok")
|
|
.with_stdout_contains_n("test [..] ... ok", 3)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cfg_override_doc() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
links = "a"
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{target}.a]
|
|
rustc-cfg = ["foo"]
|
|
[target.{target}.b]
|
|
rustc-cfg = ["bar"]
|
|
"#,
|
|
target = rustc_host()
|
|
),
|
|
)
|
|
.file("build.rs", "")
|
|
.file("src/lib.rs", "#[cfg(foo)] pub fn foo() {}")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
links = "b"
|
|
"#,
|
|
)
|
|
.file("bar/build.rs", "")
|
|
.file("bar/src/lib.rs", "#[cfg(bar)] pub fn bar() {}")
|
|
.build();
|
|
p.cargo("doc").run();
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
|
|
assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn env_build() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
const FOO: &'static str = env!("FOO");
|
|
fn main() {
|
|
println!("{}", FOO);
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() { println!("cargo::rustc-env=FOO=foo"); }"#,
|
|
)
|
|
.build();
|
|
p.cargo("build -v").run();
|
|
p.cargo("run -v").with_stdout("foo\n").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn env_test() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() { println!("cargo::rustc-env=FOO=foo"); }"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"pub const FOO: &'static str = env!("FOO"); "#,
|
|
)
|
|
.file(
|
|
"tests/test.rs",
|
|
r#"
|
|
extern crate foo;
|
|
|
|
#[test]
|
|
fn test_foo() {
|
|
assert_eq!("foo", foo::FOO);
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("test -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.0.1 ([CWD])
|
|
[RUNNING] [..] build.rs [..]
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] [..] --crate-name foo[..]
|
|
[RUNNING] [..] --crate-name foo[..]
|
|
[RUNNING] [..] --crate-name test[..]
|
|
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]/foo-[..][EXE]`
|
|
[RUNNING] `[..]/test-[..][EXE]`
|
|
[DOCTEST] foo
|
|
[RUNNING] [..] --crate-name foo[..]",
|
|
)
|
|
.with_stdout_contains_n("running 0 tests", 2)
|
|
.with_stdout_contains("test test_foo ... ok")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn env_doc() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
const FOO: &'static str = env!("FOO");
|
|
fn main() {}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() { println!("cargo::rustc-env=FOO=foo"); }"#,
|
|
)
|
|
.build();
|
|
p.cargo("doc -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn flags_go_into_tests() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
b = { path = "b" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("tests/foo.rs", "")
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
[dependencies]
|
|
a = { path = "../a" }
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=test");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("test -v --test=foo")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] a v0.5.0 ([..]
|
|
[RUNNING] `rustc [..] a/build.rs [..]`
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc [..] a/src/lib.rs [..] -L test[..]`
|
|
[COMPILING] b v0.5.0 ([..]
|
|
[RUNNING] `rustc [..] b/src/lib.rs [..] -L test[..]`
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `rustc [..] src/lib.rs [..] -L test[..]`
|
|
[RUNNING] `rustc [..] tests/foo.rs [..] -L test[..]`
|
|
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]/foo-[..][EXE]`",
|
|
)
|
|
.with_stdout_contains("running 0 tests")
|
|
.run();
|
|
|
|
p.cargo("test -v -pb --lib")
|
|
.with_stderr(
|
|
"\
|
|
[FRESH] a v0.5.0 ([..]
|
|
[COMPILING] b v0.5.0 ([..]
|
|
[RUNNING] `rustc [..] b/src/lib.rs [..] -L test[..]`
|
|
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]/b-[..][EXE]`",
|
|
)
|
|
.with_stdout_contains("running 0 tests")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn diamond_passes_args_only_once() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
a = { path = "a" }
|
|
b = { path = "b" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("tests/foo.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
[dependencies]
|
|
b = { path = "../b" }
|
|
c = { path = "../c" }
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
[dependencies]
|
|
c = { path = "../c" }
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.file(
|
|
"c/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "c"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"c/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=native=test");
|
|
}
|
|
"#,
|
|
)
|
|
.file("c/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] c v0.5.0 ([..]
|
|
[RUNNING] `rustc [..]`
|
|
[RUNNING] `[..]`
|
|
[RUNNING] `rustc [..]`
|
|
[COMPILING] b v0.5.0 ([..]
|
|
[RUNNING] `rustc [..]`
|
|
[COMPILING] a v0.5.0 ([..]
|
|
[RUNNING] `rustc [..]`
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `[..]rmeta -L native=test`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn adding_an_override_invalidates() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(".cargo/config", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=native=foo");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `rustc [..]`
|
|
[RUNNING] `[..]`
|
|
[RUNNING] `rustc [..] -L native=foo`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
p.change_file(
|
|
".cargo/config",
|
|
&format!(
|
|
"
|
|
[target.{}.foo]
|
|
rustc-link-search = [\"native=bar\"]
|
|
",
|
|
target
|
|
),
|
|
);
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `rustc [..] -L native=bar`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn changing_an_override_invalidates() {
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
"
|
|
[target.{}.foo]
|
|
rustc-link-search = [\"native=foo\"]
|
|
",
|
|
target
|
|
),
|
|
)
|
|
.file("build.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `rustc [..] -L native=foo`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
p.change_file(
|
|
".cargo/config",
|
|
&format!(
|
|
"
|
|
[target.{}.foo]
|
|
rustc-link-search = [\"native=bar\"]
|
|
",
|
|
target
|
|
),
|
|
);
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo v0.5.0 ([..]): the precalculated components changed
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `rustc [..] -L native=bar`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn fresh_builds_possible_with_link_libs() {
|
|
// The bug is non-deterministic. Sometimes you can get a fresh build
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "nativefoo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
"
|
|
[target.{}.nativefoo]
|
|
rustc-link-lib = [\"a\"]
|
|
rustc-link-search = [\"./b\"]
|
|
rustc-flags = \"-l z -L ./\"
|
|
",
|
|
target
|
|
),
|
|
)
|
|
.file("build.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `rustc [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[FRESH] foo v0.5.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn fresh_builds_possible_with_multiple_metadata_overrides() {
|
|
// The bug is non-deterministic. Sometimes you can get a fresh build
|
|
let target = rustc_host();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
"
|
|
[target.{}.foo]
|
|
a = \"\"
|
|
b = \"\"
|
|
c = \"\"
|
|
d = \"\"
|
|
e = \"\"
|
|
",
|
|
target
|
|
),
|
|
)
|
|
.file("build.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([..]
|
|
[RUNNING] `rustc [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[FRESH] foo v0.5.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn generate_good_d_files() {
|
|
// this is here to stop regression on an issue where build.rs rerun-if-changed paths aren't
|
|
// made absolute properly, which in turn interacts poorly with the dep-info-basedir setting,
|
|
// and the dep-info files have other-crate-relative paths spat out in them
|
|
let p = project()
|
|
.file(
|
|
"awoo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "awoo"
|
|
version = "0.5.0"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("awoo/src/lib.rs", "")
|
|
.file(
|
|
"awoo/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rerun-if-changed=build.rs");
|
|
println!("cargo::rerun-if-changed=barkbarkbark");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "meow"
|
|
version = "0.5.0"
|
|
[dependencies]
|
|
awoo = { path = "awoo" }
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
|
|
let dot_d_path = p.bin("meow").with_extension("d");
|
|
println!("*meow at* {:?}", dot_d_path);
|
|
let dot_d = fs::read_to_string(&dot_d_path).unwrap();
|
|
|
|
println!("*.d file content*: {}", &dot_d);
|
|
|
|
assert_match_exact(
|
|
"[..]/target/debug/meow[EXE]: [..]/awoo/barkbarkbark [..]/awoo/build.rs[..]",
|
|
&dot_d,
|
|
);
|
|
|
|
// paths relative to dependency roots should not be allowed
|
|
assert!(!dot_d
|
|
.split_whitespace()
|
|
.any(|v| v == "barkbarkbark" || v == "build.rs"));
|
|
|
|
p.change_file(
|
|
".cargo/config.toml",
|
|
r#"
|
|
[build]
|
|
dep-info-basedir="."
|
|
"#,
|
|
);
|
|
p.cargo("build -v").run();
|
|
|
|
let dot_d = fs::read_to_string(&dot_d_path).unwrap();
|
|
|
|
println!("*.d file content with dep-info-basedir*: {}", &dot_d);
|
|
|
|
assert_match_exact(
|
|
"target/debug/meow[EXE]: awoo/barkbarkbark awoo/build.rs[..]",
|
|
&dot_d,
|
|
);
|
|
|
|
// paths relative to dependency roots should not be allowed
|
|
assert!(!dot_d
|
|
.split_whitespace()
|
|
.any(|v| v == "barkbarkbark" || v == "build.rs"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn generate_good_d_files_for_external_tools() {
|
|
// This tests having a relative paths going out of the
|
|
// project root in config's dep-info-basedir
|
|
let p = project_in("rust_things")
|
|
.file(
|
|
"awoo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "awoo"
|
|
version = "0.5.0"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("awoo/src/lib.rs", "")
|
|
.file(
|
|
"awoo/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rerun-if-changed=build.rs");
|
|
println!("cargo::rerun-if-changed=barkbarkbark");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "meow"
|
|
version = "0.5.0"
|
|
[dependencies]
|
|
awoo = { path = "awoo" }
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file(
|
|
".cargo/config.toml",
|
|
r#"
|
|
[build]
|
|
dep-info-basedir="../.."
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
|
|
let dot_d_path = p.bin("meow").with_extension("d");
|
|
let dot_d = fs::read_to_string(&dot_d_path).unwrap();
|
|
|
|
println!("*.d file content with dep-info-basedir*: {}", &dot_d);
|
|
|
|
assert_match_exact(
|
|
concat!(
|
|
"rust_things/foo/target/debug/meow[EXE]:",
|
|
" rust_things/foo/awoo/barkbarkbark",
|
|
" rust_things/foo/awoo/build.rs",
|
|
" rust_things/foo/awoo/src/lib.rs",
|
|
" rust_things/foo/src/main.rs",
|
|
),
|
|
&dot_d,
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn rebuild_only_on_explicit_paths() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rerun-if-changed=foo");
|
|
println!("cargo::rerun-if-changed=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
|
|
// files don't exist, so should always rerun if they don't exist
|
|
println!("run without");
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo v0.5.0 ([..]): the file `foo` is missing
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc [..] src/lib.rs [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
sleep_ms(1000);
|
|
p.change_file("foo", "");
|
|
p.change_file("bar", "");
|
|
sleep_ms(1000); // make sure the to-be-created outfile has a timestamp distinct from the infiles
|
|
|
|
// now the exist, so run once, catch the mtime, then shouldn't run again
|
|
println!("run with");
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo v0.5.0 ([..]): the file `foo` has changed ([..])
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc [..] src/lib.rs [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
println!("run with2");
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[FRESH] foo v0.5.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
sleep_ms(1000);
|
|
|
|
// random other files do not affect freshness
|
|
println!("run baz");
|
|
p.change_file("baz", "// modified");
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[FRESH] foo v0.5.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
// but changing dependent files does
|
|
println!("run foo change");
|
|
p.change_file("foo", "// modified");
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo v0.5.0 ([..]): the file `foo` has changed ([..])
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc [..] src/lib.rs [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
// .. as does deleting a file
|
|
println!("run bar delete");
|
|
fs::remove_file(p.root().join("bar")).unwrap();
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[DIRTY] foo v0.5.0 ([..]): the file `bar` is missing
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `[..]/build-script-build`
|
|
[RUNNING] `rustc [..] src/lib.rs [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doctest_receives_build_link_args() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
[dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "bar"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=native=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("test -v")
|
|
.with_stderr_contains(
|
|
"[RUNNING] `rustdoc [..]--crate-name foo --test [..]-L native=bar[..]`",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn please_respect_the_dag() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies]
|
|
a = { path = 'a' }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=native=foo");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "bar"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=native=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr_contains("[RUNNING] `rustc [..] -L native=foo -L native=bar[..]`")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn non_utf8_output() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::io::prelude::*;
|
|
|
|
fn main() {
|
|
let mut out = std::io::stdout();
|
|
// print something that's not utf8
|
|
out.write_all(b"\xff\xff\n").unwrap();
|
|
|
|
// now print some cargo metadata that's utf8
|
|
println!("cargo::rustc-cfg=foo");
|
|
|
|
// now print more non-utf8
|
|
out.write_all(b"\xff\xff\n").unwrap();
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "#[cfg(foo)] fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_target_dir() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
a = { path = "a" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
".cargo/config",
|
|
r#"
|
|
[build]
|
|
target-dir = 'test'
|
|
"#,
|
|
)
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/build.rs", "fn main() {}")
|
|
.file("a/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn panic_abort_with_build_scripts() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[profile.release]
|
|
panic = 'abort'
|
|
|
|
[dependencies]
|
|
a = { path = "a" }
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
"#[allow(unused_extern_crates)] extern crate a;",
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[build-dependencies]
|
|
b = { path = "../b" }
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file(
|
|
"a/build.rs",
|
|
"#[allow(unused_extern_crates)] extern crate b; fn main() {}",
|
|
)
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v --release").run();
|
|
|
|
p.root().join("target").rm_rf();
|
|
|
|
p.cargo("test --release -v")
|
|
.with_stderr_does_not_contain("[..]panic=abort[..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn warnings_emitted() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::warning=foo");
|
|
println!("cargo::warning=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `rustc [..]`
|
|
[RUNNING] `[..]`
|
|
warning: foo@0.5.0: foo
|
|
warning: foo@0.5.0: bar
|
|
[RUNNING] `rustc [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn warnings_emitted_when_build_script_panics() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::warning=foo");
|
|
println!("cargo::warning=bar");
|
|
panic!();
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stdout("")
|
|
.with_stderr_contains("warning: foo@0.5.0: foo\nwarning: foo@0.5.0: bar")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn warnings_hidden_for_upstream() {
|
|
Package::new("bar", "0.1.0")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::warning=foo");
|
|
println!("cargo::warning=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "*"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr(
|
|
"\
|
|
[UPDATING] `[..]` index
|
|
[DOWNLOADING] crates ...
|
|
[DOWNLOADED] bar v0.1.0 ([..])
|
|
[COMPILING] bar v0.1.0
|
|
[RUNNING] `rustc [..]`
|
|
[RUNNING] `[..]`
|
|
[RUNNING] `rustc [..]`
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `rustc [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn warnings_printed_on_vv() {
|
|
Package::new("bar", "0.1.0")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::warning=foo");
|
|
println!("cargo::warning=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "*"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build -vv")
|
|
.with_stderr(
|
|
"\
|
|
[UPDATING] `[..]` index
|
|
[DOWNLOADING] crates ...
|
|
[DOWNLOADED] bar v0.1.0 ([..])
|
|
[COMPILING] bar v0.1.0
|
|
[RUNNING] `[..] rustc [..]`
|
|
[RUNNING] `[..]`
|
|
warning: bar@0.1.0: foo
|
|
warning: bar@0.1.0: bar
|
|
[RUNNING] `[..] rustc [..]`
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `[..] rustc [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn output_shows_on_vv() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::io::prelude::*;
|
|
|
|
fn main() {
|
|
std::io::stderr().write_all(b"stderr\n").unwrap();
|
|
std::io::stdout().write_all(b"stdout\n").unwrap();
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -vv")
|
|
.with_stdout("[foo 0.5.0] stdout")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo v0.5.0 ([..])
|
|
[RUNNING] `[..] rustc [..]`
|
|
[RUNNING] `[..]`
|
|
[foo 0.5.0] stderr
|
|
[RUNNING] `[..] rustc [..]`
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_with_dots() {
|
|
let target = rustc_host();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
links = "a.b"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-link-search=bar")
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
".cargo/config",
|
|
&format!(
|
|
r#"
|
|
[target.{}.'a.b']
|
|
rustc-link-search = ["foo"]
|
|
"#,
|
|
target
|
|
),
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr_contains("[RUNNING] `rustc --crate-name foo [..] [..] -L foo[..]`")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn rustc_and_rustdoc_set_correctly() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
assert_eq!(env::var("RUSTC").unwrap(), "rustc");
|
|
assert_eq!(env::var("RUSTDOC").unwrap(), "rustdoc");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("bench").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn cfg_env_vars_available() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
|
|
fn main() {
|
|
let fam = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
|
|
if cfg!(unix) {
|
|
assert_eq!(fam, "unix");
|
|
} else {
|
|
assert_eq!(fam, "windows");
|
|
}
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("bench").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn switch_features_rerun() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[features]
|
|
foo = []
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
fn main() {
|
|
println!(include_str!(concat!(env!("OUT_DIR"), "/output")));
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
fn main() {
|
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
let output = Path::new(&out_dir).join("output");
|
|
|
|
if env::var_os("CARGO_FEATURE_FOO").is_some() {
|
|
fs::write(output, "foo").unwrap();
|
|
} else {
|
|
fs::write(output, "bar").unwrap();
|
|
}
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build -v --features=foo").run();
|
|
p.rename_run("foo", "with_foo").with_stdout("foo\n").run();
|
|
p.cargo("build -v").run();
|
|
p.rename_run("foo", "without_foo")
|
|
.with_stdout("bar\n")
|
|
.run();
|
|
p.cargo("build -v --features=foo").run();
|
|
p.rename_run("foo", "with_foo2").with_stdout("foo\n").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn assume_build_script_when_build_rs_present() {
|
|
let p = project()
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
fn main() {
|
|
if ! cfg!(foo) {
|
|
panic!("the build script was not run");
|
|
}
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-cfg=foo");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("run -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn if_build_set_to_false_dont_treat_build_rs_as_build_script() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = false
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
fn main() {
|
|
if cfg!(foo) {
|
|
panic!("the build script was run");
|
|
}
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-cfg=foo");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("run -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn deterministic_rustc_dependency_flags() {
|
|
// This bug is non-deterministic hence the large number of dependencies
|
|
// in the hopes it will have a much higher chance of triggering it.
|
|
|
|
Package::new("dep1", "0.1.0")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "dep1"
|
|
version = "0.1.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-flags=-L native=test1");
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
Package::new("dep2", "0.1.0")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "dep2"
|
|
version = "0.1.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-flags=-L native=test2");
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
Package::new("dep3", "0.1.0")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "dep3"
|
|
version = "0.1.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-flags=-L native=test3");
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
Package::new("dep4", "0.1.0")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "dep4"
|
|
version = "0.1.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-flags=-L native=test4");
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
dep1 = "*"
|
|
dep2 = "*"
|
|
dep3 = "*"
|
|
dep4 = "*"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("build -v")
|
|
.with_stderr_contains(
|
|
"\
|
|
[RUNNING] `rustc --crate-name foo [..] -L native=test1 -L native=test2 \
|
|
-L native=test3 -L native=test4`
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_duplicates_with_cycle() {
|
|
// this tests that the links_duplicates are caught at resolver time
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
build = "build.rs"
|
|
|
|
[dependencies.a]
|
|
path = "a"
|
|
|
|
[dev-dependencies]
|
|
b = { path = "b" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "a"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file("a/build.rs", "")
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
foo = { path = ".." }
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build").with_status(101)
|
|
.with_stderr("\
|
|
error: failed to select a version for `a`.
|
|
... required by package `foo v0.5.0 ([..])`
|
|
versions that meet the requirements `*` are: 0.5.0
|
|
|
|
the package `a` links to the native library `a`, but it conflicts with a previous package which links to `a` as well:
|
|
package `foo v0.5.0 ([..])`
|
|
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = \"a\"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
|
|
|
|
failed to select a version for `a` which could resolve this conflict
|
|
").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn rename_with_link_search_path() {
|
|
_rename_with_link_search_path(false);
|
|
}
|
|
|
|
#[cargo_test]
|
|
#[cfg_attr(
|
|
target_os = "macos",
|
|
ignore = "don't have a cdylib cross target on macos"
|
|
)]
|
|
fn rename_with_link_search_path_cross() {
|
|
if cross_compile::disabled() {
|
|
return;
|
|
}
|
|
|
|
_rename_with_link_search_path(true);
|
|
}
|
|
|
|
fn _rename_with_link_search_path(cross: bool) {
|
|
let target_arg = if cross {
|
|
format!(" --target={}", cross_compile::alternate())
|
|
} else {
|
|
"".to_string()
|
|
};
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[lib]
|
|
crate-type = ["cdylib"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
"#[no_mangle] pub extern fn cargo_test_foo() {}",
|
|
);
|
|
let p = p.build();
|
|
|
|
p.cargo(&format!("build{}", target_arg)).run();
|
|
|
|
let p2 = project()
|
|
.at("bar")
|
|
.file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
fn main() {
|
|
// Move the `libfoo.so` from the root of our project into the
|
|
// build directory. This way Cargo should automatically manage
|
|
// `LD_LIBRARY_PATH` and such.
|
|
let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
|
|
let file = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);
|
|
let src = root.join(&file);
|
|
|
|
let dst_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
|
let dst = dst_dir.join(&file);
|
|
|
|
fs::copy(&src, &dst).unwrap();
|
|
// handle windows, like below
|
|
drop(fs::copy(root.join("foo.dll.lib"), dst_dir.join("foo.dll.lib")));
|
|
|
|
println!("cargo::rerun-if-changed=build.rs");
|
|
if cfg!(target_env = "msvc") {
|
|
println!("cargo::rustc-link-lib=foo.dll");
|
|
} else {
|
|
println!("cargo::rustc-link-lib=foo");
|
|
}
|
|
println!("cargo::rustc-link-search=all={}",
|
|
dst.parent().unwrap().display());
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
extern {
|
|
#[link_name = "cargo_test_foo"]
|
|
fn foo();
|
|
}
|
|
|
|
fn main() {
|
|
unsafe { foo(); }
|
|
}
|
|
"#,
|
|
);
|
|
let p2 = p2.build();
|
|
|
|
// Move the output `libfoo.so` into the directory of `p2`, and then delete
|
|
// the `p` project. On macOS, the `libfoo.dylib` artifact references the
|
|
// original path in `p` so we want to make sure that it can't find it (hence
|
|
// the deletion).
|
|
let root = if cross {
|
|
p.root()
|
|
.join("target")
|
|
.join(cross_compile::alternate())
|
|
.join("debug")
|
|
.join("deps")
|
|
} else {
|
|
p.root().join("target").join("debug").join("deps")
|
|
};
|
|
let file = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);
|
|
let src = root.join(&file);
|
|
|
|
let dst = p2.root().join(&file);
|
|
|
|
fs::copy(&src, &dst).unwrap();
|
|
// copy the import library for windows, if it exists
|
|
drop(fs::copy(
|
|
&root.join("foo.dll.lib"),
|
|
p2.root().join("foo.dll.lib"),
|
|
));
|
|
remove_dir_all(p.root()).unwrap();
|
|
|
|
// Everything should work the first time
|
|
p2.cargo(&format!("run{}", target_arg)).run();
|
|
|
|
// Now rename the root directory and rerun `cargo run`. Not only should we
|
|
// not build anything but we also shouldn't crash.
|
|
let mut new = p2.root();
|
|
new.pop();
|
|
new.push("bar2");
|
|
|
|
// For whatever reason on Windows right after we execute a binary it's very
|
|
// unlikely that we're able to successfully delete or rename that binary.
|
|
// It's not really clear why this is the case or if it's a bug in Cargo
|
|
// holding a handle open too long. In an effort to reduce the flakiness of
|
|
// this test though we throw this in a loop
|
|
//
|
|
// For some more information see #5481 and rust-lang/rust#48775
|
|
let mut i = 0;
|
|
loop {
|
|
let error = match fs::rename(p2.root(), &new) {
|
|
Ok(()) => break,
|
|
Err(e) => e,
|
|
};
|
|
i += 1;
|
|
if !cfg!(windows) || error.kind() != io::ErrorKind::PermissionDenied || i > 10 {
|
|
panic!("failed to rename: {}", error);
|
|
}
|
|
println!("assuming {} is spurious, waiting to try again", error);
|
|
thread::sleep(slow_cpu_multiplier(100));
|
|
}
|
|
|
|
p2.cargo(&format!("run{}", target_arg))
|
|
.cwd(&new)
|
|
.with_stderr(
|
|
"\
|
|
[FINISHED] [..]
|
|
[RUNNING] [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn optional_build_script_dep() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = { path = "bar", optional = true }
|
|
|
|
[build-dependencies]
|
|
bar = { path = "bar", optional = true }
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
#[cfg(feature = "bar")]
|
|
extern crate bar;
|
|
|
|
fn main() {
|
|
#[cfg(feature = "bar")] {
|
|
println!("cargo::rustc-env=FOO={}", bar::bar());
|
|
return
|
|
}
|
|
println!("cargo::rustc-env=FOO=0");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
#[cfg(feature = "bar")]
|
|
extern crate bar;
|
|
|
|
fn main() {
|
|
println!("{}", env!("FOO"));
|
|
}
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() -> u32 { 1 }");
|
|
let p = p.build();
|
|
|
|
p.cargo("run").with_stdout("0\n").run();
|
|
p.cargo("run --features bar").with_stdout("1\n").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn optional_build_dep_and_required_normal_dep() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = { path = "./bar", optional = true }
|
|
|
|
[build-dependencies]
|
|
bar = { path = "./bar" }
|
|
"#,
|
|
)
|
|
.file("build.rs", "extern crate bar; fn main() { bar::bar(); }")
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
#[cfg(feature = "bar")]
|
|
extern crate bar;
|
|
|
|
fn main() {
|
|
#[cfg(feature = "bar")] {
|
|
println!("{}", bar::bar());
|
|
}
|
|
#[cfg(not(feature = "bar"))] {
|
|
println!("0");
|
|
}
|
|
}
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() -> u32 { 1 }");
|
|
let p = p.build();
|
|
|
|
p.cargo("run")
|
|
.with_stdout("0")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] bar v0.5.0 ([..])
|
|
[COMPILING] foo v0.1.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]foo[EXE]`",
|
|
)
|
|
.run();
|
|
|
|
p.cargo("run --all-features")
|
|
.with_stdout("1")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] bar v0.5.0 ([..])
|
|
[COMPILING] foo v0.1.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
[RUNNING] `[..]foo[EXE]`",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn using_rerun_if_changed_does_not_rebuild() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rerun-if-changed=build.rs");
|
|
}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("build").run();
|
|
p.cargo("build").with_stderr("[FINISHED] [..]").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn links_interrupted_can_restart() {
|
|
// Test for a `links` dependent build script getting canceled and then
|
|
// restarted. Steps:
|
|
// 1. Build to establish fingerprints.
|
|
// 2. Change something (an env var in this case) that triggers the
|
|
// dependent build script to run again. Kill the top-level build script
|
|
// while it is running (such as hitting Ctrl-C).
|
|
// 3. Run the build again, it should re-run the build script.
|
|
let bar = project()
|
|
.at("bar")
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.5.0"
|
|
authors = []
|
|
links = "foo"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rerun-if-env-changed=SOMEVAR");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
|
|
[dependencies.bar]
|
|
path = '{}'
|
|
"#,
|
|
bar.root().display()
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
use std::env;
|
|
fn main() {
|
|
println!("cargo::metadata=rebuild-if-changed=build.rs");
|
|
if std::path::Path::new("abort").exists() {
|
|
panic!("Crash!");
|
|
}
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build").run();
|
|
// Simulate the user hitting Ctrl-C during a build.
|
|
p.change_file("abort", "");
|
|
// Set SOMEVAR to trigger a rebuild.
|
|
p.cargo("build")
|
|
.env("SOMEVAR", "1")
|
|
.with_stderr_contains("[..]Crash![..]")
|
|
.with_status(101)
|
|
.run();
|
|
fs::remove_file(p.root().join("abort")).unwrap();
|
|
// Try again without aborting the script.
|
|
// ***This is currently broken, the script does not re-run.
|
|
p.cargo("build -v")
|
|
.env("SOMEVAR", "1")
|
|
.with_stderr_contains("[RUNNING] [..]/foo-[..]/build-script-build[..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn dev_dep_with_links() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
authors = []
|
|
links = "x"
|
|
|
|
[dev-dependencies]
|
|
bar = { path = "./bar" }
|
|
"#,
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
authors = []
|
|
links = "y"
|
|
|
|
[dependencies]
|
|
foo = { path = ".." }
|
|
"#,
|
|
)
|
|
.file("bar/build.rs", "fn main() {}")
|
|
.file("bar/src/lib.rs", "")
|
|
.build();
|
|
p.cargo("check --tests").run()
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn rerun_if_directory() {
|
|
if !symlink_supported() {
|
|
return;
|
|
}
|
|
|
|
// rerun-if-changed of a directory should rerun if any file in the directory changes.
|
|
let p = project()
|
|
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rerun-if-changed=somedir");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
let dirty = |dirty_line: &str, compile_build_script: bool| {
|
|
let mut dirty_line = dirty_line.to_string();
|
|
|
|
if !dirty_line.is_empty() {
|
|
dirty_line.push('\n');
|
|
}
|
|
|
|
let compile_build_script_line = if compile_build_script {
|
|
"[RUNNING] `rustc --crate-name build_script_build [..]\n"
|
|
} else {
|
|
""
|
|
};
|
|
|
|
p.cargo("check -v")
|
|
.with_stderr(format!(
|
|
"\
|
|
{dirty_line}\
|
|
[COMPILING] foo [..]
|
|
{compile_build_script_line}\
|
|
[RUNNING] `[..]build-script-build[..]`
|
|
[RUNNING] `rustc --crate-name foo [..]
|
|
[FINISHED] [..]",
|
|
))
|
|
.run();
|
|
};
|
|
|
|
let fresh = || {
|
|
p.cargo("check").with_stderr("[FINISHED] [..]").run();
|
|
};
|
|
|
|
// Start with a missing directory.
|
|
dirty("", true);
|
|
// Because the directory doesn't exist, it will trigger a rebuild every time.
|
|
// https://github.com/rust-lang/cargo/issues/6003
|
|
dirty(
|
|
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` is missing",
|
|
false,
|
|
);
|
|
|
|
if is_coarse_mtime() {
|
|
sleep_ms(1000);
|
|
}
|
|
|
|
// Empty directory.
|
|
fs::create_dir(p.root().join("somedir")).unwrap();
|
|
dirty(
|
|
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
|
false,
|
|
);
|
|
fresh();
|
|
|
|
if is_coarse_mtime() {
|
|
sleep_ms(1000);
|
|
}
|
|
|
|
// Add a file.
|
|
p.change_file("somedir/foo", "");
|
|
p.change_file("somedir/bar", "");
|
|
dirty(
|
|
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
|
false,
|
|
);
|
|
fresh();
|
|
|
|
if is_coarse_mtime() {
|
|
sleep_ms(1000);
|
|
}
|
|
|
|
// Add a symlink.
|
|
p.symlink("foo", "somedir/link");
|
|
dirty(
|
|
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
|
false,
|
|
);
|
|
fresh();
|
|
|
|
if is_coarse_mtime() {
|
|
sleep_ms(1000);
|
|
}
|
|
|
|
// Move the symlink.
|
|
fs::remove_file(p.root().join("somedir/link")).unwrap();
|
|
p.symlink("bar", "somedir/link");
|
|
dirty(
|
|
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
|
false,
|
|
);
|
|
fresh();
|
|
|
|
if is_coarse_mtime() {
|
|
sleep_ms(1000);
|
|
}
|
|
|
|
// Remove a file.
|
|
fs::remove_file(p.root().join("somedir/foo")).unwrap();
|
|
dirty(
|
|
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
|
false,
|
|
);
|
|
fresh();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn rerun_if_published_directory() {
|
|
// build script of a dependency contains a `rerun-if-changed` pointing to a directory
|
|
Package::new("mylib-sys", "1.0.0")
|
|
.file("mylib/balrog.c", "")
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
// Changing to mylib/balrog.c will not trigger a rebuild
|
|
println!("cargo::rerun-if-changed=mylib");
|
|
}
|
|
"#,
|
|
)
|
|
.publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
|
|
[dependencies]
|
|
mylib-sys = "1.0.0"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("check").run();
|
|
|
|
// Delete regitry src to make directories being recreated with the latest timestamp.
|
|
cargo_home().join("registry/src").rm_rf();
|
|
|
|
p.cargo("check --verbose")
|
|
.with_stderr(
|
|
"\
|
|
[FRESH] mylib-sys v1.0.0
|
|
[FRESH] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
// Upgrade of a package should still trigger a rebuild
|
|
Package::new("mylib-sys", "1.0.1")
|
|
.file("mylib/balrog.c", "")
|
|
.file("mylib/balrog.h", "")
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rerun-if-changed=mylib");
|
|
}
|
|
"#,
|
|
)
|
|
.publish();
|
|
p.cargo("update").run();
|
|
p.cargo("fetch").run();
|
|
|
|
p.cargo("check -v")
|
|
.with_stderr(format!(
|
|
"\
|
|
[COMPILING] mylib-sys [..]
|
|
[RUNNING] `rustc --crate-name build_script_build [..]
|
|
[RUNNING] `[..]build-script-build[..]`
|
|
[RUNNING] `rustc --crate-name mylib_sys [..]
|
|
[CHECKING] foo [..]
|
|
[RUNNING] `rustc --crate-name foo [..]
|
|
[FINISHED] [..]",
|
|
))
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_with_dep_metadata() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
bar = { path = 'bar' }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
assert_eq!(std::env::var("DEP_BAR_FOO").unwrap(), "bar");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
links = 'bar'
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "")
|
|
.file(
|
|
"bar/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::metadata=foo=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("test --lib").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn duplicate_script_with_extra_env() {
|
|
// Test where a build script is run twice, that emits different rustc-env
|
|
// and rustc-cfg values. In this case, one is run for host, the other for
|
|
// target.
|
|
if !cross_compile::can_run_on_host() {
|
|
return;
|
|
}
|
|
|
|
let target = cross_compile::alternate();
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo", "pm"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
pm = { path = "../pm" }
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/src/lib.rs",
|
|
&r#"
|
|
//! ```rust
|
|
//! #[cfg(not(mycfg="{target}"))]
|
|
//! compile_error!{"expected mycfg set"}
|
|
//! assert_eq!(env!("CRATE_TARGET"), "{target}");
|
|
//! assert_eq!(std::env::var("CRATE_TARGET").unwrap(), "{target}");
|
|
//! ```
|
|
|
|
#[test]
|
|
fn check_target() {
|
|
#[cfg(not(mycfg="{target}"))]
|
|
compile_error!{"expected mycfg set"}
|
|
// Compile-time assertion.
|
|
assert_eq!(env!("CRATE_TARGET"), "{target}");
|
|
// Run-time assertion.
|
|
assert_eq!(std::env::var("CRATE_TARGET").unwrap(), "{target}");
|
|
}
|
|
"#
|
|
.replace("{target}", target),
|
|
)
|
|
.file(
|
|
"foo/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::rustc-env=CRATE_TARGET={}", std::env::var("TARGET").unwrap());
|
|
println!("cargo::rustc-cfg=mycfg=\"{}\"", std::env::var("TARGET").unwrap());
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"pm/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "pm"
|
|
version = "0.1.0"
|
|
|
|
[lib]
|
|
proc-macro = true
|
|
# This is just here to speed things up.
|
|
doctest = false
|
|
|
|
[dev-dependencies]
|
|
foo = { path = "../foo" }
|
|
"#,
|
|
)
|
|
.file("pm/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("test --workspace --target")
|
|
.arg(&target)
|
|
.with_stdout_contains("test check_target ... ok")
|
|
.run();
|
|
|
|
if cargo_test_support::is_nightly() {
|
|
p.cargo("test --workspace -Z doctest-xcompile --doc --target")
|
|
.arg(&target)
|
|
.masquerade_as_nightly_cargo(&["doctest-xcompile"])
|
|
.with_stdout_contains("test foo/src/lib.rs - (line 2) ... ok")
|
|
.run();
|
|
}
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn wrong_output() {
|
|
let p = project()
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::example");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo [..]
|
|
error: invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo::example`
|
|
Expected a line with `cargo::KEY=VALUE` with an `=` character, but none was found.
|
|
See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
|
|
for more information about build script outputs.
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn custom_build_closes_stdin() {
|
|
// Ensure stdin is closed to prevent deadlock.
|
|
// See https://github.com/rust-lang/cargo/issues/11196
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() {
|
|
let mut line = String::new();
|
|
std::io::stdin().read_line(&mut line).unwrap();
|
|
}"#,
|
|
)
|
|
.build();
|
|
p.cargo("build").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_old_syntax() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
const FOO: &'static str = env!("FOO");
|
|
fn main() {
|
|
println!("{}", FOO);
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() {
|
|
println!("cargo:rustc-env=FOO=foo");
|
|
println!("cargo:foo=foo");
|
|
}"#,
|
|
)
|
|
.build();
|
|
p.cargo("build -v").run();
|
|
p.cargo("run -v").with_stdout("foo\n").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_invalid_old_syntax() {
|
|
// Unexpected metadata value.
|
|
let p = project()
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo:foo");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo [..]
|
|
error: invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo:foo`
|
|
Expected a line with `cargo:KEY=VALUE` with an `=` character, but none was found.
|
|
See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
|
|
for more information about build script outputs.
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_invalid_new_syntax() {
|
|
// Unexpected metadata value.
|
|
let p = project()
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::metadata=foo");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo [..]
|
|
error: invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo::metadata=foo`
|
|
Expected a line with `cargo::metadata=KEY=VALUE` with an `=` character, but none was found.
|
|
See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
|
|
for more information about build script outputs.
|
|
",
|
|
)
|
|
.run();
|
|
// `cargo::` can not be used with the unknown key.
|
|
let p = project()
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::foo=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] foo [..]
|
|
error: invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo::foo=bar`
|
|
Unknown key: `foo`.
|
|
See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
|
|
for more information about build script outputs.
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_new_syntax_with_old_msrv() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = []
|
|
build = "build.rs"
|
|
rust-version = "1.60.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo::metadata=foo=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("build")
|
|
.with_status(101)
|
|
.with_stderr_contains(
|
|
"\
|
|
[COMPILING] foo [..]
|
|
error: the `cargo::` syntax for build script output instructions was added in Rust 1.77.0, \
|
|
but the minimum supported Rust version of `foo v0.5.0 ([ROOT]/foo)` is 1.60.0.
|
|
See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
|
|
for more information about build script outputs.
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn test_old_syntax_with_old_msrv() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
rust-version = "1.60.0"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
const FOO: &'static str = env!("FOO");
|
|
fn main() {
|
|
println!("{}", FOO);
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"build.rs",
|
|
r#"fn main() {
|
|
println!("cargo:rustc-env=FOO=foo");
|
|
println!("cargo:foo=foo");
|
|
}"#,
|
|
)
|
|
.build();
|
|
p.cargo("build -v").run();
|
|
p.cargo("run -v").with_stdout("foo\n").run();
|
|
}
|