Skip to content

Commit 3d6970d

Browse files
committed
Auto merge of #10395 - jonhoo:fix-10206, r=alexcrichton
Enable propagating host rustflags to build scripts ### 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 1. 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. 2. 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 being `false`. 3. It's not entirely clear how `target-applies-to-host-kind` should interact with `-Zmultitarget`. If, for example, `requested_kinds = [HostTarget, SomeOtherTarget]` and `kind.is_host()`, should `RUSTFLAGS` take effect or not? For the time being I've just hard-coded the behavior for single targets, and the answer would be "no".
2 parents 9d754ed + 56db829 commit 3d6970d

File tree

4 files changed

+425
-189
lines changed

4 files changed

+425
-189
lines changed

Diff for: src/cargo/core/compiler/build_context/target_info.rs

+112-52
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ impl TargetInfo {
144144
&rustc.host,
145145
None,
146146
kind,
147-
"RUSTFLAGS",
147+
Flags::Rust,
148148
)?;
149149
let extra_fingerprint = kind.fingerprint_hash();
150150
let mut process = rustc.workspace_process();
@@ -241,15 +241,15 @@ impl TargetInfo {
241241
&rustc.host,
242242
Some(&cfg),
243243
kind,
244-
"RUSTFLAGS",
244+
Flags::Rust,
245245
)?,
246246
rustdocflags: env_args(
247247
config,
248248
requested_kinds,
249249
&rustc.host,
250250
Some(&cfg),
251251
kind,
252-
"RUSTDOCFLAGS",
252+
Flags::Rustdoc,
253253
)?,
254254
cfg,
255255
supports_split_debuginfo,
@@ -554,89 +554,134 @@ fn output_err_info(cmd: &ProcessBuilder, stdout: &str, stderr: &str) -> String {
554554
result
555555
}
556556

557+
#[derive(Debug, Copy, Clone)]
558+
enum Flags {
559+
Rust,
560+
Rustdoc,
561+
}
562+
563+
impl Flags {
564+
fn as_key(self) -> &'static str {
565+
match self {
566+
Flags::Rust => "rustflags",
567+
Flags::Rustdoc => "rustdocflags",
568+
}
569+
}
570+
571+
fn as_env(self) -> &'static str {
572+
match self {
573+
Flags::Rust => "RUSTFLAGS",
574+
Flags::Rustdoc => "RUSTDOCFLAGS",
575+
}
576+
}
577+
}
578+
557579
/// Acquire extra flags to pass to the compiler from various locations.
558580
///
559581
/// The locations are:
560582
///
561583
/// - the `CARGO_ENCODED_RUSTFLAGS` environment variable
562584
/// - the `RUSTFLAGS` environment variable
563585
///
564-
/// then if this was not found
586+
/// then if none of those were found
565587
///
566588
/// - `target.*.rustflags` from the config (.cargo/config)
567589
/// - `target.cfg(..).rustflags` from the config
590+
/// - `host.*.rustflags` from the config if compiling a host artifact or without `--target`
568591
///
569-
/// then if neither of these were found
592+
/// then if none of those were found
570593
///
571594
/// - `build.rustflags` from the config
572595
///
573-
/// Note that if a `target` is specified, no args will be passed to host code (plugins, build
574-
/// scripts, ...), even if it is the same as the target.
596+
/// The behavior differs slightly when cross-compiling (or, specifically, when `--target` is
597+
/// provided) for artifacts that are always built for the host (plugins, build scripts, ...).
598+
/// For those artifacts, _only_ `host.*.rustflags` is respected, and no other configuration
599+
/// sources, _regardless of the value of `target-applies-to-host`_. This is counterintuitive, but
600+
/// necessary to retain bacwkards compatibility with older versions of Cargo.
575601
fn env_args(
576602
config: &Config,
577603
requested_kinds: &[CompileKind],
578604
host_triple: &str,
579605
target_cfg: Option<&[Cfg]>,
580606
kind: CompileKind,
581-
name: &str,
607+
flags: Flags,
582608
) -> CargoResult<Vec<String>> {
583-
// We *want* to apply RUSTFLAGS only to builds for the
584-
// requested target architecture, and not to things like build
585-
// scripts and plugins, which may be for an entirely different
586-
// architecture. Cargo's present architecture makes it quite
587-
// hard to only apply flags to things that are not build
588-
// scripts and plugins though, so we do something more hacky
589-
// instead to avoid applying the same RUSTFLAGS to multiple targets
590-
// arches:
591-
//
592-
// 1) If --target is not specified we just apply RUSTFLAGS to
593-
// all builds; they are all going to have the same target.
594-
//
595-
// 2) If --target *is* specified then we only apply RUSTFLAGS
596-
// to compilation units with the Target kind, which indicates
597-
// it was chosen by the --target flag.
609+
let target_applies_to_host = config.target_applies_to_host()?;
610+
611+
// Host artifacts should not generally pick up rustflags from anywhere except [host].
598612
//
599-
// This means that, e.g., even if the specified --target is the
600-
// same as the host, build scripts in plugins won't get
601-
// RUSTFLAGS.
602-
if requested_kinds != [CompileKind::Host] && kind.is_host() {
603-
// This is probably a build script or plugin and we're
604-
// compiling with --target. In this scenario there are
605-
// no rustflags we can apply.
606-
return Ok(Vec::new());
613+
// The one exception to this is if `target-applies-to-host = true`, which opts into a
614+
// particular (inconsistent) past Cargo behavior where host artifacts _do_ pick up rustflags
615+
// set elsewhere when `--target` isn't passed.
616+
if kind.is_host() {
617+
if target_applies_to_host && requested_kinds == [CompileKind::Host] {
618+
// This is the past Cargo behavior where we fall back to the same logic as for other
619+
// artifacts without --target.
620+
} else {
621+
// In all other cases, host artifacts just get flags from [host], regardless of
622+
// --target. Or, phrased differently, no `--target` behaves the same as `--target
623+
// <host>`, and host artifacts are always "special" (they don't pick up `RUSTFLAGS` for
624+
// example).
625+
return Ok(rustflags_from_host(config, flags, host_triple)?.unwrap_or_else(Vec::new));
626+
}
607627
}
608628

629+
// All other artifacts pick up the RUSTFLAGS, [target.*], and [build], in that order.
630+
// NOTE: It is impossible to have a [host] section and reach this logic with kind.is_host(),
631+
// since [host] implies `target-applies-to-host = false`, which always early-returns above.
632+
633+
if let Some(rustflags) = rustflags_from_env(flags) {
634+
Ok(rustflags)
635+
} else if let Some(rustflags) =
636+
rustflags_from_target(config, host_triple, target_cfg, kind, flags)?
637+
{
638+
Ok(rustflags)
639+
} else if let Some(rustflags) = rustflags_from_build(config, flags)? {
640+
Ok(rustflags)
641+
} else {
642+
Ok(Vec::new())
643+
}
644+
}
645+
646+
fn rustflags_from_env(flags: Flags) -> Option<Vec<String>> {
609647
// First try CARGO_ENCODED_RUSTFLAGS from the environment.
610648
// Prefer this over RUSTFLAGS since it's less prone to encoding errors.
611-
if let Ok(a) = env::var(format!("CARGO_ENCODED_{}", name)) {
649+
if let Ok(a) = env::var(format!("CARGO_ENCODED_{}", flags.as_env())) {
612650
if a.is_empty() {
613-
return Ok(Vec::new());
651+
return Some(Vec::new());
614652
}
615-
return Ok(a.split('\x1f').map(str::to_string).collect());
653+
return Some(a.split('\x1f').map(str::to_string).collect());
616654
}
617655

618656
// Then try RUSTFLAGS from the environment
619-
if let Ok(a) = env::var(name) {
657+
if let Ok(a) = env::var(flags.as_env()) {
620658
let args = a
621659
.split(' ')
622660
.map(str::trim)
623661
.filter(|s| !s.is_empty())
624662
.map(str::to_string);
625-
return Ok(args.collect());
663+
return Some(args.collect());
626664
}
627665

666+
// No rustflags to be collected from the environment
667+
None
668+
}
669+
670+
fn rustflags_from_target(
671+
config: &Config,
672+
host_triple: &str,
673+
target_cfg: Option<&[Cfg]>,
674+
kind: CompileKind,
675+
flag: Flags,
676+
) -> CargoResult<Option<Vec<String>>> {
628677
let mut rustflags = Vec::new();
629678

630-
let name = name
631-
.chars()
632-
.flat_map(|c| c.to_lowercase())
633-
.collect::<String>();
634679
// Then the target.*.rustflags value...
635680
let target = match &kind {
636681
CompileKind::Host => host_triple,
637682
CompileKind::Target(target) => target.short_name(),
638683
};
639-
let key = format!("target.{}.{}", target, name);
684+
let key = format!("target.{}.{}", target, flag.as_key());
640685
if let Some(args) = config.get::<Option<StringList>>(&key)? {
641686
rustflags.extend(args.as_slice().iter().cloned());
642687
}
@@ -656,22 +701,37 @@ fn env_args(
656701
});
657702
}
658703

659-
if !rustflags.is_empty() {
660-
return Ok(rustflags);
704+
if rustflags.is_empty() {
705+
Ok(None)
706+
} else {
707+
Ok(Some(rustflags))
661708
}
709+
}
662710

711+
fn rustflags_from_host(
712+
config: &Config,
713+
flag: Flags,
714+
host_triple: &str,
715+
) -> CargoResult<Option<Vec<String>>> {
716+
let target_cfg = config.host_cfg_triple(host_triple)?;
717+
let list = match flag {
718+
Flags::Rust => &target_cfg.rustflags,
719+
Flags::Rustdoc => {
720+
// host.rustdocflags is not a thing, since it does not make sense
721+
return Ok(None);
722+
}
723+
};
724+
Ok(list.as_ref().map(|l| l.val.as_slice().to_vec()))
725+
}
726+
727+
fn rustflags_from_build(config: &Config, flag: Flags) -> CargoResult<Option<Vec<String>>> {
663728
// Then the `build.rustflags` value.
664729
let build = config.build_config()?;
665-
let list = if name == "rustflags" {
666-
&build.rustflags
667-
} else {
668-
&build.rustdocflags
730+
let list = match flag {
731+
Flags::Rust => &build.rustflags,
732+
Flags::Rustdoc => &build.rustdocflags,
669733
};
670-
if let Some(list) = list {
671-
return Ok(list.as_slice().to_vec());
672-
}
673-
674-
Ok(Vec::new())
734+
Ok(list.as_ref().map(|l| l.as_slice().to_vec()))
675735
}
676736

677737
/// Collection of information about `rustc` and the host and target.

Diff for: src/doc/src/reference/unstable.md

+30-10
Original file line numberDiff line numberDiff line change
@@ -509,14 +509,32 @@ CLI paths are relative to the current working directory.
509509
* Original Pull Request: [#9322](https://github.com/rust-lang/cargo/pull/9322)
510510
* Tracking Issue: [#9453](https://github.com/rust-lang/cargo/issues/9453)
511511

512-
The `target-applies-to-host` key in a config file can be used set the desired
513-
behavior for passing target config flags to build scripts.
514-
515-
It requires the `-Ztarget-applies-to-host` command-line option.
516-
517-
The current default for `target-applies-to-host` is `true`, which will be
518-
changed to `false` in the future, if `-Zhost-config` is used the new `false`
519-
default will be set for `target-applies-to-host`.
512+
Historically, Cargo's behavior for whether the `linker` and `rustflags`
513+
configuration options from environment variables and `[target]` are
514+
respected for build scripts, plugins, and other artifacts that are
515+
_always_ built for the host platform has been somewhat inconsistent.
516+
When `--target` is _not_ passed, Cargo respects the same `linker` and
517+
`rustflags` for build scripts as for all other compile artifacts. When
518+
`--target` _is_ passed, however, Cargo respects `linker` from
519+
`[target.<host triple>]`, and does not pick up any `rustflags`
520+
configuration. This dual behavior is confusing, but also makes it
521+
difficult to correctly configure builds where the host triple and the
522+
target triple happen to be the same, but artifacts intended to run on
523+
the build host should still be configured differently.
524+
525+
`-Ztarget-applies-to-host` enables the top-level
526+
`target-applies-to-host` setting in Cargo configuration files which
527+
allows users to opt into different (and more consistent) behavior for
528+
these properties. When `target-applies-to-host` is unset, or set to
529+
`true`, in the configuration file, the existing Cargo behavior is
530+
preserved (though see `-Zhost-config`, which changes that default). When
531+
it is set to `false`, no options from `[target.<host triple>]`,
532+
`RUSTFLAGS`, or `[build]` are respected for host artifacts regardless of
533+
whether `--target` is passed to Cargo. To customize artifacts intended
534+
to be run on the host, use `[host]` ([`host-config`](#host-config)).
535+
536+
In the future, `target-applies-to-host` may end up defaulting to `false`
537+
to provide more sane and consistent default behavior.
520538

521539
```toml
522540
# config.toml
@@ -536,15 +554,17 @@ such as build scripts that must run on the host system instead of the target
536554
system when cross compiling. It supports both generic and host arch specific
537555
tables. Matching host arch tables take precedence over generic host tables.
538556

539-
It requires the `-Zhost-config` and `-Ztarget-applies-to-host` command-line
540-
options to be set.
557+
It requires the `-Zhost-config` and `-Ztarget-applies-to-host`
558+
command-line options to be set, and that `target-applies-to-host =
559+
false` is set in the Cargo configuration file.
541560

542561
```toml
543562
# config.toml
544563
[host]
545564
linker = "/path/to/host/linker"
546565
[host.x86_64-unknown-linux-gnu]
547566
linker = "/path/to/host/arch/linker"
567+
rustflags = ["-Clink-arg=--verbose"]
548568
[target.x86_64-unknown-linux-gnu]
549569
linker = "/path/to/target/linker"
550570
```

0 commit comments

Comments
 (0)