Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cargo/core/compiler/build_context/target_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,7 @@ impl RustDocFingerprint {

let fingerprint_path = build_runner
.files()
.host_root()
.host_build_root()
.join(".rustdoc_fingerprint.json");
let write_fingerprint = || -> CargoResult<()> {
paths::write(
Expand Down Expand Up @@ -1181,7 +1181,7 @@ impl RustDocFingerprint {
.bcx
.all_kinds
.iter()
.map(|kind| build_runner.files().layout(*kind).doc())
.map(|kind| build_runner.files().layout(*kind).artifact_dir().doc())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The separation of ArtifactDirLayout and BuildDirLayout makes sense, as it the actually layout of two directories a lot clearer.

However, I feel like it should be opaque to anything outside layout.rs. Other module shouldn't concern where those build caches are actually stored. Exposing fn artifact_dir() and build_dir() seems to expose a bit too many implementation details to me. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I feel like it should be opaque to anything outside layout.rs. Other module shouldn't concern where those build caches are actually stored

I understand where you are coming from but I think exposing artifact_dir vs build_dir is necessary.
We already do that by duplicating functions like examples() and build_examples(). If we keep everything in Layout we would probably eventually end up with root() and build_root(), dest() and build_dest(), etc.
At that point, I think its better to explicitly use the build_dir()/artifact_dir() to avoid confusion as to where the files are going.

Also I found that in most (all?) of the time I knew which directory I wanted move files to and the opaque nature of Layout felt like it was hurting more than it was helping.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For myself, I feel like exposing the split isn't about exposing implementation details but being clearer in communication and thinking about intermediate and final artifacts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair! Thanks for the discussion!

.filter(|path| path.exists())
.try_for_each(|path| clean_doc(path))?;
write_fingerprint()?;
Expand Down
48 changes: 32 additions & 16 deletions src/cargo/core/compiler/build_runner/compilation_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,13 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
// Docscrape units need to have doc/ set as the out_dir so sources for reverse-dependencies
// will be put into doc/ and not into deps/ where the *.examples files are stored.
if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
self.layout(unit.kind).doc().to_path_buf()
self.layout(unit.kind).artifact_dir().doc().to_path_buf()
} else if unit.mode.is_doc_test() {
panic!("doc tests do not have an out dir");
} else if unit.target.is_custom_build() {
self.build_script_dir(unit)
} else if unit.target.is_example() {
self.layout(unit.kind).build_examples().to_path_buf()
self.layout(unit.kind).build_dir().examples().to_path_buf()
} else if unit.artifact.is_true() {
self.artifact_dir(unit)
} else {
Expand Down Expand Up @@ -250,36 +250,41 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {

/// Returns the final artifact path for the host (`/…/target/debug`)
pub fn host_dest(&self) -> &Path {
self.host.dest()
self.host.artifact_dir().dest()
}

/// Returns the root of the build output tree for the host (`/…/target`)
pub fn host_root(&self) -> &Path {
self.host.root()
/// Returns the root of the build output tree for the host (`/…/build-dir`)
pub fn host_build_root(&self) -> &Path {
self.host.build_dir().root()
}

/// Returns the host `deps` directory path.
pub fn host_deps(&self, unit: &Unit) -> PathBuf {
let dir = self.pkg_dir(unit);
self.host.deps(&dir)
self.host.build_dir().deps(&dir)
}

/// Returns the directories where Rust crate dependencies are found for the
/// specified unit.
pub fn deps_dir(&self, unit: &Unit) -> PathBuf {
let dir = self.pkg_dir(unit);
self.layout(unit.kind).deps(&dir)
self.layout(unit.kind).build_dir().deps(&dir)
}

/// Directory where the fingerprint for the given unit should go.
pub fn fingerprint_dir(&self, unit: &Unit) -> PathBuf {
let dir = self.pkg_dir(unit);
self.layout(unit.kind).fingerprint(&dir)
self.layout(unit.kind).build_dir().fingerprint(&dir)
}

/// Directory where incremental output for the given unit should go.
pub fn incremental_dir(&self, unit: &Unit) -> &Path {
self.layout(unit.kind).incremental()
self.layout(unit.kind).build_dir().incremental()
}

/// Directory where timing output should go.
pub fn timings_dir(&self) -> &Path {
self.host.artifact_dir().timings()
}

/// Returns the path for a file in the fingerprint directory.
Expand Down Expand Up @@ -314,7 +319,9 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
assert!(!unit.mode.is_run_custom_build());
assert!(self.metas.contains_key(unit));
let dir = self.pkg_dir(unit);
self.layout(CompileKind::Host).build_script(&dir)
self.layout(CompileKind::Host)
.build_dir()
.build_script(&dir)
}

/// Returns the directory for compiled artifacts files.
Expand All @@ -338,7 +345,11 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
invalid
),
};
self.layout(unit.kind).artifact().join(dir).join(kind)
self.layout(unit.kind)
.build_dir()
.artifact()
.join(dir)
.join(kind)
}

/// Returns the directory where information about running a build script
Expand All @@ -348,7 +359,9 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
assert!(unit.target.is_custom_build());
assert!(unit.mode.is_run_custom_build());
let dir = self.pkg_dir(unit);
self.layout(unit.kind).build_script_execution(&dir)
self.layout(unit.kind)
.build_dir()
.build_script_execution(&dir)
}

/// Returns the "`OUT_DIR`" directory for running a build script.
Expand All @@ -367,7 +380,7 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
bcx: &BuildContext<'_, '_>,
) -> CargoResult<PathBuf> {
assert!(target.is_bin());
let dest = self.layout(kind).dest();
let dest = self.layout(kind).artifact_dir().dest();
let info = bcx.target_data.info(kind);
let (file_types, _) = info
.rustc_outputs(
Expand Down Expand Up @@ -435,11 +448,14 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
let filename = file_type.uplift_filename(&unit.target);
let uplift_path = if unit.target.is_example() {
// Examples live in their own little world.
self.layout(unit.kind).examples().join(filename)
self.layout(unit.kind)
.artifact_dir()
.examples()
.join(filename)
} else if unit.target.is_custom_build() {
self.build_script_dir(unit).join(filename)
} else {
self.layout(unit.kind).dest().join(filename)
self.layout(unit.kind).artifact_dir().dest().join(filename)
};
if from_path == uplift_path {
// This can happen with things like examples that reside in the
Expand Down
4 changes: 2 additions & 2 deletions src/cargo/core/compiler/build_runner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
let layout = files.layout(kind);
self.compilation
.root_output
.insert(kind, layout.dest().to_path_buf());
.insert(kind, layout.artifact_dir().dest().to_path_buf());
if self.bcx.gctx.cli_unstable().build_dir_new_layout {
for (unit, _) in self.bcx.unit_graph.iter() {
let dep_dir = self.files().deps_dir(unit);
Expand All @@ -411,7 +411,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
} else {
self.compilation
.deps_output
.insert(kind, layout.legacy_deps().to_path_buf());
.insert(kind, layout.build_dir().legacy_deps().to_path_buf());
}
}
Ok(())
Expand Down
179 changes: 112 additions & 67 deletions src/cargo/core/compiler/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,38 +111,8 @@ use std::path::{Path, PathBuf};
///
/// See module docs for more information.
pub struct Layout {
/// The root directory: `/path/to/target`.
/// If cross compiling: `/path/to/target/$TRIPLE`.
root: PathBuf,
/// The final artifact destination: `$root/debug` (or `release`).
dest: PathBuf,
/// The directory with rustc artifacts: `$dest/deps`
deps: PathBuf,
/// The directory for build scripts: `$dest/build`
build: PathBuf,
/// The directory for artifacts, i.e. binaries, cdylibs, staticlibs: `$dest/deps/artifact`
artifact: PathBuf,
/// The directory for incremental files: `$dest/incremental`
incremental: PathBuf,
/// The directory for fingerprints: `$dest/.fingerprint`
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`
tmp: PathBuf,
/// 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>,
is_new_layout: bool,
artifact_dir: ArtifactDirLayout,
build_dir: BuildDirLayout,
}

impl Layout {
Expand Down Expand Up @@ -182,9 +152,10 @@ impl Layout {
// For now we don't do any more finer-grained locking on the artifact
// 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 artifact_dir_lock =
dest.open_rw_exclusive_create(".cargo-lock", ws.gctx(), "build directory")?;

let build_lock = if root != build_root {
let build_dir_lock = if root != build_root {
Some(build_dest.open_rw_exclusive_create(
".cargo-lock",
ws.gctx(),
Expand All @@ -201,23 +172,112 @@ impl Layout {
let artifact = deps.join("artifact");

Ok(Layout {
deps,
build: build_dest.join("build"),
artifact,
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: build_root.join("tmp"),
root,
dest,
_lock: lock,
_build_lock: build_lock,
is_new_layout,
artifact_dir: ArtifactDirLayout {
dest: dest.clone(),
examples: dest.join("examples"),
doc: root.join("doc"),
timings: root.join("cargo-timings"),
_lock: artifact_dir_lock,
},
build_dir: BuildDirLayout {
root: build_root.clone(),
deps,
build: build_dest.join("build"),
artifact,
incremental: build_dest.join("incremental"),
fingerprint: build_dest.join(".fingerprint"),
examples: build_dest.join("examples"),
tmp: build_root.join("tmp"),
_lock: build_dir_lock,
is_new_layout,
},
})
}

/// Makes sure all directories stored in the Layout exist on the filesystem.
pub fn prepare(&mut self) -> CargoResult<()> {
self.artifact_dir.prepare()?;
self.build_dir.prepare()?;

Ok(())
}

pub fn artifact_dir(&self) -> &ArtifactDirLayout {
&self.artifact_dir
}

pub fn build_dir(&self) -> &BuildDirLayout {
&self.build_dir
}
}

pub struct ArtifactDirLayout {
/// The final artifact destination: `<artifact-dir>/debug` (or `release`).
dest: PathBuf,
/// The directory for examples
examples: PathBuf,
/// The directory for rustdoc output
doc: PathBuf,
/// The directory for --timings output
timings: PathBuf,
/// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
/// struct is `drop`ped.
_lock: FileLock,
}

impl ArtifactDirLayout {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally prefer impl blocks to be next to their types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can understand keeping it here in this commit to make it easier to review but would be good to move in a follow up commit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, added that change in 6751e46

/// Makes sure all directories stored in the Layout exist on the filesystem.
pub fn prepare(&mut self) -> CargoResult<()> {
paths::create_dir_all(&self.examples)?;

Ok(())
}
/// Fetch the destination path for final artifacts (`/…/target/debug`).
pub fn dest(&self) -> &Path {
&self.dest
}
/// Fetch the examples path.
pub fn examples(&self) -> &Path {
&self.examples
}
/// Fetch the doc path.
pub fn doc(&self) -> &Path {
&self.doc
}
/// Fetch the cargo-timings path.
pub fn timings(&self) -> &Path {
&self.timings
}
}

pub struct BuildDirLayout {
/// The root directory: `/path/to/build-dir`.
/// If cross compiling: `/path/to/build-dir/$TRIPLE`.
root: PathBuf,
/// The directory with rustc artifacts
deps: PathBuf,
/// The primary directory for build files
build: PathBuf,
/// The directory for artifacts, i.e. binaries, cdylibs, staticlibs
artifact: PathBuf,
/// The directory for incremental files
incremental: PathBuf,
/// The directory for fingerprints
fingerprint: PathBuf,
/// The directory for pre-uplifted examples: `build-dir/debug/examples`
examples: PathBuf,
/// The directory for temporary data of integration tests and benches
tmp: PathBuf,
/// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
/// struct is `drop`ped.
///
/// Will be `None` when the build-dir and target-dir are the same path as we cannot
/// lock the same path twice.
_lock: Option<FileLock>,
is_new_layout: bool,
}

impl BuildDirLayout {
/// Makes sure all directories stored in the Layout exist on the filesystem.
pub fn prepare(&mut self) -> CargoResult<()> {
if !self.is_new_layout {
Expand All @@ -226,16 +286,10 @@ impl Layout {
}
paths::create_dir_all(&self.incremental)?;
paths::create_dir_all(&self.examples)?;
paths::create_dir_all(&self.build_examples)?;
paths::create_dir_all(&self.build)?;

Ok(())
}

/// Fetch the destination path for final artifacts (`/…/target/debug`).
pub fn dest(&self) -> &Path {
&self.dest
}
/// Fetch the deps path.
pub fn deps(&self, pkg_dir: &str) -> PathBuf {
if self.is_new_layout {
Expand All @@ -248,22 +302,13 @@ impl Layout {
pub fn legacy_deps(&self) -> &Path {
&self.deps
}
/// Fetch the examples path.
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
}
/// Fetch the root path (`/…/target`).
pub fn root(&self) -> &Path {
&self.root
}
/// Fetch the build examples path.
pub fn examples(&self) -> &Path {
&self.examples
}
/// Fetch the incremental path.
pub fn incremental(&self) -> &Path {
&self.incremental
Expand Down
Loading