-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented build.build-dir
config option
#15104
base: master
Are you sure you want to change the base?
Conversation
build.build-dir
config option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just want to make sure I didn't miss something. From what I can tell these directories/files have been removed right?
target/<profile>/.metabuild
target/<profile>/.fingerprint
target/<profile>/deps
target/<profile>/incremental
target/<profile>/build
target/.cargo-lock
target/tmp
target/.rustc_info.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We usually add some tests verifying a nightly flag is really gated.
@@ -290,7 +290,9 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { | |||
}); | |||
} | |||
|
|||
super::output_depinfo(&mut self, unit)?; | |||
if !self.bcx.gctx.cli_unstable().build_dir { | |||
super::output_depinfo(&mut self, unit)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we stop generating this when build-dir
is enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, actually I believe this is a mistake on my part 😅
My original assumption was that the /target/debug/{project-name}.d
file was the same file as /target/debug/deps/{project-name}-{hash}.d
, so I was trying to avoid copying it into target
.
But now that I compared the files they appear to be different so it looks like that was a bad assumption.
I believe this should probably be considered an intermediate build artifact so it should probably be moved to the build-dir
location.
Modifying this file in particular was a bit tricky as it was not just replacing .target_dir()
with .build_dir()
.
I think I will probably need to go to where the OutputFile
is created and modify the hardlink
to be the new build-dir path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this comment I am going to revert this change
Yes, that with the exception of Ideally in the longer term it can be removed in favor of fine grain locking like #4282 So a typical
|
src/doc/src/reference/unstable.md
Outdated
## build-dir | ||
* Original Issue: [#14125](https://github.com/rust-lang/cargo/issues/14125) | ||
* Tracking Issue: [#14125](https://github.com/rust-lang/cargo/issues/14125) | ||
|
||
This feature allows you to specify the directory where intermediate build artifacts will be stored. | ||
The final artifacts will also be contained in this directory but will be hardlinked into the artifact directory (usually `target`) | ||
|
||
This can be specified in `.cargo/config.toml` files using the `build.build-dir`. | ||
|
||
Example: | ||
|
||
```toml | ||
[build] | ||
build-dir = "out" | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you include documentation in this that mirrors what would be in https://doc.rust-lang.org/cargo/reference/config.html
src/cargo/core/compiler/layout.rs
Outdated
/// Same as `_lock` but for the build directory. | ||
/// | ||
/// NOTE: `_lock` and `_build_lock` can eventually be merged once #14125 is stablized. | ||
/// Will be `None` when the build-directory and target-directory are the same path as we cannot | ||
/// lock the same path twice. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can we merge these locks?
In the short term, we'll have
- target-dir
- build-dir
which both need locking
In the long term, we'll have
- artifact-dir
- build-dir
which will both need locking
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, you are right. Not quiet sure what I was thinking when I wrote this comment.
It should clean the build dir |
imo The artifact for |
Can we call out explicitly what our testing strategy is? We likely should also explicitly document in the PR what is considered an artifact and what is a build output and make sure we have tests for these. |
One other question that came to my mind was the output of Perhaps symlinking the |
@epage sure, I updated the PR description but let me know if I missed anything. |
imo |
There are multiple types of depinfo files. I suspect the ones next to final artifacts are also considered final artifacts, see https://doc.rust-lang.org/cargo/reference/build-cache.html#dep-info-files |
FYI I added to the PR description a couple more intermediate artifacts
When are workspace member rlibs considered final artifacts? We're putting them in |
dd06427
to
f53007f
Compare
I spent some more time this weekend making some progress on this PR. Here are my updates
I updated the PR description with more details as well. notably:
|
I haven't looked but would it work to split that out into a follow up PR? Keeping PRs focused can help with ensuring a smooth review and that we are less likely to overlook something.
My take is that if it isn't staged/uplifted, then its not a final artifact. I assume this also applies to test binaries, build scripts, and proc-macros. |
Sure. Its not a ton of code, but I have no problems breaking that out into anther PR to reduce the scope of this one 👍 |
Thanks, I think that sounds reasonable. |
a68a5eb
to
e49bf62
Compare
tests/testsuite/build_dir.rs
Outdated
name.to_string() | ||
}; | ||
|
||
assert_eq!(path.join(executable).exists(), exists); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you emit the path in the assert message?
tests/testsuite/build_dir.rs
Outdated
} | ||
|
||
#[cargo_test] | ||
fn verify_build_dir_is_disabled_by_feature_flag() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add this test to the first commit?
tests/testsuite/build_dir.rs
Outdated
#[cargo_test] | ||
fn verify_build_dir_is_disabled_by_feature_flag() { | ||
let p = project() | ||
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) | ||
.file( | ||
".cargo/config.toml", | ||
r#" | ||
[build] | ||
build-dir = "build" | ||
"#, | ||
) | ||
.build(); | ||
|
||
p.cargo("build") | ||
.masquerade_as_nightly_cargo(&[]) | ||
.enable_mac_dsym() | ||
.run(); | ||
|
||
assert_build_dir(p.root().join("target"), "debug", true); | ||
assert_executeable_exists(p.root().join("target/debug"), "foo", true); | ||
assert!(!p.root().join("build").exists()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you are taking the approach "Ignore the feature that is used without a gate " (see https://doc.rust-lang.org/nightly/nightly-rustc/cargo/core/features/index.html)
Could you speak to that (and update the PR description with that)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I updated the PR description with a feature gating section
src/cargo/util/context/mod.rs
Outdated
if let Some(val) = &self.build_config()?.build_dir { | ||
let path = val.resolve_path(self); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compared to pub fn target_dir()
,
- We don't have
self.build_dir
which is fine as we don't have a CLI flag - We don't check
CARGO_BUILD_DIR
env variable as a shortcut forCARGO_BUIILD_BUILD_DIR
. Should we have this shortcut?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't check CARGO_BUILD_DIR env variable as a shortcut for CARGO_BUILD_BUILD_DIR. Should we have this shortcut?
I am in favor of adding this as CARGO_BUILD_BUILD_DIR
is a bit rough on the eyes.
I can see this being useful when modifying the .cargo/config.toml
is not possible or inconvenient.
ie. Its much easier to set an env var than update a toml file in CI bash script.
} else { | ||
// For now, fallback to the previous implementation. | ||
// This will change in the future. | ||
return self.target_dir(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we handle this fallback here or in Workspace::build_dir
?
(I can see both ways)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it is in the follow up commit, duplicating the fallback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I added the fallback in both places "just in case"
fn target_root(build_runner: &BuildRunner<'_, '_>) -> PathBuf { | ||
build_runner.bcx.ws.target_dir().into_path_unlocked() | ||
build_runner.bcx.ws.build_dir().into_path_unlocked() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should target_root
be renamed?
.build_dir() | ||
.open_rw_exclusive_create( | ||
FUTURE_INCOMPAT_FILE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not seeing this discussed in the PR as intermediate vs final.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out. I reverted the change and added the following to the "final artifacts" category
- reports generated from
cargo report
like future-incompat-report
src/cargo/core/compiler/mod.rs
Outdated
@@ -297,7 +297,7 @@ fn rustc( | |||
let exec = exec.clone(); | |||
|
|||
let root_output = build_runner.files().host_dest().to_path_buf(); | |||
let target_dir = build_runner.bcx.ws.target_dir().into_path_unlocked(); | |||
let target_dir = build_runner.bcx.ws.build_dir().into_path_unlocked(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we rename this variable?
tests/testsuite/build_dir.rs
Outdated
assert_build_dir(p.root().join("build"), "debug", true); | ||
assert_executeable_exists(p.root().join("build/debug"), "foo", true); | ||
assert!(!p.root().join("target").exists()); | ||
assert_build_dir(p.root().join("target"), "debug", false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In reading these tests, the intent of the assertion isn't too clear (asserting that the target dir is a build dir? what does false
mean?). I think it'd be better to have two separate functions. If they truly must share an implementation, then they can just be wrappers on top of that.
ec7d7ba
to
2af0c91
Compare
These ares are in preparation to split target-dir into artifact-dir and build-dir
This is in preparation for splitting the intermediate build artifacts from the `target` directory.
This commit adds a `build_dir` option to the `build` table in `config.toml` and adds the equivalent field to `Workspace` and `GlobalContext`.
This commits implements the seperation of the intermidate artifact directory (called "build directory") from the target directory. (see rust-lang#14125)
2af0c91
to
1a326c2
Compare
I think this PR is now complete to the point that I will mark this PR as ready to review. Since the last review I have:
r? @epage |
What does this PR try to resolve?
This PR adds a new
build.build-dir
configuration option that was proposed in #14125 (comment)This new config option allows the user to specify a directory where intermediate build artifacts should be stored.
I have shortened it to just
build-dir
fromtarget-build-dir
, although naming is still subject to change.What is a final artifact vs an intermediate build artifact
Final artifacts
These are the files that end users will typically want to access directly or indirectly via a third party tool.
.crate
files output fromcargo package
.d
files) for third party build-system integrations (see https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/fingerprint/mod.rs#L194)cargo doc
output (html/css/js/etc)cargo report
like future-incompat-reportIntermediate build artifact
These are files that are used internally by Cargo/Rustc during the build process
OUT_DIR
target/build
)examples
that contain the hash in the name, bins forbenches
, proc macros, build scripts)CARGO_TARGET_TMPDIR
files (see rational for this here)Feature Gating Strategy
We are following the "Ignore the feature that is used without a gate" approach as described here.
The rational for this is:
The
build.build-dir
is likely going to be set by by users "globally" (ie.$CARGO_HOME/config.toml
) to set a shared build directory to reduce rebuilding dependencies. For users that multiple cargo versions having having an error would be disrupted.The fallback behavior is to revert to the behavior of the current stable release (building in
$CARGO_TARGET_DIR
)Testing Strategy
rand
to verify files are being output to the correct directory.How should we test and review this PR?
This is probably best reviewed commit by commit. I documented each commit.
I tied to follow the atomic commits recommendation in the Cargo contributors guide, but I split out some commits for ease of review. (Otherwise I think this would have ended up being 1 or 2 large commits 😅)
Questions
cargo clean
?target
and does not impact the build-dir but this is easily changable.build.build-dir
config option #15104 (comment)cargo package
are was expecting just the.crate
file to be intarget
while all other output be stored inbuild.build-dir
? Not sure if we consider things likeCargo.toml
,Cargo.toml.orig
,.cargo_vcs_info.json
part of the user facing interface..crate
is considered a final artifactcargo doc
output go? HTML/JS for many crates can be pretty large. Moving to the build-dir would help reduce duplication if we find the that acceptable. Forcargo doc --open
this is not a problem but may be problematic for other use cases?build.build-dir
config option #15104 (comment)benches
considered final artifacts?examples
are considered final artifacts, it seems natural thatbenches
should also be considered final artifacts. However, unlikeexamples
thebenches
bins are stored intarget/{profile}/deps
instead of a dedicated directory (liketarget/{profile}/examples
). We could move them into a dedicated directory (target/{profile}/benches
) but that mean would also be changing the structure of thetarget
directory which feels out of scope for this change. If we decide thatbenches
are final artifacts, it would probably be better to consider that changes as part of--artifact-dir
(nee--out-dir
) Tracking Issue #6790build.build-dir
config option #15104 (comment)CARGO_BUILD_DIR
shortcut env var?CARGO_BUILD_DIR
shortcut. This can be removed before merging if there a good reason to.TODO
cargo clean
Implement templating forbuild.build-dir
target/examples
still containing "pre-uplifted" binariesbuild-dir
with non-bin crate types