]> git.proxmox.com Git - cargo.git/blame - src/cargo/core/compiler/layout.rs
Auto merge of #6249 - Eh2406:cleanup, r=alexcrichton
[cargo.git] / src / cargo / core / compiler / layout.rs
CommitLineData
9f5d9b81
AC
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//!
39f0bd47
AC
6//! ```ignore
7//! # This is the root directory for all output, the top-level package
8//! # places all of its output here.
9//! target/
9f5d9b81 10//!
39f0bd47
AC
11//! # This is the root directory for all output of *dependencies*
12//! deps/
9f5d9b81 13//!
e969e495
AC
14//! # Root directory for all compiled examples
15//! examples/
16//!
39f0bd47
AC
17//! # This is the location at which the output of all custom build
18//! # commands are rooted
34ace110
PK
19//! build/
20//!
21//! # Each package gets its own directory where its build script and
22//! # script output are placed
23//! $pkg1/
24//! $pkg2/
25//! $pkg3/
26//!
27//! # Each directory package has a `out` directory where output
28//! # is placed.
29//! out/
30//!
31//! # This is the location at which the output of all old custom build
32//! # commands are rooted
39f0bd47 33//! native/
c2b23512 34//!
39f0bd47
AC
35//! # Each package gets its own directory for where its output is
36//! # placed. We can't track exactly what's getting put in here, so
37//! # we just assume that all relevant output is in these
38//! # directories.
39//! $pkg1/
40//! $pkg2/
41//! $pkg3/
c2b23512 42//!
a5bf3b88
NM
43//! # Directory used to store incremental data for the compiler (when
44//! # incremental is enabled.
45//! incremental/
46//!
39f0bd47
AC
47//! # Hidden directory that holds all of the fingerprint files for all
48//! # packages
49//! .fingerprint/
39f0bd47 50//! ```
9f5d9b81 51
a6dad622 52use std::fs;
a6dad622 53use std::io;
1e682848 54use std::path::{Path, PathBuf};
9f5d9b81 55
41579bad 56use core::Workspace;
1e682848 57use util::{CargoResult, Config, FileLock, Filesystem};
c2b23512 58
72899f5b
RD
59/// Contains the paths of all target output locations.
60///
61/// See module docs for more information.
9f5d9b81 62pub struct Layout {
a6dad622
AC
63 root: PathBuf,
64 deps: PathBuf,
65 native: PathBuf,
66 build: PathBuf,
a5bf3b88 67 incremental: PathBuf,
a6dad622
AC
68 fingerprint: PathBuf,
69 examples: PathBuf,
72899f5b 70 /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
a9fd1c2c 71 _lock: FileLock,
9f5d9b81
AC
72}
73
6633e290
AK
74pub fn is_bad_artifact_name(name: &str) -> bool {
75 ["deps", "examples", "build", "native", "incremental"]
76 .iter()
23591fe5 77 .any(|&reserved| reserved == name)
6633e290
AK
78}
79
9f5d9b81 80impl Layout {
ffd5e0fc 81 /// Calculate the paths for build output, lock the build directory, and return as a Layout.
72899f5b
RD
82 ///
83 /// This function will block if the directory is already locked.
84 ///
ffd5e0fc 85 /// Differs from `at` in that this calculates the root path from the workspace target directory,
72899f5b 86 /// adding the target triple and the profile (debug, release, ...).
1e682848 87 pub fn new(ws: &Workspace, triple: Option<&str>, dest: &str) -> CargoResult<Layout> {
3c9b362b 88 let mut path = ws.target_dir();
29b24cdb
AC
89 // Flexible target specifications often point at filenames, so interpret
90 // the target triple as a Path and then just use the file stem as the
91 // component for the directory name.
92 if let Some(triple) = triple {
1e682848
AC
93 path.push(Path::new(triple)
94 .file_stem()
6999db6f 95 .ok_or_else(|| format_err!("invalid target"))?);
325c5f2d 96 }
14ff482d 97 path.push(dest);
58ddb28a 98 Layout::at(ws.config(), path)
325c5f2d
AC
99 }
100
ffd5e0fc 101 /// Calculate the paths for build output, lock the build directory, and return as a Layout.
72899f5b
RD
102 ///
103 /// This function will block if the directory is already locked.
a9fd1c2c
AC
104 pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
105 // For now we don't do any more finer-grained locking on the artifact
106 // directory, so just lock the entire thing for the duration of this
107 // compile.
82655b46 108 let lock = root.open_rw(".cargo-lock", config, "build directory")?;
a9fd1c2c
AC
109 let root = root.into_path_unlocked();
110
111 Ok(Layout {
9f5d9b81 112 deps: root.join("deps"),
c2b23512 113 native: root.join("native"),
34ace110 114 build: root.join("build"),
a5bf3b88 115 incremental: root.join("incremental"),
79768eb0 116 fingerprint: root.join(".fingerprint"),
e969e495 117 examples: root.join("examples"),
0247dc42 118 root,
a9fd1c2c
AC
119 _lock: lock,
120 })
9f5d9b81
AC
121 }
122
8e0a7cad
K
123 #[cfg(not(target_os = "macos"))]
124 fn exclude_from_backups(&self, _: &Path) {}
125
126 #[cfg(target_os = "macos")]
127 /// Marks files or directories as excluded from Time Machine on macOS
128 ///
129 /// This is recommended to prevent derived/temporary files from bloating backups.
130 fn exclude_from_backups(&self, path: &Path) {
131 use std::ptr;
1e682848 132 use core_foundation::{number, string, url};
8e0a7cad
K
133 use core_foundation::base::TCFType;
134
135 // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
136 let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
d4999dc8
DW
137 let path = url::CFURL::from_path(path, false);
138 if let (Some(path), Ok(is_excluded_key)) = (path, is_excluded_key) {
139 unsafe {
8e0a7cad
K
140 url::CFURLSetResourcePropertyForKey(
141 path.as_concrete_TypeRef(),
142 is_excluded_key.as_concrete_TypeRef(),
143 number::kCFBooleanTrue as *const _,
144 ptr::null_mut(),
145 );
d4999dc8 146 }
8e0a7cad 147 }
d4999dc8
DW
148 // Errors are ignored, since it's an optional feature and failure
149 // doesn't prevent Cargo from working
8e0a7cad
K
150 }
151
72899f5b 152 /// Make sure all directories stored in the Layout exist on the filesystem.
a6dad622 153 pub fn prepare(&mut self) -> io::Result<()> {
97a2f271 154 if fs::metadata(&self.root).is_err() {
82655b46 155 fs::create_dir_all(&self.root)?;
9f5d9b81
AC
156 }
157
8e0a7cad
K
158 self.exclude_from_backups(&self.root);
159
82655b46
SG
160 mkdir(&self.deps)?;
161 mkdir(&self.native)?;
a5bf3b88 162 mkdir(&self.incremental)?;
82655b46
SG
163 mkdir(&self.fingerprint)?;
164 mkdir(&self.examples)?;
165 mkdir(&self.build)?;
9f5d9b81 166
e969e495
AC
167 return Ok(());
168
a6dad622 169 fn mkdir(dir: &Path) -> io::Result<()> {
97a2f271 170 if fs::metadata(&dir).is_err() {
82655b46 171 fs::create_dir(dir)?;
e969e495
AC
172 }
173 Ok(())
174 }
9f5d9b81
AC
175 }
176
72899f5b 177 /// Fetch the root path.
1e682848
AC
178 pub fn dest(&self) -> &Path {
179 &self.root
180 }
72899f5b 181 /// Fetch the deps path.
1e682848
AC
182 pub fn deps(&self) -> &Path {
183 &self.deps
184 }
72899f5b 185 /// Fetch the examples path.
1e682848
AC
186 pub fn examples(&self) -> &Path {
187 &self.examples
188 }
72899f5b 189 /// Fetch the root path.
1e682848
AC
190 pub fn root(&self) -> &Path {
191 &self.root
192 }
72899f5b 193 /// Fetch the incremental path.
1e682848
AC
194 pub fn incremental(&self) -> &Path {
195 &self.incremental
196 }
72899f5b 197 /// Fetch the fingerprint path.
1e682848
AC
198 pub fn fingerprint(&self) -> &Path {
199 &self.fingerprint
200 }
72899f5b 201 /// Fetch the build path.
1e682848
AC
202 pub fn build(&self) -> &Path {
203 &self.build
204 }
9f5d9b81 205}