Enable propagating host rustflags to build scripts by jonhoo · Pull Request #103...
source link: https://github.com/rust-lang/cargo/pull/10395
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
New issue
Enable propagating host rustflags to build scripts #10395
Merged
Conversation
What does this PR try to resolve?
This PR primarily fixes #10206, but in doing so it also slightly modifies the interface for the unstable target-applies-to-host
feature (#9453), and adds the unstable target-applies-to-host-kind
flag to mirror target-applies-to-host
for build scripts and other host artifacts.
The commit messages have more in-depth discussion.
How should we test and review this PR?
The test case from #10206 now works rather than producing an error. It has also been added a regression test case. A few additional test cases have also been added to handle the expected behavior around rustflags for build scripts with and without target-applies-to-host-kind
enabled.
Additional information
- This changes the interface for
target-applies-to-host
so that it does not need to be specified twice to be used. And it can still be set through configuration files using the[unstable]
table. However, we may(?) want to pick a stable format for in-file configuration of this setting unless we intend for it to only ever be a command-line flag. - It may be that
target-applies-to-host-kind
is never behavior we want users to turn on, and that it should therefore simply be removed and hard-coded as beingfalse
. - It's not entirely clear how
target-applies-to-host-kind
should interact with-Zmultitarget
. If, for example,requested_kinds = [HostTarget, SomeOtherTarget]
andkind.is_host()
, shouldRUSTFLAGS
take effect or not? For the time being I've just hard-coded the behavior for single targets, and the answer would be "no".
(rust-highfive has picked a reviewer for you, use r? to override)
PR failures are due to new clap 3.1.0 deprecations combined with -Dwarnings
. Fixing separately in #10396.
/cc @jameshilliard too since you contributed the original feature :)
- This changes the interface for
target-applies-to-host
so that it does not need to be specified twice to be used. And it can still be set through configuration files using the[unstable]
table. However, we may(?) want to pick a stable format for in-file configuration of this setting unless we intend for it to only ever be a command-line flag.
Why did you remove the stable format? The only reason you have to specify target-applies-to-host
twice is because the nightly feature is not yet stabilized.
3. It's not entirely clear how
target-applies-to-host-kind
should interact with-Zmultitarget
. If, for example,requested_kinds = [HostTarget, SomeOtherTarget]
andkind.is_host()
, shouldRUSTFLAGS
take effect or not? For the time being I've just hard-coded the behavior for single targets, and the answer would be "no".
Target configs are always triple specific, so setting the config flag target-applies-to-host = true
is just intended to use/apply the target specific triple configs as if they were also host triple specific configs, the idea is you would basically get equivalent behavior by copying the target triple configs manually as host triple configs(this is effectively cargo's current default behavior). Setting target-applies-to-host = true
should never apply a target triple config unless the host triple being built matches the target triple config.
It's intentional that target-applies-to-host
is a top level configuration setting as we need that for many cross compiling scenarios since we want to be able to unconditionally set target-applies-to-host = false
for all targets being built. We really don't want the target-applies-to-host = false
behavior to be gated behind a nightly config option as doing so forces us to set hacks like __CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS="nightly"
when cross compiling with a stable toolchain. The reason for the stable flag as opposed to just changing the default is to allow for gradual transition away from the broken target-applies-to-host = true
behavior without causing issues for users that currently depend on that. There's potentially some users that may want to retain target-applies-to-host = true
behavior as it would allow for smaller configs in the event they want target and host configs to be the same.
I gave the original discussion for the feature another reading, and I agree with you that having the top-level configuration option is probably the way to go. It has a similar flavor to resolver = "2"
, where we may want to flip the default in the future. So I've restored the past logic in that regard
The reason this is hairy is because the behavior of Cargo today is inconsistent. Only linker
and runner
from [target.<host triple>]
are applied to host artifacts, but not rustflags
. The way I've represented that in the latest revision of this PR that I just pushed is that target-applies-to-host
really has three states: unset, true
, and false
. When unset, the current (inconsistent) behavior is preserved. When set to true
, everything from [target.<host triple>]
is respected for host artifacts. And when set to true
, [target.<host triple>]
is ignored for host artifacts. That strikes the right balance to me at least.
I'm personally also not in favor of having -Zhost-config
change the default for target-applies-to-host
. Instead, I'd prefer for -Zhost-config
to produce an error if target-applies-to-host
isn't set to false
. That way we start to incentivize affected users to put target-applies-to-host = false
in their configuration files. But I've left that logic as-is for now.
The reason this is hairy is because the behavior of Cargo today is inconsistent.
Yeah, it's def a hairy mess.
Only linker and runner from [target.] are applied to host artifacts, but not rustflags.
Ugh, that's pretty bad, I only tested the linkers myself since that's what was causing build errors for us. That should probably just be fixed outright as it's clearly a bug.
When unset, the current (inconsistent) behavior is preserved.
IMO the best behavior when unset would be to apply target triples to host if --target
is not set but don't apply if it is set. In addition if a host table is present without --target
set I would have it override that and disable apply target configs to host.
So defaults like this for cases where target-applies-to-host
is not explicitly specified is probably the least likely to break configurations IMO:
- if
--target
unset && no host table present =>target-applies-to-host = true
- if
--target
unset && host table present =>target-applies-to-host = false
- if
--target
set =>target-applies-to-host = false
And when set to
true
,[target.<host triple>]
is ignored for host artifacts.
I assume you mean when set to false
here right?
I'm personally also not in favor of having
-Zhost-config
change the default fortarget-applies-to-host
. Instead, I'd prefer for-Zhost-config
to produce an error iftarget-applies-to-host
isn't set tofalse
.
Well the main reason for having it change the default was mostly to minimize the amount of combinations(branch conditions essentially) to test, I only wanted the host table feature to be tested with the new defaults for target-applies-to-host
. By having it change the default it cuts down the amount of combination testing needing as you then no longer have to test the host table combined with old defaults.
Only linker and runner from [target.] are applied to host artifacts, but not rustflags.
Ugh, that's pretty bad, I only tested the linkers myself since that's what was causing build errors for us. That should probably just be fixed outright as it's clearly a bug.
When unset, the current (inconsistent) behavior is preserved.
IMO the best behavior when unset would be to apply target triples to host if
--target
is not set but don't apply if it is set.
I don't think we can just fix it, sadly, as that would likely break a bunch of cross-compiling users. Hence the "legacy" mode this PR implements. I think we almost certainly have to preserve backwards compatibility here, or cause a bunch of unnecessary churn for users. Though if the Cargo team is okay with the breakage, I'm okay with removing the legacy mode. I just assumed they wouldn't be.
In addition if a host table is present without
--target
set I would have it override that and disable apply target configs to host.So defaults like this for cases where
target-applies-to-host
is not explicitly specified is probably the least likely to break configurations IMO:1. if `--target` unset && no host table present => `target-applies-to-host = true` 2. if `--target` unset && host table present => `target-applies-to-host = false` 3. if `--target` set => `target-applies-to-host = false`
I really dislike dynamic defaults, since they tend to be hard to discover and hard to debug. I'd much rather (as this PR implements) have -Zhost-config
require target-applies-to-host = false
. I also don't think we can change today's behavior with respect to --target
being set/unset except at something like an edition boundary, since a fair number of users probably rely on the current behavior (though here, too, if the Cargo team is okay with the breakage, we should do it). Which then leads to the choices this PR makes:
- If
-Zhost-config
andtarget-applies-to-host != false
, error. - If
target-applies-to-host
istrue
, pick uplinker
,runner
, andrustflags
(or, really, all keys) fromtarget.<host>
for host artifacts. - If
target-applies-to-host
isfalse
, do not pick uptarget.<host>
for host artifacts. - If
target-applies-to-host
is unset (which implies no host table), pick uplinker
,runner
, and any future fields fromtarget.<host>
for host artifacts. Pick uprustflags
only if--target
isn't passed.
Then, come next edition, we make target-applies-to-host = "false"
the default. And maybe the edition after we remove target-applies-to-host
as a user-visible configuration option.
And when set to
true
,[target.<host triple>]
is ignored for host artifacts.I assume you mean when set to
false
here right?
Sorry, yes, false
.
I'm personally also not in favor of having
-Zhost-config
change the default fortarget-applies-to-host
. Instead, I'd prefer for-Zhost-config
to produce an error iftarget-applies-to-host
isn't set tofalse
.Well the main reason for having it change the default was mostly to minimize the amount of combinations(branch conditions essentially) to test, I only wanted the host table feature to be tested with the new defaults for
target-applies-to-host
. By having it change the default it cuts down the amount of combination testing needing as you then no longer have to test the host table combined with old defaults.
The number of combinations should be the same, since = true
is just outright disallowed with -Zhost-config
.
I don't think we can just fix it, sadly, as that would likely break a bunch of cross-compiling users.
We're talking about fixing the rustflags
bug in the nightly only host-config
feature right? Isn't the entire point of the feature being nightly only to allow breaking changes/fixes?
Hence the "legacy" mode this PR implements. I think we almost certainly have to preserve backwards compatibility here, or cause a bunch of unnecessary churn for users. Though if the Cargo team is okay with the breakage, I'm okay with removing the legacy mode. I just assumed they wouldn't be.
I'm highly skeptical changing the target-applies-to-host
defaults would be all that problematic mostly since the target-applies-to-host = false
default behavior already effectively exists for target triple != host triple
cross compilation scenarios.
But this target-applies-to-host
default change is an entirely separate issue AFAIU from fixing the host-config
rustflags
bug, I think it's probably best to fix the rustflags
bug separately then worry about the defaults/stabilization path for the host-config
and target-applies-to-host
features after that's taken care of.
Build scripts typically don't usually need custom build flags at all to function(we don't even need/use the host-config feature in buildroot, we only use the target-applies-to-host feature to override the existing default buggy target-applies-to-host = true
behavior so that our x86_64
cross builds don't break due to linker errors) AFAIU in most cases build scripts just need to be able to execute on the host and cargo doesn't even have a way to provide a host artifact specific configs without enabling -Zhost-config
anyways, only triple specific configs are supported in stable toolchains which are inherently buggy for host artifact cross compilation configuration.
Arguably anyone cross compiling who has a config that changing this default breaks has a buggy config already, they just happen to have things working by accident, either way the point of the target-applies-to-host
config flag is to provide an escape hatch to restore the previous buggy cross compilation behavior for anyone who actually depends on it.
From my understanding the Cargo team is fine with this approach provided there is a transition period before changing the default(although I personally don't actually think this is necessary since fixing the buggy behavior is only likely to break obscure configurations anyways).
I really dislike dynamic defaults, since they tend to be hard to discover and hard to debug.
I mean, if the goal is to have host triple == target triple
cross compilation work as expected by default while breaking the least amount of existing configs then dynamic defaults here is probably the least terrible option.
I'd much rather (as this PR implements) have
-Zhost-config
requiretarget-applies-to-host = false
.
What are you trying to do here? Requiring a config option that's intended to be stabilized in order to enable setting a nightly gate for a feature also intended to be stabilized makes no sense to me.
Setting -Zhost-config
isn't something that will do anything when the host config feature is stabilized, you would use the host config options once stabilized just by adding a host config table, -Zhost-config
is a nightly feature gate option that will be removed.
I also don't think we can change today's behavior with respect to
--target
being set/unset except at something like an edition boundary, since a fair number of users probably rely on the current behavior (though here, too, if the Cargo team is okay with the breakage, we should do it).
Either way this seems to be something separate from the host.rustflags
fix. Can we not fix the host.rustflags
bug in the nightly host-config
feature and then worry about --target
behavior separately? The host/target split logic in cargo is rather complex/confusing in general and having all these changes intertwined makes things difficult to review here.
Which then leads to the choices this PR makes:
1. If `-Zhost-config` and `target-applies-to-host != false`, error.
This doesn't make sense since -Zhost-config
is just a nightly feature gate flag that will not even exist when running builds with stable toolchains.
2. If `target-applies-to-host` is `true`, pick up `linker`, `runner`, and `rustflags` (or, really, all keys) from `target.<host>` for host artifacts.
This sounds fine.
3. If `target-applies-to-host` is `false`, do not pick up `target.<host>` for host artifacts.
This sounds fine.
4. If `target-applies-to-host` is unset (which implies no host table), pick up `linker`, `runner`, and any future fields from `target.<host>` for host artifacts. Pick up `rustflags` only if `--target` _isn't_ passed.
This is extremely confusing, AFAIU isn't not even possible to set host artifact specific rustflags
at all without this fix, or any host artifact specific config options at all(only triple specific flags seem possible without nightly features) for that matter without enabling the nightly -Zhost-config
feature gate.
The report #10206 that this fixes seems to be entirely referencing a bug in the nightly host-config
feature and not something applicable to a stabilized feature, which should be able to be fixed without a migration period as that feature is not stabilized yet.
Is there also a different bug with rustflags
for target triple config flags(ie without -Zhost-config
being used at all).
Then, come next edition, we make
target-applies-to-host = "false"
the default. And maybe the edition after we removetarget-applies-to-host
as a user-visible configuration option.
I think the important part is just changing the default before we stabilize the host-config
feature to reduce the amount of potential branch conditions we have to handle/test.
The number of combinations should be the same, since
= true
is just outright disallowed with-Zhost-config
.
We want to test the host-config
feature behavior as if it were already stabilized. You appear to be effectively trying to test the -Zhost-config
nightly feature gating logic which isn't particularly useful as nightly feature gating isn't applicable to features once stabilized at all.
@alexcrichton I believe I've modified this to be more in line with your expectations now. As mentioned above, I think we should adjust the -Z
flag and (potentially) change the logic in get_target_applies_to_host
in a separate PR, so I've reverted my changes related to those two in this PR.
Sorry I still don't really understand why this is structured this way, and it's still not really how I expect. I can try to reiterate though.
In the limit I don't believe there will be a "legacy" mode in Cargo. Instead we'll have target-applies-to-host
as a configuration setting and its default will change at some point in the future but I don't think we have any plans to remove it entirely. This means that structuring code for a legacy code path to get removed at some point I don't think makes sense.
Otherwise my expectation is for the logic to, in one location, have somewhat of a complicated condition to do what the default is today but otherwise everything should basically appear the same.
Right now it looks like you've got quite a bit of duplicated code between branches for a part of Cargo that's arguably already incorrect (doesn't accumulate flags) and is quite tricky (pulling flags from multiple sources).
Sorry I can try to get more detailed but I'd rather not take on the task of writing this patch myself.
Is the latest patch more in line with what you were expecting?
src/cargo/core/compiler/build_context/target_info.rs
Outdated Show resolved
src/doc/src/reference/unstable.md
Outdated Show resolved
src/doc/src/reference/unstable.md
Outdated
artifacts. Furthermore, when set to `false`, host artifacts do not pick
up flags from `RUSTFLAGS` or `[build]`, even if `--target` is _not_
passed to Cargo.
If you're going to specifically call out the case where --target
is not passed I think it's worth pointing out here that it basically doesn't work at all. If target-applies-to-host
is false
and you type cargo build
then this PR makes all of RUSTFLAGS
, [build]
, and [target]
get ignored. That's a bug in Cargo that needs to be fixed one day before this is stabilized, of course, but if it's going to be called out here I think it's worthwhile to be called out accurately.
I've added a sentence to that effect.
I'm not sure whether it's a bug in Cargo or "working as intended". My understanding at least is that the desire is for RUSTFLAGS
, [build]
, and [target]
to only ever apply to target artifacts, for cargo build
to act like cargo build --target <host triple>
, and for --target <host triple>
to still treat the target as having a separate configuration from the host, which implies this behavior. But I could be missing something about how you'd like this to work.
tests/testsuite/build_script.rs
Show resolved
tests/testsuite/build_script.rs
Show resolved
Outdated
#[cargo_test]
fn env_rustflags_build_script_with_target_doesnt_apply_to_host_kind() {
// RUSTFLAGS should *not* be passed to rustc for build scripts when --target is specified as the
// host triple even if target-applies-to-host-kind is enabled, to match legacy Cargo behavior.
// In this test if --cfg foo is passed the build will fail.
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
build = "build.rs"
"#,
)
.file("src/lib.rs", "")
.file(
"build.rs",
r#"
fn main() { }
#[cfg(foo)]
fn main() { }
"#,
)
.file(
".cargo/config.toml",
r#"
target-applies-to-host = true
"#,
)
.build();
let host = rustc_host();
p.cargo("build --target")
.masquerade_as_nightly_cargo()
.arg(host)
.arg("-Ztarget-applies-to-host")
.env("RUSTFLAGS", "--cfg foo")
.run();
}
This at least doesn't match my mental model of Cargo to the point that one of the checks when calculating rustflags may need adjusting. At least in my own mental model of what's happening here target-specific rustflags have been configured, and it's been explicitly opted-in to that target-applies-to-host
, meaning that the target-specific rustflags should be passed to the host, so --cfg foo
should be passed to the build script.
I read the other comment first, so left an explanation there. It basically comes down to whether = true
should match the current Cargo behavior (in which case I argue it should be renamed), or whether = true
should also pick up cases like this (which the original draft of this PR did) and some third state (= "mixed"
) should map to the current behavior.
Outdated Show resolved
Outdated Show resolved
// Even with the setting, the rustflags from `target.` should not apply, to match the legacy
// Cargo behavior.
p.change_file(
".cargo/config",
&format!(
"
target-applies-to-host = true
[target.{}]
rustflags = [\"--cfg=foo\"]
",
host
),
);
p.cargo("build --target")
.arg(host)
.masquerade_as_nightly_cargo()
.arg("-Ztarget-applies-to-host")
.run();
I mentioned this above, but this doesn't match my own mental model at least because if target-applies-to-host = true
then I'd expect that target-specific flags apply to the host builds.
Ah, so, this one is special, and gets back to my point about how target-applies-to-host
should arguably be a tri-state of true/false/legacy
. Currently (as in, on master
), if you pass --target <host triple>
, then build scripts will not pick up target.<host>.rustflags
due to
if requested_kinds != [CompileKind::Host] && kind.is_host() {
// This is probably a build script or plugin and we're
// compiling with --target. In this scenario there are
// no rustflags we can apply.
return Ok(Vec::new());
}
Example (using latest Cargo release):
$ cargo new bs Created binary (application) `bs` package $ cd bs $ echo 'fn main() { assert!(cfg!(foo)); }' > build.rs $ mkdir .cargo $ echo '[target.x86_64-apple-darwin]' > .cargo/config $ echo 'rustflags = ["--cfg=foo"]' >> .cargo/config $ cargo b Compiling bs v0.1.0 (/Users/jongje/bs) Finished dev [unoptimized + debuginfo] target(s) in 1.27s $ cargo b --target x86_64-apple-darwin Compiling bs v0.1.0 (/Users/jongje/bs) error: failed to run custom build command for `bs v0.1.0 (/Users/jongje/bs)` Caused by: process didn't exit successfully: `/Users/jongje/bs/target/debug/build/bs-7d41676a7672d1a0/build-script-build` (exit status: 101) --- stderr thread 'main' panicked at 'assertion failed: cfg!(foo)', build.rs:1:13 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
if target-applies-to-host
is just a bool
, and true
is supposed to be the existing behavior, then making target.<host>.rustflags
apply to build scripts with --target <host>
would be a backwards-incompatible change (as per above). Now, maybe that's okay, and we want to consider that fixing a bug — that's up to you. Otherwise, we'd need a third state for target-applies-to-host
that maps exactly to the current behavior.
Outdated Show resolved
Ok I think I understand what you mean by the tri-state behavior, I never fully understood that but seeing the test cases now and how they're working clarifies this for me at least. My main priority in reviewing all of this rustflags/target/host related stuff is to ensure that breakage is quanitified and either mitigated or deemed acceptable. In that sense I'm pretty confident that this PR doesn't change the current behavior, which is good in the sense that it mitigates possible breakage. For the future, though, I think we'll want the tri-state idea but not necessarily super-well-supported.
I don't think anyone will really argue that today's behavior is correct and should be codified into Cargo for all time. Today's behavior is the amalgamation of growing over years as PRs touched various portions and we as Cargo reviewers didn't do a great job of seeing how everything fits together. What's done is done though, we move past it. This I think means that the stabilization story for target-applies-to-host
may be a bit different though. In my mind the "tri-state" is "not configured", true
, and false
. The "not configured" case is whatever Cargo does today to prevent breaking any existing builds. In the future I was assuming we would stabilize as true
and then in the future switch to false
at some point later. I believe, though, that at least in my desired interpretation of true
then stabilizing as true
would be a breaking change because as noted here some tests aren't behaving as I'd expect (where when you say target-applies-to-host
that doesn't actually happen). Instead this may mean that we need to bite the bullet on breakage and simply stabilize the false
option first (and maybe even just switch internal defaults and leave the target-applies-to-host
option unstable).
Basically what I'm trying to do is to chart a course from where we are to where we want to be with minimal breakage to the ecosystem. Ideally this would mean that at any time if someone hits a breakage they can flip a switch to go back to some previous behavior or something like that. I've been working under the assumption that this is possible but it may simply not be possible. This may all simply mean that breakage is unavoidable and if the breakage doesn't work for someone all we can say is "sorry you can hold back on upgrading Cargo for a bit while the breakage is worked through".
I completely agree — that matches my thinking on the subject.
I think the right question then becomes is "how hard is mitigation". If target-applies-to-host = false
is made the default, then that will break users with no recourse until [host]
is stabilized — they'll be unable to set the rustflags and linker for build scripts when --target
is passed. Which seems untenable to me. We could perhaps (as you suggested) group target-applies-to-host
and host-config
together under a single -Z
so they land together, but I'll leave that up to you. In the meantime, I actually wonder if the right thing to do short-term is to change the default to = true
so that Cargo's behavior is at least consistent, and so that there is a way to accomplish what users might want, even if it's not exactly the behavior we think is least likely to cause problems.
In any case, I also agree with you that this PR doesn't change current behavior beyond fixing #10206, and so should be possible to safely land.
@bors: r+
Ok well we can get all this sorted out during the stabilization of the features here. I agree this is fine to go for now. Personally I continue to feel that these unstable features are also gated on the fact that cargo build
is "all host" rather than the expected "some host some target" builds, because if we were to stabilize target-applies-to-host = false
, which I think is what we want, then RUSTFLAGS="" cargo build
wouldn't actually apply any flags anywhere.
Commit 56db829 has been approved by alexcrichton
Test successful - checks-actions
Approved by: alexcrichton
Pushing 3d6970d to master...
It's a good point. I wonder if the way to go here is to take a lesson from alexcrichton/cc-rs#9 and add support for RUSTFLAGS_$TARGET
and the like. That way we can say that RUSTFLAGS
applies to all targets (including the host), TARGET_RUSTFLAGS
applies only to the target(s), HOST_RUSTFLAGS
applies only to the host, RUSTFLAGS_$TARGET
applies only to $TARGET
, etc. What do you think?
Maybe? That's something I think needs discussion outside of just this PR and input from others as well.
Oh, yes, definitely. I just don't see a way around doing that, or something like it, if we want cargo build
to work like cargo build --target <host>
.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
No milestone
Successfully merging this pull request may close these issues.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK