diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index 81a2d622c63..cff55cf6f2c 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -53,14 +53,17 @@ pub struct FileType { /// The kind of file. pub flavor: FileFlavor, /// The suffix for the file (for example, `.rlib`). + /// This is an empty string for executables on Unix-like platforms. suffix: String, /// The prefix for the file (for example, `lib`). + /// This is an empty string for things like executables. prefix: String, - // Wasm bin target will generate two files in deps such as - // "web-stuff.js" and "web_stuff.wasm". Note the different usages of - // "-" and "_". should_replace_hyphens is a flag to indicate that - // we need to convert the stem "web-stuff" to "web_stuff", so we - // won't miss "web_stuff.wasm". + /// Flag to convert hyphen to underscore. + /// + /// wasm bin targets will generate two files in deps such as + /// "web-stuff.js" and "web_stuff.wasm". Note the different usages of "-" + /// and "_". This flag indicates that the stem "web-stuff" should be + /// converted to "web_stuff". should_replace_hyphens: bool, } diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index 8c24c2e281b..c3a92f33546 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -22,6 +22,7 @@ pub struct Doctest { /// A structure returning the result of a compilation. pub struct Compilation<'cfg> { /// An array of all tests created during this compilation. + /// `(package, target, path_to_test_exe)` pub tests: Vec<(Package, Target, PathBuf)>, /// An array of all binaries created. diff --git a/src/cargo/core/compiler/context/compilation_files.rs b/src/cargo/core/compiler/context/compilation_files.rs index caf7c5f8be0..f7e0ee7cfb8 100644 --- a/src/cargo/core/compiler/context/compilation_files.rs +++ b/src/cargo/core/compiler/context/compilation_files.rs @@ -145,7 +145,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { /// target. pub fn out_dir(&self, unit: &Unit<'a>) -> PathBuf { if unit.mode.is_doc() { - self.layout(unit.kind).root().parent().unwrap().join("doc") + self.layout(unit.kind).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() { @@ -169,11 +169,6 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { } } - /// Returns the root of the build output tree for the target - pub fn target_root(&self) -> &Path { - self.target.as_ref().unwrap_or(&self.host).dest() - } - /// Returns the root of the build output tree for the host pub fn host_root(&self) -> &Path { self.host.dest() @@ -261,8 +256,8 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { /// (eg a dependent lib). fn link_stem(&self, unit: &Unit<'a>) -> Option<(PathBuf, String)> { let out_dir = self.out_dir(unit); - let bin_stem = self.bin_stem(unit); - let file_stem = self.file_stem(unit); + let bin_stem = self.bin_stem(unit); // Stem without metadata. + let file_stem = self.file_stem(unit); // Stem with metadata. // We currently only lift files up from the `deps` directory. If // it was compiled into something like `example/` or `doc/` then diff --git a/src/cargo/core/compiler/layout.rs b/src/cargo/core/compiler/layout.rs index e4ae2bc5174..e5361b67905 100644 --- a/src/cargo/core/compiler/layout.rs +++ b/src/cargo/core/compiler/layout.rs @@ -8,71 +8,123 @@ //! # places all of its output here. //! target/ //! -//! # This is the root directory for all output of *dependencies* -//! deps/ +//! # Cache of `rustc -Vv` output for performance. +//! .rustc-info.json //! -//! # Root directory for all compiled examples -//! examples/ +//! # All final artifacts are linked into this directory from `deps`. +//! debug/ # or release/ +//! +//! # File used to lock the directory to prevent multiple cargo processes +//! # from using it at the same time. +//! .cargo-lock +//! +//! # Hidden directory that holds all of the fingerprint files for all +//! # packages +//! .fingerprint/ +//! # Each package is in a separate directory. +//! $pkgname-$META/ +//! # Set of source filenames for this package. +//! dep-lib-$pkgname-$META +//! # Timestamp when this package was last built. +//! invoked.timestamp +//! # The fingerprint hash. +//! lib-$pkgname-$META +//! # Detailed information used for logging the reason why +//! # something is being recompiled. +//! lib-$pkgname-$META.json +//! +//! # This is the root directory for all rustc artifacts except build +//! # scripts, examples, and test and bench executables. Almost every +//! # artifact should have a metadata hash added to its filename to +//! # prevent collisions. One notable exception is dynamic libraries. +//! deps/ +//! +//! # Root directory for all compiled examples. +//! examples/ +//! +//! # Directory used to store incremental data for the compiler (when +//! # incremental is enabled. +//! incremental/ //! //! # This is the location at which the output of all custom build -//! # commands are rooted +//! # commands are rooted. //! build/ //! //! # Each package gets its own directory where its build script and //! # script output are placed -//! $pkg1/ -//! $pkg2/ -//! $pkg3/ +//! $pkgname-$META/ # For the build script itself. +//! # The build script executable (name may be changed by user). +//! build-script-build-$META +//! # Hard link to build-script-build-$META. +//! build-script-build +//! # Dependency information generated by rustc. +//! build-script-build-$META.d +//! # Debug information, depending on platform and profile +//! # settings. +//! //! -//! # Each directory package has a `out` directory where output -//! # is placed. +//! # The package shows up twice with two different metadata hashes. +//! $pkgname-$META/ # For the output of the build script. +//! # Timestamp when the build script was last executed. +//! invoked.timestamp +//! # Directory where script can output files ($OUT_DIR). //! out/ +//! # Output from the build script. +//! output +//! # Path to `out`, used to help when the target directory is +//! # moved. +//! root-output +//! # Stderr output from the build script. +//! stderr +//! +//! # Output from rustdoc +//! doc/ //! -//! # This is the location at which the output of all old custom build -//! # commands are rooted -//! native/ -//! -//! # Each package gets its own directory for where its output is -//! # placed. We can't track exactly what's getting put in here, so -//! # we just assume that all relevant output is in these -//! # directories. -//! $pkg1/ -//! $pkg2/ -//! $pkg3/ -//! -//! # Directory used to store incremental data for the compiler (when -//! # incremental is enabled. -//! incremental/ -//! -//! # Hidden directory that holds all of the fingerprint files for all -//! # packages -//! .fingerprint/ +//! # Used by `cargo package` and `cargo publish` to build a `.crate` file. +//! package/ +//! +//! # Experimental feature for generated build scripts. +//! .metabuild/ //! ``` +//! +//! When cross-compiling, the layout is the same, except it appears in +//! `target/$TRIPLE`. use std::fs; use std::io; use std::path::{Path, PathBuf}; use crate::core::Workspace; -use crate::util::{CargoResult, Config, FileLock, Filesystem}; +use crate::util::{CargoResult, FileLock}; /// Contains the paths of all target output locations. /// /// 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, - native: PathBuf, + /// The directory for build scripts: `$dest/build` build: 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 lock file for a build, will be unlocked when this struct is `drop`ped. + /// The directory for rustdoc output: `$root/doc` + doc: PathBuf, + /// The lockfile for a build (`.cargo-lock`). Will be unlocked when this + /// struct is `drop`ped. _lock: FileLock, } pub fn is_bad_artifact_name(name: &str) -> bool { - ["deps", "examples", "build", "native", "incremental"] + ["deps", "examples", "build", "incremental"] .iter() .any(|&reserved| reserved == name) } @@ -82,55 +134,50 @@ impl Layout { /// /// This function will block if the directory is already locked. /// - /// Differs from `at` in that this calculates the root path from the workspace target directory, - /// adding the target triple and the profile (debug, release, ...). + /// `dest` should be the final artifact directory name. Currently either + /// "debug" or "release". pub fn new(ws: &Workspace<'_>, triple: Option<&str>, dest: &str) -> CargoResult { - let mut path = ws.target_dir(); + let mut root = ws.target_dir(); // Flexible target specifications often point at json files, so interpret // the target triple as a Path and then just use the file stem as the // component for the directory name in that case. if let Some(triple) = triple { let triple = Path::new(triple); if triple.extension().and_then(|s| s.to_str()) == Some("json") { - path.push( + root.push( triple .file_stem() .ok_or_else(|| failure::format_err!("invalid target"))?, ); } else { - path.push(triple); + root.push(triple); } } - path.push(dest); - Layout::at(ws.config(), path) - } - - /// Calculate the paths for build output, lock the build directory, and return as a Layout. - /// - /// This function will block if the directory is already locked. - pub fn at(config: &Config, root: Filesystem) -> CargoResult { + 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. - if !root.as_path_unlocked().exists() { - root.create_dir()?; - exclude_from_backups(root.as_path_unlocked()); + if !dest.as_path_unlocked().exists() { + dest.create_dir()?; + exclude_from_backups(dest.as_path_unlocked()); } // 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 = root.open_rw(".cargo-lock", config, "build directory")?; + let lock = dest.open_rw(".cargo-lock", ws.config(), "build directory")?; let root = root.into_path_unlocked(); + let dest = dest.into_path_unlocked(); Ok(Layout { - deps: root.join("deps"), - native: root.join("native"), - build: root.join("build"), - incremental: root.join("incremental"), - fingerprint: root.join(".fingerprint"), - examples: root.join("examples"), + deps: dest.join("deps"), + build: dest.join("build"), + incremental: dest.join("incremental"), + fingerprint: dest.join(".fingerprint"), + examples: dest.join("examples"), + doc: root.join("doc"), root, + dest, _lock: lock, }) } @@ -138,7 +185,6 @@ impl Layout { /// Makes sure all directories stored in the Layout exist on the filesystem. pub fn prepare(&mut self) -> io::Result<()> { mkdir(&self.deps)?; - mkdir(&self.native)?; mkdir(&self.incremental)?; mkdir(&self.fingerprint)?; mkdir(&self.examples)?; @@ -154,9 +200,9 @@ impl Layout { } } - /// Fetch the root path. + /// Fetch the destination path for final artifacts (`/…/target/debug`). pub fn dest(&self) -> &Path { - &self.root + &self.dest } /// Fetch the deps path. pub fn deps(&self) -> &Path { @@ -166,7 +212,11 @@ impl Layout { pub fn examples(&self) -> &Path { &self.examples } - /// Fetch the root path. + /// Fetch the doc path. + pub fn doc(&self) -> &Path { + &self.doc + } + /// Fetch the root path (`/…/target`). pub fn root(&self) -> &Path { &self.root } @@ -178,7 +228,7 @@ impl Layout { pub fn fingerprint(&self) -> &Path { &self.fingerprint } - /// Fetch the build path. + /// Fetch the build script path. pub fn build(&self) -> &Path { &self.build } diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 58763d9750e..14e2f60adad 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -480,6 +480,7 @@ fn link_targets<'a, 'cfg>( })) } +/// Hardlink (file) or symlink (dir) src to dst if possible, otherwise copy it. fn hardlink_or_copy(src: &Path, dst: &Path) -> CargoResult<()> { debug!("linking {} to {}", src.display(), dst.display()); if is_same_file(src, dst).unwrap_or(false) { diff --git a/src/doc/src/reference/manifest.md b/src/doc/src/reference/manifest.md index ea60e8c5578..4839be1257d 100644 --- a/src/doc/src/reference/manifest.md +++ b/src/doc/src/reference/manifest.md @@ -628,7 +628,7 @@ dependencies residing in the workspace directory become members. You can add additional packages to the workspace by listing them in the `members` key. Note that members of the workspaces listed explicitly will also have their path dependencies included in the workspace. Sometimes a package may have a lot of -workspace members and it can be onerous to keep up to date. The path dependency +workspace members and it can be onerous to keep up to date. The `members` list can also use [globs][globs] to match multiple paths. Finally, the `exclude` key can be used to blacklist paths from being included in a workspace. This can be useful if some path dependencies aren't desired to be in the workspace at