cargo/core/compiler/
layout.rs

1//! Management of the directory layout of a build
2//!
3//! The directory layout is a little tricky at times, hence a separate file to
4//! house this logic. The current layout looks like this:
5//!
6//! ```text
7//! # This is the root directory for all output, the top-level package
8//! # places all of its output here.
9//! target/
10//!
11//!     # Cache of `rustc -Vv` output for performance.
12//!     .rustc-info.json
13//!
14//!     # All final artifacts are linked into this directory from `deps`.
15//!     # Note that named profiles will soon be included as separate directories
16//!     # here. They have a restricted format, similar to Rust identifiers, so
17//!     # Cargo-specific directories added in the future should use some prefix
18//!     # like `.` to avoid name collisions.
19//!     debug/  # or release/
20//!
21//!         # File used to lock the directory to prevent multiple cargo processes
22//!         # from using it at the same time.
23//!         .cargo-lock
24//!
25//!         # Hidden directory that holds all of the fingerprint files for all
26//!         # packages
27//!         .fingerprint/
28//!             # Each package is in a separate directory.
29//!             # Note that different target kinds have different filename prefixes.
30//!             $pkgname-$META/
31//!                 # Set of source filenames for this package.
32//!                 dep-lib-$targetname
33//!                 # Timestamp when this package was last built.
34//!                 invoked.timestamp
35//!                 # The fingerprint hash.
36//!                 lib-$targetname
37//!                 # Detailed information used for logging the reason why
38//!                 # something is being recompiled.
39//!                 lib-$targetname.json
40//!                 # The console output from the compiler. This is cached
41//!                 # so that warnings can be redisplayed for "fresh" units.
42//!                 output-lib-$targetname
43//!
44//!         # This is the root directory for all rustc artifacts except build
45//!         # scripts, examples, and test and bench executables. Almost every
46//!         # artifact should have a metadata hash added to its filename to
47//!         # prevent collisions. One notable exception is dynamic libraries.
48//!         deps/
49//!
50//!             # Each artifact dependency gets in its own directory.
51//!             /artifact/$pkgname-$META/$kind
52//!
53//!         # Root directory for all compiled examples.
54//!         examples/
55//!
56//!         # Directory used to store incremental data for the compiler (when
57//!         # incremental is enabled.
58//!         incremental/
59//!
60//!         # This is the location at which the output of all custom build
61//!         # commands are rooted.
62//!         build/
63//!
64//!             # Each package gets its own directory where its build script and
65//!             # script output are placed
66//!             $pkgname-$META/    # For the build script itself.
67//!                 # The build script executable (name may be changed by user).
68//!                 build-script-build-$META
69//!                 # Hard link to build-script-build-$META.
70//!                 build-script-build
71//!                 # Dependency information generated by rustc.
72//!                 build-script-build-$META.d
73//!                 # Debug information, depending on platform and profile
74//!                 # settings.
75//!                 <debug symbols>
76//!
77//!             # The package shows up twice with two different metadata hashes.
78//!             $pkgname-$META/  # For the output of the build script.
79//!                 # Timestamp when the build script was last executed.
80//!                 invoked.timestamp
81//!                 # Directory where script can output files ($OUT_DIR).
82//!                 out/
83//!                 # Output from the build script.
84//!                 output
85//!                 # Path to `out`, used to help when the target directory is
86//!                 # moved.
87//!                 root-output
88//!                 # Stderr output from the build script.
89//!                 stderr
90//!
91//!     # Output from rustdoc
92//!     doc/
93//!
94//!     # Used by `cargo package` and `cargo publish` to build a `.crate` file.
95//!     package/
96//!
97//!     # Experimental feature for generated build scripts.
98//!     .metabuild/
99//! ```
100//!
101//! When cross-compiling, the layout is the same, except it appears in
102//! `target/$TRIPLE`.
103
104use crate::core::compiler::CompileTarget;
105use crate::core::Workspace;
106use crate::util::{CargoResult, FileLock};
107use cargo_util::paths;
108use std::path::{Path, PathBuf};
109
110/// Contains the paths of all target output locations.
111///
112/// See module docs for more information.
113pub struct Layout {
114    /// The root directory: `/path/to/target`.
115    /// If cross compiling: `/path/to/target/$TRIPLE`.
116    root: PathBuf,
117    /// The final artifact destination: `$root/debug` (or `release`).
118    dest: PathBuf,
119    /// The directory with rustc artifacts: `$dest/deps`
120    deps: PathBuf,
121    /// The directory for build scripts: `$dest/build`
122    build: PathBuf,
123    /// The directory for artifacts, i.e. binaries, cdylibs, staticlibs: `$dest/deps/artifact`
124    artifact: PathBuf,
125    /// The directory for incremental files: `$dest/incremental`
126    incremental: PathBuf,
127    /// The directory for fingerprints: `$dest/.fingerprint`
128    fingerprint: PathBuf,
129    /// The directory for examples: `$dest/examples`
130    examples: PathBuf,
131    /// The directory for rustdoc output: `$root/doc`
132    doc: PathBuf,
133    /// The directory for temporary data of integration tests and benches: `$dest/tmp`
134    tmp: PathBuf,
135    /// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
136    /// struct is `drop`ped.
137    _lock: FileLock,
138}
139
140impl Layout {
141    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
142    ///
143    /// This function will block if the directory is already locked.
144    ///
145    /// `dest` should be the final artifact directory name. Currently either
146    /// "debug" or "release".
147    pub fn new(
148        ws: &Workspace<'_>,
149        target: Option<CompileTarget>,
150        dest: &str,
151    ) -> CargoResult<Layout> {
152        let mut root = ws.target_dir();
153        if let Some(target) = target {
154            root.push(target.short_name());
155        }
156        let dest = root.join(dest);
157        // If the root directory doesn't already exist go ahead and create it
158        // here. Use this opportunity to exclude it from backups as well if the
159        // system supports it since this is a freshly created folder.
160        //
161        paths::create_dir_all_excluded_from_backups_atomic(root.as_path_unlocked())?;
162        // Now that the excluded from backups target root is created we can create the
163        // actual destination (sub)subdirectory.
164        paths::create_dir_all(dest.as_path_unlocked())?;
165
166        // For now we don't do any more finer-grained locking on the artifact
167        // directory, so just lock the entire thing for the duration of this
168        // compile.
169        let lock = dest.open_rw_exclusive_create(".cargo-lock", ws.gctx(), "build directory")?;
170        let root = root.into_path_unlocked();
171        let dest = dest.into_path_unlocked();
172        let deps = dest.join("deps");
173        let artifact = deps.join("artifact");
174
175        Ok(Layout {
176            deps,
177            build: dest.join("build"),
178            artifact,
179            incremental: dest.join("incremental"),
180            fingerprint: dest.join(".fingerprint"),
181            examples: dest.join("examples"),
182            doc: root.join("doc"),
183            tmp: root.join("tmp"),
184            root,
185            dest,
186            _lock: lock,
187        })
188    }
189
190    /// Makes sure all directories stored in the Layout exist on the filesystem.
191    pub fn prepare(&mut self) -> CargoResult<()> {
192        paths::create_dir_all(&self.deps)?;
193        paths::create_dir_all(&self.incremental)?;
194        paths::create_dir_all(&self.fingerprint)?;
195        paths::create_dir_all(&self.examples)?;
196        paths::create_dir_all(&self.build)?;
197
198        Ok(())
199    }
200
201    /// Fetch the destination path for final artifacts  (`/…/target/debug`).
202    pub fn dest(&self) -> &Path {
203        &self.dest
204    }
205    /// Fetch the deps path.
206    pub fn deps(&self) -> &Path {
207        &self.deps
208    }
209    /// Fetch the examples path.
210    pub fn examples(&self) -> &Path {
211        &self.examples
212    }
213    /// Fetch the doc path.
214    pub fn doc(&self) -> &Path {
215        &self.doc
216    }
217    /// Fetch the root path (`/…/target`).
218    pub fn root(&self) -> &Path {
219        &self.root
220    }
221    /// Fetch the incremental path.
222    pub fn incremental(&self) -> &Path {
223        &self.incremental
224    }
225    /// Fetch the fingerprint path.
226    pub fn fingerprint(&self) -> &Path {
227        &self.fingerprint
228    }
229    /// Fetch the build script path.
230    pub fn build(&self) -> &Path {
231        &self.build
232    }
233    /// Fetch the artifact path.
234    pub fn artifact(&self) -> &Path {
235        &self.artifact
236    }
237    /// Create and return the tmp path.
238    pub fn prepare_tmp(&self) -> CargoResult<&Path> {
239        paths::create_dir_all(&self.tmp)?;
240        Ok(&self.tmp)
241    }
242}