-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
For design, see #14125 (comment)
For tracking the artifact-dir side of this, see #6790
Documentation: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-dir
Testing instructions: #14125 (comment)
FCP: #14125 (comment)
Implementation
- unstable build-dir support (Implemented
build.build-dirconfig option #15104) - build-dir templating (Added
build.build_dirtemplating support #15236) -
cargo metadatasupport (Addedbuild_directoryfield to cargo metadata output #15377) - Document
build_directorycargo metadatafield (docs(metadata): Added build_directory to cargo metadata documentation #15410) -
workspace-path-hashshould have symlinks resolved (Added symlink resolution forworkspace-path-hash#15400) - error on unmatched
{,}(Added validation for unmatched brackets in build-dir template #15414) - append
closest_msgto unknown variable error (and maybe list all variables if no match is found?) (Improved error message when build-dir template var is invalid #15418) - call for testing (Redefine
CARGO_TARGET_DIRto be only an artifacts directory #14125 (comment)) - stabilize build-dir
Stabilizing this would also resolve
Known issues:
Decisions
cargo cleanwill clean bothtarget-dirandbuild-dir- Skipping including a
CARGO_BUILD_DIRshortcut forCARGO_BUILD_BUILD_DIR(likeCARGO_TARGET_DIRis a shortcut forCARGO_BUILD_TARGET_DIR)
artifact-dir files:
- build
- binary executable for bin crates
- binary executable for examples
- depinfo files (
.dfiles) for third party build-system integrations (see https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/fingerprint/mod.rs#L194) - Cargo's
--timingsHTML report
cargo package's generated.cratefilescargo docoutput (html/css/js/etc)
build-dir files (intermediate artifacts, build state, caches):
- build
- "pre and non uplifted" binary executables. (ie. bins for
examplesthat contain the hash in the name, bins forbenches, proc macros, build scripts) - other depinfo files (generated by rustc, fingerprint, etc. See https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/fingerprint/mod.rs#L164)
- rlibs and debug info from dependencies
- build script
OUT_DIR - output from proc macros (previously stored in
target/build) - incremental build output from rustc
- fingerprint files used by Cargo for rebuild detection
- Cache of rustc invocations (
.rustc_info.json)
- "pre and non uplifted" binary executables. (ie. bins for
cargo package's scratchpad used for the verify stepCARGO_TARGET_TMPDIRfiles (see rational for this here)- reports generated from
cargo reportlike future-incompat-report
Open questions
- Are we good with the name
build-dir?- Yes, discussed on 2025-03-18
- Should we offer
CARGO_BUILD_DIRas a shortcut toCARGO_BUILD_BUILD_DIR, likeCARGO_TARGET_DIRis forCARGO_BUILD_TARGET_DIR? see Implementedbuild.build-dirconfig option #15104 (comment)- No, discussed on 2025-03-18
- End-users are most likely to set this globally in config
- Env variable is most likely in CI
- Length and "cleaner name" aren't priorities for the target audience, CI
- Should we stick with the name
{workspace-manifest-path-hash}and what should it include? Should we shorten to{workspace-hash}or even just{hash}?- We should drop
manifest, unsure about dropping eitherworkspaceorpath. Users may be confused if they don't realize the path is a part of the hash - Renamed to
workspace-path-hashin fix(build-dir): Renamed workspace-manifest-path-hash to workspace-path-hash #15334
- We should drop
-
Should we include the Cargo version indeferred{workspace-manifest-path-hash}so we get unique whole-target directories for easier cleanup (Garbage collect wholetarget/#13136) - Should we resolve symlinks in workspace manifest-path before generating
{workspace-manifest-path-hash}? See Addedbuild.build_dirtemplating support #15236 (comment)- The cargo team leans towards doing so right now
- As the hash is unspecified, we feel this is a two-way door
- Added symlink resolution for
workspace-path-hash#15400
- Should we keep erroring on unknown template variables? Should we start erroring on unmatch
{? See Addedbuild.build_dirtemplating support #15236 (comment)- Yes, we should error on unknown template variables. It is the least surprising, even if annoying, and provides better error messages (229489e)
- Yes, we should error on unmatched
{. This includes{{; escaping has been deferred (Added validation for unmatched brackets in build-dir template #15414)
- Should we take the advantage to self-ignore
build.build-dir? Make target dir self-ignoring #15061 - Include in
cargo metadata? What about that people need to matchcargo metadataversion againstcargoto get it?- Yes, it should be included in
cargo metadatabut only the current one. Changing the hash on every cargo version has been deferred to reduce the need to providebuild-dirfor all cargo versions - Added
build_directoryfield to cargo metadata output #15377, docs(metadata): Added build_directory to cargo metadata documentation #15410
- Yes, it should be included in
- Should we offer
CARGO_BUILD_TMPDIR, deprecatingCARGO_TARGET_TMPDIR? - should we offer the workspace base name either as a prefix to the hash or as its own variable for making it easier for humans to find delete specific build dirs
Deferred
{workspace-manifest-hash}also hashes the cargo version- Excludes release channel information, including which nightly
- Allows easier cleanup on
rustup update(Garbage collect wholetarget/#13136) - Makes very clear that the hash's meaning is unstable
- Blocked on Garbage collect whole
target/#13136 (maybe more?) to reduce the need for third-party clean up tools which will need to know the path to everybuild-dirfor a workspace
- In templates,
{{is an escaped{- With us erroring on
{, we have the room to allow escaping in the future - We'd like escaping support to be based on use cases and not speculatively developed as
{in paths is rare and this isn't a general path
- With us erroring on
Original Issue:
Problem
There are a couple of issues with the CARGO_TARGET_DIR that are seemingly in conflict with each other:
-
Multiple locations of
targetdirs complicate excluding them from backups and full-disk search, cleanup of the temp files, moving temp files to dedicated partitions, out of slow network drives or container mounts, etc. Users don't like that thetargetdir is huge, and multiple instances of it add up to lot of disk space. Users would prefer a central location to ease management of the temp files, and also to dedupe/reuse dependencies across many projects. -
People (and tools) are relying on a relative
./targetdirectory being present to copy or run built files out of there. Additionally, users may not want to configure a sharedCARGO_TARGET_DIRdue to risk of file name conflicts between projects.
However, the dilemma between 1 and 2 exists only because Cargo uses CARGO_TARGET_DIR for two different roles:
- A cache for all intermediate build products (a place where crates.io crates are built, where compiler-private temp files are) which aren't project-specific, and/or files that users don't need to access directly.
- A location for user-facing final build products (artifacts) that users expect to be there and need to access.
Proposed Solution
So to satisfy both uses, I suggest to change the thinking about what the role of CARGO_TARGET_DIR should be. Instead of thinking where to put the same huge all-purpose mixed CARGO_TARGET_DIR, think how to deduplicate and slim CARGO_TARGET_DIR, and move everything non-user-facing out of it.
Instead of merging or sharding the CARGO_TARGET_DIR as-is with all of its current content, and adding --artifact-dir as a separate place where final products are being copied to — make CARGO_TARGET_DIR to be the artifact dir (without copying).
As long as the CARGO_TARGET_DIR dir is the place for all of the build files, of all crates including all the crates.io and local builds, with all the caches, all the temp junk, then this is going to be a problematic large directory that needs to be managed. But if the purpose of the ./target dir was changed to be only for user-facing files (files that users can name, and would access via ./target path themselves), then this directory would be relatively small, with a good reason to stay workspace-relative.
What isn't an intermediate build product? (and should stay in ./target)
- linked (and stripped) binaries of the current workspace, including binaries for the examples,
- libraries of the current workspace as
.a/.so, wherelib.crate-typecalls for them. Possibly.rlib/.rmetain the future if there's a stable ABI. - linked binaries for tests and benches of the current workspace (to make it easy to launch them under a debugger/profiler, and so they can use relative file paths to read workspace assets).
- debug symbols for all of the above.
.dfiles for all of the above (so that IDEs and other build systems know when to rebuild the artifacts).- if Cargo adds some "staging" directory (a non-private
OUT_DIRforbuild.rs, see Allow build scripts to stage final artifacts #13663), then for build scripts belonging to the current workspace it would be inside./targetas well.
So generally files that users build intentionally, and may want to access directly (run themselves, or package up for distribution) and files that users may need configure their IDE and debugger to find inside the project.
Crates in [patch.crates-io] with a path are a gray area, an might also have their artifacts included in the ./target dir (but in some way that avoids clobbering workspaces' files).
What isn't a final build product, and doesn't belong to ./target:
- anything related to building crates from crates.io, or any other registry (packages with
source = "registry+…") - all
.fingerprintandincrementaldir content of all crates. These are implementation details of the compiler, and nobody should be accessing these directly via./target/…. .ofiles. Users are not supposed to use them directly either (Rust has static libs for this).- proc macro libs. They're not useful without rustc present.
All of these should be built in some other shared build cache dir (one that is not inside CARGO_TARGET_DIR), configurable by a new option/env var.
Registry dependencies would get unique paths derived from rustc version + package IDs + enabled features (so that different crates using different features don't invalidate each others' caches all the time). This would enable sharing built crates.io dependencies across all projects for the same local user, without also causing local workspaces to clobber each others' CARGO_TARGET_DIR/profile/product paths. Temp directories for local projects would need some hashed paths in the shared build/temp dir too.
Advantages
- Such split removes about 90% of the weight from
./targetdirs (forcargoitself, it makes./target/debugwith binaries and tests take 415MB, instead of 4.2GB). This makes cleanup of all the scatteredtargetdirs less of a pressing problem. - The
./targetkeeps relatively few files, and removes high-frequency-churning files out of it, which makes it less of a problem for real-time disk indexing (like search and backups on macOS). - I/O latency of
./targetstops being critical for build speeds, unlike I/O of the incremental cache and rewrites of thousands of.ofiles. It becomes feasible to have project directory on a network drive without overridingCARGO_TARGET_DIR(network filesystems are used by non-Linux systems where tools like Vagrant and Docker have to run full-fat VMs, and can't cheaply share the file system). - It makes
./targetcontain only workspace-unique files, which makes it justified for every workspace to have one. - It enables moving registry deps to a shared build directory, without side effect of local projects overwriting each others' files. Sharing of dependencies matches users' expectation that the same dependencies shouldn't be redundantly rebuilt for each local project.
- It's almost entirely backwards compatible. Users can get the benefits without breaking their existing workflows, post-build scripts, and integrations. It doesn't invalidate documentation/books/tutorials that refer to
target/release/exeetc. - It could be the default behavior, so it could benefit all users without friction of adding
--artifact-diror.cargo/config.
Notes
No response
Metadata
Metadata
Assignees
Labels
Type
Projects
Status