Seperated build directory from target directory

This commits implements the seperation of the intermidate artifact
directory (called "build directory") from the target directory. (see #14125)
This commit is contained in:
Ross Sullivan 2025-02-22 14:08:44 +09:00
parent aab7b90818
commit 5874b6f347
No known key found for this signature in database
GPG Key ID: A7D198C212395322
14 changed files with 206 additions and 132 deletions

View File

@ -217,7 +217,7 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
} else if unit.target.is_custom_build() {
self.build_script_dir(unit)
} else if unit.target.is_example() {
self.layout(unit.kind).examples().to_path_buf()
self.layout(unit.kind).build_examples().to_path_buf()
} else if unit.artifact.is_true() {
self.artifact_dir(unit)
} else {

View File

@ -1124,7 +1124,7 @@ fn prepare_metabuild(
let path = unit
.pkg
.manifest()
.metabuild_path(build_runner.bcx.ws.target_dir());
.metabuild_path(build_runner.bcx.ws.build_dir());
paths::create_dir_all(path.parent().unwrap())?;
paths::write_if_changed(path, &output)?;
Ok(())

View File

@ -51,9 +51,9 @@ pub struct RustcDepInfo {
pub enum DepInfoPathType {
/// src/, e.g. src/lib.rs
PackageRootRelative,
/// target/debug/deps/lib...
/// {build-dir}/debug/deps/lib...
/// or an absolute path /.../sysroot/...
TargetRootRelative,
BuildRootRelative,
}
/// Same as [`RustcDepInfo`] except avoids absolute paths as much as possible to
@ -126,7 +126,7 @@ impl EncodedDepInfo {
for _ in 0..nfiles {
let ty = match read_u8(bytes)? {
0 => DepInfoPathType::PackageRootRelative,
1 => DepInfoPathType::TargetRootRelative,
1 => DepInfoPathType::BuildRootRelative,
_ => return None,
};
let path_bytes = read_bytes(bytes)?;
@ -210,7 +210,7 @@ impl EncodedDepInfo {
for (ty, file, checksum_info) in self.files.iter() {
match ty {
DepInfoPathType::PackageRootRelative => dst.push(0),
DepInfoPathType::TargetRootRelative => dst.push(1),
DepInfoPathType::BuildRootRelative => dst.push(1),
}
write_bytes(dst, paths::path2bytes(file)?);
write_bool(dst, checksum_info.is_some());
@ -292,14 +292,14 @@ pub fn translate_dep_info(
cargo_dep_info: &Path,
rustc_cwd: &Path,
pkg_root: &Path,
target_root: &Path,
build_root: &Path,
rustc_cmd: &ProcessBuilder,
allow_package: bool,
env_config: &Arc<HashMap<String, OsString>>,
) -> CargoResult<()> {
let depinfo = parse_rustc_dep_info(rustc_dep_info)?;
let target_root = crate::util::try_canonicalize(target_root)?;
let build_root = crate::util::try_canonicalize(build_root)?;
let pkg_root = crate::util::try_canonicalize(pkg_root)?;
let mut on_disk_info = EncodedDepInfo::default();
on_disk_info.env = depinfo.env;
@ -351,8 +351,8 @@ pub fn translate_dep_info(
let canon_file =
crate::util::try_canonicalize(&abs_file).unwrap_or_else(|_| abs_file.clone());
let (ty, path) = if let Ok(stripped) = canon_file.strip_prefix(&target_root) {
(DepInfoPathType::TargetRootRelative, stripped)
let (ty, path) = if let Ok(stripped) = canon_file.strip_prefix(&build_root) {
(DepInfoPathType::BuildRootRelative, stripped)
} else if let Ok(stripped) = canon_file.strip_prefix(&pkg_root) {
if !allow_package {
return None;
@ -362,7 +362,7 @@ pub fn translate_dep_info(
// It's definitely not target root relative, but this is an absolute path (since it was
// joined to rustc_cwd) and as such re-joining it later to the target root will have no
// effect.
(DepInfoPathType::TargetRootRelative, &*abs_file)
(DepInfoPathType::BuildRootRelative, &*abs_file)
};
Some((ty, path.to_owned()))
};
@ -472,7 +472,7 @@ pub fn parse_rustc_dep_info(rustc_dep_info: &Path) -> CargoResult<RustcDepInfo>
/// indicates that the crate should likely be rebuilt.
pub fn parse_dep_info(
pkg_root: &Path,
target_root: &Path,
build_root: &Path,
dep_info: &Path,
) -> CargoResult<Option<RustcDepInfo>> {
let Ok(data) = paths::read_bytes(dep_info) else {
@ -487,7 +487,7 @@ pub fn parse_dep_info(
ret.files
.extend(info.files.into_iter().map(|(ty, path, checksum_info)| {
(
make_absolute_path(ty, pkg_root, target_root, path),
make_absolute_path(ty, pkg_root, build_root, path),
checksum_info.and_then(|(file_len, checksum)| {
Checksum::from_str(&checksum).ok().map(|c| (file_len, c))
}),
@ -499,13 +499,13 @@ pub fn parse_dep_info(
fn make_absolute_path(
ty: DepInfoPathType,
pkg_root: &Path,
target_root: &Path,
build_root: &Path,
path: PathBuf,
) -> PathBuf {
match ty {
DepInfoPathType::PackageRootRelative => pkg_root.join(path),
// N.B. path might be absolute here in which case the join will have no effect
DepInfoPathType::TargetRootRelative => target_root.join(path),
DepInfoPathType::BuildRootRelative => build_root.join(path),
}
}
@ -678,7 +678,7 @@ mod encoded_dep_info {
fn gen_test(checksum: bool) {
let checksum = checksum.then_some((768, "c01efc669f09508b55eced32d3c88702578a7c3e".into()));
let lib_rs = (
DepInfoPathType::TargetRootRelative,
DepInfoPathType::BuildRootRelative,
PathBuf::from("src/lib.rs"),
checksum.clone(),
);
@ -691,7 +691,7 @@ mod encoded_dep_info {
assert_eq!(EncodedDepInfo::parse(&data).unwrap(), depinfo);
let mod_rs = (
DepInfoPathType::TargetRootRelative,
DepInfoPathType::BuildRootRelative,
PathBuf::from("src/mod.rs"),
checksum.clone(),
);

View File

@ -839,7 +839,7 @@ impl LocalFingerprint {
mtime_cache: &mut HashMap<PathBuf, FileTime>,
checksum_cache: &mut HashMap<PathBuf, Checksum>,
pkg: &Package,
target_root: &Path,
build_root: &Path,
cargo_exe: &Path,
gctx: &GlobalContext,
) -> CargoResult<Option<StaleItem>> {
@ -852,8 +852,8 @@ impl LocalFingerprint {
// the `dep_info` file itself whose mtime represents the start of
// rustc.
LocalFingerprint::CheckDepInfo { dep_info, checksum } => {
let dep_info = target_root.join(dep_info);
let Some(info) = parse_dep_info(pkg_root, target_root, &dep_info)? else {
let dep_info = build_root.join(dep_info);
let Some(info) = parse_dep_info(pkg_root, build_root, &dep_info)? else {
return Ok(Some(StaleItem::MissingFile(dep_info)));
};
for (key, previous) in info.env.iter() {
@ -910,7 +910,7 @@ impl LocalFingerprint {
LocalFingerprint::RerunIfChanged { output, paths } => Ok(find_stale_file(
mtime_cache,
checksum_cache,
&target_root.join(output),
&build_root.join(output),
paths.iter().map(|p| (pkg_root.join(p), None)),
false,
)),
@ -1153,7 +1153,7 @@ impl Fingerprint {
mtime_cache: &mut HashMap<PathBuf, FileTime>,
checksum_cache: &mut HashMap<PathBuf, Checksum>,
pkg: &Package,
target_root: &Path,
build_root: &Path,
cargo_exe: &Path,
gctx: &GlobalContext,
) -> CargoResult<()> {
@ -1261,7 +1261,7 @@ impl Fingerprint {
mtime_cache,
checksum_cache,
pkg,
target_root,
build_root,
cargo_exe,
gctx,
)? {
@ -1449,13 +1449,13 @@ fn calculate(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult
// After we built the initial `Fingerprint` be sure to update the
// `fs_status` field of it.
let target_root = target_root(build_runner);
let build_root = build_root(build_runner);
let cargo_exe = build_runner.bcx.gctx.cargo_exe()?;
fingerprint.check_filesystem(
&mut build_runner.mtime_cache,
&mut build_runner.checksum_cache,
&unit.pkg,
&target_root,
&build_root,
cargo_exe,
build_runner.bcx.gctx,
)?;
@ -1493,7 +1493,7 @@ fn calculate_normal(
};
// Afterwards calculate our own fingerprint information.
let target_root = target_root(build_runner);
let build_root = build_root(build_runner);
let local = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
// rustdoc does not have dep-info files.
let fingerprint = pkg_fingerprint(build_runner.bcx, &unit.pkg).with_context(|| {
@ -1505,7 +1505,7 @@ fn calculate_normal(
vec![LocalFingerprint::Precalculated(fingerprint)]
} else {
let dep_info = dep_info_loc(build_runner, unit);
let dep_info = dep_info.strip_prefix(&target_root).unwrap().to_path_buf();
let dep_info = dep_info.strip_prefix(&build_root).unwrap().to_path_buf();
vec![LocalFingerprint::CheckDepInfo {
dep_info,
checksum: build_runner.bcx.gctx.cli_unstable().checksum_freshness,
@ -1714,7 +1714,7 @@ fn build_script_local_fingerprints(
// longstanding bug, in Cargo. Recent refactorings just made it painfully
// obvious.
let pkg_root = unit.pkg.root().to_path_buf();
let target_dir = target_root(build_runner);
let build_dir = build_root(build_runner);
let env_config = Arc::clone(build_runner.bcx.gctx.env_config()?);
let calculate =
move |deps: &BuildDeps, pkg_fingerprint: Option<&dyn Fn() -> CargoResult<String>>| {
@ -1747,7 +1747,7 @@ fn build_script_local_fingerprints(
// them all here.
Ok(Some(local_fingerprints_deps(
deps,
&target_dir,
&build_dir,
&pkg_root,
&env_config,
)))
@ -1783,7 +1783,7 @@ fn build_script_override_fingerprint(
/// [`RunCustomBuild`]: crate::core::compiler::CompileMode::RunCustomBuild
fn local_fingerprints_deps(
deps: &BuildDeps,
target_root: &Path,
build_root: &Path,
pkg_root: &Path,
env_config: &Arc<HashMap<String, OsString>>,
) -> Vec<LocalFingerprint> {
@ -1796,7 +1796,7 @@ fn local_fingerprints_deps(
// absolute prefixes from them.
let output = deps
.build_script_output
.strip_prefix(target_root)
.strip_prefix(build_root)
.unwrap()
.to_path_buf();
let paths = deps
@ -1854,10 +1854,10 @@ pub fn dep_info_loc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> Path
build_runner.files().fingerprint_file_path(unit, "dep-")
}
/// Returns an absolute path that target directory.
/// Returns an absolute path that build directory.
/// All paths are rewritten to be relative to this.
fn target_root(build_runner: &BuildRunner<'_, '_>) -> PathBuf {
build_runner.bcx.ws.target_dir().into_path_unlocked()
fn build_root(build_runner: &BuildRunner<'_, '_>) -> PathBuf {
build_runner.bcx.ws.build_dir().into_path_unlocked()
}
/// Reads the value from the old fingerprint hash file and compare.

View File

@ -91,7 +91,7 @@ pub struct Diagnostic {
pub level: String,
}
/// The filename in the top-level `target` directory where we store
/// The filename in the top-level `build-dir` directory where we store
/// the report
const FUTURE_INCOMPAT_FILE: &str = ".future-incompat-report.json";
/// Max number of reports to save on disk.
@ -166,7 +166,7 @@ impl OnDiskReports {
}
let on_disk = serde_json::to_vec(&self).unwrap();
if let Err(e) = ws
.target_dir()
.build_dir()
.open_rw_exclusive_create(
FUTURE_INCOMPAT_FILE,
ws.gctx(),
@ -191,7 +191,7 @@ impl OnDiskReports {
/// Loads the on-disk reports.
pub fn load(ws: &Workspace<'_>) -> CargoResult<OnDiskReports> {
let report_file = match ws.target_dir().open_ro_shared(
let report_file = match ws.build_dir().open_ro_shared(
FUTURE_INCOMPAT_FILE,
ws.gctx(),
"Future incompatible report",

View File

@ -128,6 +128,8 @@ pub struct Layout {
fingerprint: PathBuf,
/// The directory for examples: `$dest/examples`
examples: PathBuf,
/// The directory for pre-uplifted examples: `$build-dir/debug/examples`
build_examples: PathBuf,
/// The directory for rustdoc output: `$root/doc`
doc: PathBuf,
/// The directory for temporary data of integration tests and benches: `$dest/tmp`
@ -135,6 +137,11 @@ pub struct Layout {
/// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
/// struct is `drop`ped.
_lock: FileLock,
/// Same as `_lock` but for the build directory.
///
/// Will be `None` when the build-dir and target-dir are the same path as we cannot
/// lock the same path twice.
_build_lock: Option<FileLock>,
}
impl Layout {
@ -150,15 +157,22 @@ impl Layout {
dest: &str,
) -> CargoResult<Layout> {
let mut root = ws.target_dir();
let mut build_root = ws.build_dir();
if let Some(target) = target {
root.push(target.short_name());
build_root.push(target.short_name());
}
let build_dest = build_root.join(dest);
let dest = root.join(dest);
// If the root directory doesn't already exist go ahead and create it
// here. Use this opportunity to exclude it from backups as well if the
// system supports it since this is a freshly created folder.
//
paths::create_dir_all_excluded_from_backups_atomic(root.as_path_unlocked())?;
if root != build_root {
paths::create_dir_all_excluded_from_backups_atomic(build_root.as_path_unlocked())?;
}
// Now that the excluded from backups target root is created we can create the
// actual destination (sub)subdirectory.
paths::create_dir_all(dest.as_path_unlocked())?;
@ -167,23 +181,37 @@ impl Layout {
// directory, so just lock the entire thing for the duration of this
// compile.
let lock = dest.open_rw_exclusive_create(".cargo-lock", ws.gctx(), "build directory")?;
let build_lock = if root != build_root {
Some(build_dest.open_rw_exclusive_create(
".cargo-lock",
ws.gctx(),
"build directory",
)?)
} else {
None
};
let root = root.into_path_unlocked();
let build_root = build_root.into_path_unlocked();
let dest = dest.into_path_unlocked();
let deps = dest.join("deps");
let build_dest = build_dest.as_path_unlocked();
let deps = build_dest.join("deps");
let artifact = deps.join("artifact");
Ok(Layout {
deps,
build: dest.join("build"),
build: build_dest.join("build"),
artifact,
incremental: dest.join("incremental"),
fingerprint: dest.join(".fingerprint"),
incremental: build_dest.join("incremental"),
fingerprint: build_dest.join(".fingerprint"),
examples: dest.join("examples"),
build_examples: build_dest.join("examples"),
doc: root.join("doc"),
tmp: root.join("tmp"),
tmp: build_root.join("tmp"),
root,
dest,
_lock: lock,
_build_lock: build_lock,
})
}
@ -193,6 +221,7 @@ impl Layout {
paths::create_dir_all(&self.incremental)?;
paths::create_dir_all(&self.fingerprint)?;
paths::create_dir_all(&self.examples)?;
paths::create_dir_all(&self.build_examples)?;
paths::create_dir_all(&self.build)?;
Ok(())
@ -210,6 +239,10 @@ impl Layout {
pub fn examples(&self) -> &Path {
&self.examples
}
/// Fetch the build examples path.
pub fn build_examples(&self) -> &Path {
&self.build_examples
}
/// Fetch the doc path.
pub fn doc(&self) -> &Path {
&self.doc

View File

@ -297,7 +297,7 @@ fn rustc(
let exec = exec.clone();
let root_output = build_runner.files().host_dest().to_path_buf();
let target_dir = build_runner.bcx.ws.target_dir().into_path_unlocked();
let build_dir = build_runner.bcx.ws.build_dir().into_path_unlocked();
let pkg_root = unit.pkg.root().to_path_buf();
let cwd = rustc
.get_cwd()
@ -455,7 +455,7 @@ fn rustc(
&dep_info_loc,
&cwd,
&pkg_root,
&target_dir,
&build_dir,
&rustc,
// Do not track source files in the fingerprint for registry dependencies.
is_local,
@ -555,7 +555,7 @@ fn link_targets(
let path = unit
.pkg
.manifest()
.metabuild_path(build_runner.bcx.ws.target_dir());
.metabuild_path(build_runner.bcx.ws.build_dir());
target.set_src_path(TargetSourcePath::Path(path));
}

View File

@ -429,9 +429,7 @@ impl<'gctx> Workspace<'gctx> {
if !self.gctx().cli_unstable().build_dir {
return self.target_dir();
}
self.build_dir
.clone()
.unwrap_or_else(|| self.default_target_dir())
self.build_dir.clone().unwrap_or_else(|| self.target_dir())
}
fn default_target_dir(&self) -> Filesystem {

View File

@ -41,6 +41,7 @@ pub struct CleanContext<'gctx> {
/// Cleans various caches.
pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
let mut target_dir = ws.target_dir();
let mut build_dir = ws.build_dir();
let gctx = opts.gctx;
let mut clean_ctx = CleanContext::new(gctx);
clean_ctx.dry_run = opts.dry_run;
@ -67,6 +68,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
// that profile.
let dir_name = profiles.get_dir_name();
target_dir = target_dir.join(dir_name);
build_dir = build_dir.join(dir_name);
}
// If we have a spec, then we need to delete some packages, otherwise, just
@ -75,7 +77,15 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
// Note that we don't bother grabbing a lock here as we're just going to
// blow it all away anyway.
if opts.spec.is_empty() {
clean_ctx.remove_paths(&[target_dir.into_path_unlocked()])?;
let paths: &[PathBuf] = if gctx.cli_unstable().build_dir && build_dir != target_dir {
&[
target_dir.into_path_unlocked(),
build_dir.into_path_unlocked(),
]
} else {
&[target_dir.into_path_unlocked()]
};
clean_ctx.remove_paths(paths)?;
} else {
clean_specs(
&mut clean_ctx,
@ -222,7 +232,7 @@ fn clean_specs(
.rustc_outputs(mode, target.kind(), triple)?;
let (dir, uplift_dir) = match target.kind() {
TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
(layout.examples(), Some(layout.examples()))
(layout.build_examples(), Some(layout.examples()))
}
// Tests/benchmarks are never uplifted.
TargetKind::Test | TargetKind::Bench => (layout.deps(), None),

View File

@ -217,7 +217,7 @@ fn do_package<'a>(
};
let mut local_reg = if ws.gctx().cli_unstable().package_workspace {
let reg_dir = ws.target_dir().join("package").join("tmp-registry");
let reg_dir = ws.build_dir().join("package").join("tmp-registry");
sid.map(|sid| TmpRegistry::new(ws.gctx(), reg_dir, sid))
.transpose()?
} else {

View File

@ -45,9 +45,11 @@ pub fn run_verify(
tar.file().seek(SeekFrom::Start(0))?;
let f = GzDecoder::new(tar.file());
let dst = tar
.parent()
.join(&format!("{}-{}", pkg.name(), pkg.version()));
let dst = ws.build_dir().as_path_unlocked().join(&format!(
"package/{}-{}",
pkg.name(),
pkg.version()
));
if dst.exists() {
paths::remove_dir_all(&dst)?;
}
@ -63,7 +65,14 @@ pub fn run_verify(
let mut src = PathSource::new(&dst, id, ws.gctx());
let new_pkg = src.root_package()?;
let pkg_fingerprint = hash_all(&dst)?;
let mut ws = Workspace::ephemeral(new_pkg, gctx, None, true)?;
let target_dir = if gctx.cli_unstable().build_dir {
Some(ws.build_dir())
} else {
None
};
let mut ws = Workspace::ephemeral(new_pkg, gctx, target_dir, true)?;
if let Some(local_reg) = local_reg {
ws.add_local_overlay(
local_reg.upstream,

View File

@ -421,11 +421,8 @@ impl GlobalContext {
/// Gets the path to the `rustc` executable.
pub fn load_global_rustc(&self, ws: Option<&Workspace<'_>>) -> CargoResult<Rustc> {
let cache_location = ws.map(|ws| {
ws.target_dir()
.join(".rustc_info.json")
.into_path_unlocked()
});
let cache_location =
ws.map(|ws| ws.build_dir().join(".rustc_info.json").into_path_unlocked());
let wrapper = self.maybe_get_tool("rustc_wrapper", &self.build_config()?.rustc_wrapper);
let rustc_workspace_wrapper = self.maybe_get_tool(
"rustc_workspace_wrapper",

View File

@ -114,7 +114,7 @@ pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions) -> Ca
pub fn path_args(ws: &Workspace<'_>, unit: &Unit) -> (PathBuf, PathBuf) {
let src = match unit.target.src_path() {
TargetSourcePath::Path(path) => path.to_path_buf(),
TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(ws.target_dir()),
TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(ws.build_dir()),
};
assert!(src.is_absolute());
if unit.pkg.package_id().source_id().is_path() {

View File

@ -29,7 +29,7 @@ fn verify_build_dir_is_disabled_by_feature_flag() {
.build();
p.cargo("build")
.masquerade_as_nightly_cargo(&[])
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
@ -48,21 +48,27 @@ fn binary_with_debug() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build")
.masquerade_as_nightly_cargo(&[])
p.cargo("build -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_build_dir_layout(p.root().join("build-dir"), "debug");
assert_artifact_dir_layout(p.root().join("target-dir"), "debug");
assert_exists_patterns_with_base_dir(
&p.root(),
&[
&format!("target-dir/debug/deps/foo*{EXE_SUFFIX}"),
"target-dir/debug/deps/foo*.d",
// Check the pre-uplifted binary in the build-dir
&format!("build-dir/debug/deps/foo*{EXE_SUFFIX}"),
"build-dir/debug/deps/foo*.d",
// Verify the binary was copied to the target-dir
&format!("target-dir/debug/foo{EXE_SUFFIX}"),
"target-dir/debug/foo.d",
],
);
assert_not_exists(&p.root().join("target"));
@ -77,25 +83,29 @@ fn binary_with_release() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build --release")
.masquerade_as_nightly_cargo(&[])
p.cargo("build --release -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "release");
assert_build_dir_layout(p.root().join("build-dir"), "release");
assert_exists(&p.root().join(format!("target-dir/release/foo{EXE_SUFFIX}")));
assert_exists_patterns_with_base_dir(
&p.root(),
&[
&format!("target-dir/release/deps/foo*{EXE_SUFFIX}"),
"target-dir/release/deps/foo*.d",
// Check the pre-uplifted binary in the build-dir
&format!("build-dir/release/deps/foo*{EXE_SUFFIX}"),
"build-dir/release/deps/foo*.d",
// Verify the binary was copied to the target-dir
&format!("target-dir/release/foo{EXE_SUFFIX}"),
"target-dir/release/foo.d",
],
);
assert_not_exists(&p.root().join("target"));
}
#[cargo_test]
@ -157,18 +167,20 @@ fn libs() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build")
.masquerade_as_nightly_cargo(&[])
p.cargo("build -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_build_dir_layout(p.root().join("build-dir"), "debug");
// Verify lib artifacts were copied into the artifact dir
assert_exists_patterns_with_base_dir(&p.root().join("target-dir/debug"), &expected_files);
assert_not_exists(&p.root().join("target"));
}
}
@ -178,8 +190,8 @@ fn should_default_to_target() {
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.build();
p.cargo("build")
.masquerade_as_nightly_cargo(&[])
p.cargo("build -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
@ -193,19 +205,18 @@ fn should_respect_env_var() {
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.build();
p.cargo("build")
.env("CARGO_TARGET_DIR", "target-dir")
.masquerade_as_nightly_cargo(&[])
p.cargo("build -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.env("CARGO_BUILD_BUILD_DIR", "build-dir")
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_exists(&p.root().join(format!("target-dir/debug/foo{EXE_SUFFIX}")));
assert_not_exists(&p.root().join("target"));
assert_build_dir_layout(p.root().join("build-dir"), "debug");
assert_exists(&p.root().join(format!("target/debug/foo{EXE_SUFFIX}")));
}
#[cargo_test]
fn build_script_should_output_to_target_dir() {
fn build_script_should_output_to_build_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file(
@ -225,27 +236,28 @@ fn build_script_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build")
.masquerade_as_nightly_cargo(&[])
p.cargo("build -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_build_dir_layout(p.root().join("build-dir"), "debug");
assert_exists_patterns_with_base_dir(
&p.root(),
&[
&format!("target-dir/debug/build/foo-*/build-script-build{EXE_SUFFIX}"),
"target-dir/debug/build/foo-*/out/foo.txt", // Verify OUT_DIR
&format!("build-dir/debug/build/foo-*/build-script-build{EXE_SUFFIX}"),
"build-dir/debug/build/foo-*/out/foo.txt", // Verify OUT_DIR
],
);
}
#[cargo_test]
fn cargo_tmpdir_should_output_to_target_dir() {
fn cargo_tmpdir_should_output_to_build_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file(
@ -266,21 +278,22 @@ fn cargo_tmpdir_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("test")
.masquerade_as_nightly_cargo(&[])
p.cargo("test -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_exists(&p.root().join(format!("target-dir/tmp/foo.txt")));
assert_build_dir_layout(p.root().join("build-dir"), "debug");
assert_exists(&p.root().join(format!("build-dir/tmp/foo.txt")));
}
#[cargo_test]
fn examples_should_output_to_target_dir() {
fn examples_should_output_to_build_dir_and_uplift_to_target_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file("examples/foo.rs", r#"fn main() { }"#)
@ -289,29 +302,32 @@ fn examples_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build --examples")
.masquerade_as_nightly_cargo(&[])
p.cargo("build --examples -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_build_dir_layout(p.root().join("build-dir"), "debug");
assert_exists_patterns_with_base_dir(
&p.root(),
&[
// uplifted (target-dir)
&format!("target-dir/debug/examples/foo{EXE_SUFFIX}"),
"target-dir/debug/examples/foo.d",
&format!("target-dir/debug/examples/foo*{EXE_SUFFIX}"),
"target-dir/debug/examples/foo*.d",
// pre-uplifted (build-dir)
&format!("build-dir/debug/examples/foo*{EXE_SUFFIX}"),
"build-dir/debug/examples/foo*.d",
],
);
}
#[cargo_test]
fn benches_should_output_to_target_dir() {
fn benches_should_output_to_build_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file("benches/foo.rs", r#"fn main() { }"#)
@ -320,21 +336,22 @@ fn benches_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build --bench=foo")
.masquerade_as_nightly_cargo(&[])
p.cargo("build --bench=foo -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_build_dir_layout(p.root().join("build-dir"), "debug");
assert_exists_patterns_with_base_dir(
&p.root(),
&[
&format!("target-dir/debug/deps/foo*{EXE_SUFFIX}"),
"target-dir/debug/deps/foo*.d",
&format!("build-dir/debug/deps/foo*{EXE_SUFFIX}"),
"build-dir/debug/deps/foo*.d",
],
);
}
@ -348,12 +365,13 @@ fn cargo_doc_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("doc")
.masquerade_as_nightly_cargo(&[])
p.cargo("doc -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
@ -364,7 +382,7 @@ fn cargo_doc_should_output_to_target_dir() {
}
#[cargo_test]
fn cargo_package_should_output_to_target_dir() {
fn cargo_package_should_build_in_build_dir_and_output_to_target_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file(
@ -372,27 +390,31 @@ fn cargo_package_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("package")
.masquerade_as_nightly_cargo(&[])
p.cargo("package -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_build_dir_layout(p.root().join("build-dir"), "debug");
let package_dir = p.root().join("target-dir/package");
assert_exists(&package_dir);
assert_exists(&package_dir.join("foo-0.0.1.crate"));
assert!(package_dir.join("foo-0.0.1.crate").is_file());
assert_exists(&package_dir.join("foo-0.0.1"));
assert!(package_dir.join("foo-0.0.1").is_dir());
let package_artifact_dir = p.root().join("target-dir/package");
assert_exists(&package_artifact_dir);
assert_exists(&package_artifact_dir.join("foo-0.0.1.crate"));
assert!(package_artifact_dir.join("foo-0.0.1.crate").is_file());
let package_build_dir = p.root().join("build-dir/package");
assert_exists(&package_build_dir);
assert_exists(&package_build_dir.join("foo-0.0.1"));
assert!(package_build_dir.join("foo-0.0.1").is_dir());
}
#[cargo_test]
fn cargo_clean_should_clean_the_target_dir() {
fn cargo_clean_should_clean_the_target_dir_and_build_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file(
@ -400,23 +422,25 @@ fn cargo_clean_should_clean_the_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build")
.masquerade_as_nightly_cargo(&[])
p.cargo("build -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert_build_dir_layout(p.root().join("target-dir"), "debug");
assert_build_dir_layout(p.root().join("build-dir"), "debug");
p.cargo("clean")
.masquerade_as_nightly_cargo(&[])
p.cargo("clean -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
assert!(!p.root().join("target-dir").exists());
assert_not_exists(&p.root().join("build-dir"));
assert_not_exists(&p.root().join("target-dir"));
}
#[cargo_test]
@ -428,12 +452,13 @@ fn timings_report_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("build --timings")
.masquerade_as_nightly_cargo(&[])
p.cargo("build --timings -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.enable_mac_dsym()
.run();
@ -444,7 +469,7 @@ fn timings_report_should_output_to_target_dir() {
nightly,
reason = "-Zfuture-incompat-test requires nightly (permanently)"
)]
fn future_incompat_should_output_to_target_dir() {
fn future_incompat_should_output_to_build_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { let x = 1; }"#)
.file(
@ -452,16 +477,18 @@ fn future_incompat_should_output_to_target_dir() {
r#"
[build]
target-dir = "target-dir"
build-dir = "build-dir"
"#,
)
.build();
p.cargo("check")
p.cargo("build -Z build-dir")
.masquerade_as_nightly_cargo(&["build-dir"])
.arg("--future-incompat-report")
.env("RUSTFLAGS", "-Zfuture-incompat-test")
.run();
assert_exists(&p.root().join("target-dir/.future-incompat-report.json"));
assert_exists(&p.root().join("build-dir/.future-incompat-report.json"));
}
#[track_caller]