#
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::Workspace;
    105use crate::core::compiler::CompileTarget;
    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 pre-uplifted examples: `$build-dir/debug/examples`
    132    build_examples: PathBuf,
    133    /// The directory for rustdoc output: `$root/doc`
    134    doc: PathBuf,
    135    /// The directory for temporary data of integration tests and benches: `$dest/tmp`
    136    tmp: PathBuf,
    137    /// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
    138    /// struct is `drop`ped.
    139    _lock: FileLock,
    140    /// Same as `_lock` but for the build directory.
    141    ///
    142    /// Will be `None` when the build-dir and target-dir are the same path as we cannot
    143    /// lock the same path twice.
    144    _build_lock: Option<FileLock>,
    145}
    146
    147impl Layout {
    148    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    149    ///
    150    /// This function will block if the directory is already locked.
    151    ///
    152    /// `dest` should be the final artifact directory name. Currently either
    153    /// "debug" or "release".
    154    pub fn new(
    155        ws: &Workspace<'_>,
    156        target: Option<CompileTarget>,
    157        dest: &str,
    158    ) -> CargoResult<Layout> {
    159        let mut root = ws.target_dir();
    160        let mut build_root = ws.build_dir();
    161        if let Some(target) = target {
    162            root.push(target.short_name());
    163            build_root.push(target.short_name());
    164        }
    165        let build_dest = build_root.join(dest);
    166        let dest = root.join(dest);
    167        // If the root directory doesn't already exist go ahead and create it
    168        // here. Use this opportunity to exclude it from backups as well if the
    169        // system supports it since this is a freshly created folder.
    170        //
    171        paths::create_dir_all_excluded_from_backups_atomic(root.as_path_unlocked())?;
    172        if root != build_root {
    173            paths::create_dir_all_excluded_from_backups_atomic(build_root.as_path_unlocked())?;
    174        }
    175
    176        // Now that the excluded from backups target root is created we can create the
    177        // actual destination (sub)subdirectory.
    178        paths::create_dir_all(dest.as_path_unlocked())?;
    179
    180        // For now we don't do any more finer-grained locking on the artifact
    181        // directory, so just lock the entire thing for the duration of this
    182        // compile.
    183        let lock = dest.open_rw_exclusive_create(".cargo-lock", ws.gctx(), "build directory")?;
    184
    185        let build_lock = if root != build_root {
    186            Some(build_dest.open_rw_exclusive_create(
    187                ".cargo-lock",
    188                ws.gctx(),
    189                "build directory",
    190            )?)
    191        } else {
    192            None
    193        };
    194        let root = root.into_path_unlocked();
    195        let build_root = build_root.into_path_unlocked();
    196        let dest = dest.into_path_unlocked();
    197        let build_dest = build_dest.as_path_unlocked();
    198        let deps = build_dest.join("deps");
    199        let artifact = deps.join("artifact");
    200
    201        Ok(Layout {
    202            deps,
    203            build: build_dest.join("build"),
    204            artifact,
    205            incremental: build_dest.join("incremental"),
    206            fingerprint: build_dest.join(".fingerprint"),
    207            examples: dest.join("examples"),
    208            build_examples: build_dest.join("examples"),
    209            doc: root.join("doc"),
    210            tmp: build_root.join("tmp"),
    211            root,
    212            dest,
    213            _lock: lock,
    214            _build_lock: build_lock,
    215        })
    216    }
    217
    218    /// Makes sure all directories stored in the Layout exist on the filesystem.
    219    pub fn prepare(&mut self) -> CargoResult<()> {
    220        paths::create_dir_all(&self.deps)?;
    221        paths::create_dir_all(&self.incremental)?;
    222        paths::create_dir_all(&self.fingerprint)?;
    223        paths::create_dir_all(&self.examples)?;
    224        paths::create_dir_all(&self.build_examples)?;
    225        paths::create_dir_all(&self.build)?;
    226
    227        Ok(())
    228    }
    229
    230    /// Fetch the destination path for final artifacts  (`/…/target/debug`).
    231    pub fn dest(&self) -> &Path {
    232        &self.dest
    233    }
    234    /// Fetch the deps path.
    235    pub fn deps(&self) -> &Path {
    236        &self.deps
    237    }
    238    /// Fetch the examples path.
    239    pub fn examples(&self) -> &Path {
    240        &self.examples
    241    }
    242    /// Fetch the build examples path.
    243    pub fn build_examples(&self) -> &Path {
    244        &self.build_examples
    245    }
    246    /// Fetch the doc path.
    247    pub fn doc(&self) -> &Path {
    248        &self.doc
    249    }
    250    /// Fetch the root path (`/…/target`).
    251    pub fn root(&self) -> &Path {
    252        &self.root
    253    }
    254    /// Fetch the incremental path.
    255    pub fn incremental(&self) -> &Path {
    256        &self.incremental
    257    }
    258    /// Fetch the fingerprint path.
    259    pub fn fingerprint(&self) -> &Path {
    260        &self.fingerprint
    261    }
    262    /// Fetch the build script path.
    263    pub fn build(&self) -> &Path {
    264        &self.build
    265    }
    266    /// Fetch the artifact path.
    267    pub fn artifact(&self) -> &Path {
    268        &self.artifact
    269    }
    270    /// Create and return the tmp path.
    271    pub fn prepare_tmp(&self) -> CargoResult<&Path> {
    272        paths::create_dir_all(&self.tmp)?;
    273        Ok(&self.tmp)
    274    }
    275}