Skip to content

Commit be13600

Browse files
authored
Allow build-std to take an array of crate names (#1488)
Closes #896. This is technically a breaking change because arbitrary strings passed to the `CROSS_BUILD_STD` environment variable (e.g. `yes`) are now no longer parsed as truthy values, but rather as a single crate name (or multiple, if containing commas) to pass to `-Zbuild-std` (resulting in e.g. `-Zbuild-std=yes`, which is invalid). Behaviour remains the same when `CROSS_BUILD_STD` is set to `true`, `false`, or a number that fits in an `i32`.
2 parents 764d258 + 45247c1 commit be13600

File tree

5 files changed

+97
-44
lines changed

5 files changed

+97
-44
lines changed

.changes/1488.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"description": "Allow `build-std` to take an array of crate names",
3+
"issues": [896],
4+
"type": "changed",
5+
"breaking": true
6+
}

docs/config_file.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,10 @@ targets:
161161

162162
```toml
163163
[target.aarch64-unknown-linux-gnu]
164-
build-std = false # always build the std library. has precedence over xargo
165-
xargo = false # disable the use of xargo
166-
image = "test-image" # use a different image for the target
167-
runner = "qemu-user" # wrapper to run the binary (must be `qemu-system`, `qemu-user`, or `native`).
164+
build-std = ["core", "alloc"] # always build the `core` and `alloc` crates from the std library. has precedence over xargo
165+
xargo = false # disable the use of xargo
166+
image = "test-image" # use a different image for the target
167+
runner = "qemu-user" # wrapper to run the binary (must be `qemu-system`, `qemu-user`, or `native`).
168168
```
169169

170170

src/config.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::cross_toml::BuildStd;
12
use crate::docker::custom::PreBuild;
23
use crate::docker::{ImagePlatform, PossibleImage};
34
use crate::shell::MessageInfo;
@@ -63,8 +64,14 @@ impl Environment {
6364
self.get_values_for("XARGO", target, bool_from_envvar)
6465
}
6566

66-
fn build_std(&self, target: &Target) -> (Option<bool>, Option<bool>) {
67-
self.get_values_for("BUILD_STD", target, bool_from_envvar)
67+
fn build_std(&self, target: &Target) -> (Option<BuildStd>, Option<BuildStd>) {
68+
self.get_values_for("BUILD_STD", target, |v| {
69+
if let Some(value) = try_bool_from_envvar(v) {
70+
BuildStd::Bool(value)
71+
} else {
72+
BuildStd::Crates(v.split(',').map(str::to_owned).collect())
73+
}
74+
})
6875
}
6976

7077
fn zig(&self, target: &Target) -> (Option<bool>, Option<bool>) {
@@ -189,12 +196,16 @@ fn split_to_cloned_by_ws(string: &str) -> Vec<String> {
189196
/// this takes the value of the environment variable,
190197
/// so you should call `bool_from_envvar(env::var("FOO"))`
191198
pub fn bool_from_envvar(envvar: &str) -> bool {
199+
try_bool_from_envvar(envvar).unwrap_or(!envvar.is_empty())
200+
}
201+
202+
pub fn try_bool_from_envvar(envvar: &str) -> Option<bool> {
192203
if let Ok(value) = bool::from_str(envvar) {
193-
value
204+
Some(value)
194205
} else if let Ok(value) = i32::from_str(envvar) {
195-
value != 0
206+
Some(value != 0)
196207
} else {
197-
!envvar.is_empty()
208+
None
198209
}
199210
}
200211

@@ -350,8 +361,8 @@ impl Config {
350361
self.bool_from_config(target, Environment::xargo, CrossToml::xargo)
351362
}
352363

353-
pub fn build_std(&self, target: &Target) -> Option<bool> {
354-
self.bool_from_config(target, Environment::build_std, CrossToml::build_std)
364+
pub fn build_std(&self, target: &Target) -> Result<Option<BuildStd>> {
365+
self.get_from_ref(target, Environment::build_std, CrossToml::build_std)
355366
}
356367

357368
pub fn zig(&self, target: &Target) -> Option<bool> {
@@ -531,7 +542,10 @@ mod tests {
531542

532543
let env = Environment::new(Some(map));
533544
assert_eq!(env.xargo(&target()), (Some(true), None));
534-
assert_eq!(env.build_std(&target()), (Some(false), None));
545+
assert_eq!(
546+
env.build_std(&target()),
547+
(Some(BuildStd::Bool(false)), None)
548+
);
535549
assert_eq!(env.zig(&target()), (None, None));
536550
assert_eq!(env.zig_version(&target()), (None, None));
537551
assert_eq!(env.zig_image(&target())?, (Some("zig:local".into()), None));
@@ -621,7 +635,7 @@ mod tests {
621635
let env = Environment::new(Some(map));
622636
let config = Config::new_with(Some(toml(TOML_BUILD_XARGO_FALSE)?), env);
623637
assert_eq!(config.xargo(&target()), Some(true));
624-
assert_eq!(config.build_std(&target()), None);
638+
assert_eq!(config.build_std(&target())?, None);
625639
assert_eq!(
626640
config.pre_build(&target())?,
627641
Some(PreBuild::Lines(vec![
@@ -637,12 +651,15 @@ mod tests {
637651
pub fn env_target_and_toml_target_xargo_target_then_use_env() -> Result<()> {
638652
let mut map = HashMap::new();
639653
map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_XARGO", "true");
640-
map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_BUILD_STD", "true");
654+
map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_BUILD_STD", "core");
641655
let env = Environment::new(Some(map));
642656

643657
let config = Config::new_with(Some(toml(TOML_TARGET_XARGO_FALSE)?), env);
644658
assert_eq!(config.xargo(&target()), Some(true));
645-
assert_eq!(config.build_std(&target()), Some(true));
659+
assert_eq!(
660+
config.build_std(&target())?,
661+
Some(BuildStd::Crates(vec!["core".to_owned()]))
662+
);
646663
assert_eq!(config.pre_build(&target())?, None);
647664

648665
Ok(())
@@ -656,7 +673,7 @@ mod tests {
656673
let env = Environment::new(Some(map));
657674
let config = Config::new_with(Some(toml(TOML_BUILD_XARGO_FALSE)?), env);
658675
assert_eq!(config.xargo(&target()), Some(true));
659-
assert_eq!(config.build_std(&target()), None);
676+
assert_eq!(config.build_std(&target())?, None);
660677
assert_eq!(config.pre_build(&target())?, None);
661678

662679
Ok(())

src/cross_toml.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct CrossBuildConfig {
2929
#[serde(default)]
3030
env: CrossEnvConfig,
3131
xargo: Option<bool>,
32-
build_std: Option<bool>,
32+
build_std: Option<BuildStd>,
3333
#[serde(default, deserialize_with = "opt_string_bool_or_struct")]
3434
zig: Option<CrossZigConfig>,
3535
default_target: Option<String>,
@@ -44,7 +44,7 @@ pub struct CrossBuildConfig {
4444
#[serde(rename_all = "kebab-case")]
4545
pub struct CrossTargetConfig {
4646
xargo: Option<bool>,
47-
build_std: Option<bool>,
47+
build_std: Option<BuildStd>,
4848
#[serde(default, deserialize_with = "opt_string_bool_or_struct")]
4949
zig: Option<CrossZigConfig>,
5050
#[serde(default, deserialize_with = "opt_string_or_struct")]
@@ -58,6 +58,28 @@ pub struct CrossTargetConfig {
5858
env: CrossEnvConfig,
5959
}
6060

61+
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
62+
#[serde(untagged, rename_all = "kebab-case")]
63+
pub enum BuildStd {
64+
Bool(bool),
65+
Crates(Vec<String>),
66+
}
67+
68+
impl Default for BuildStd {
69+
fn default() -> Self {
70+
Self::Bool(false)
71+
}
72+
}
73+
74+
impl BuildStd {
75+
pub fn enabled(&self) -> bool {
76+
match self {
77+
Self::Bool(enabled) => *enabled,
78+
Self::Crates(arr) => !arr.is_empty(),
79+
}
80+
}
81+
}
82+
6183
/// Dockerfile configuration
6284
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
6385
#[serde(rename_all = "kebab-case")]
@@ -306,8 +328,8 @@ impl CrossToml {
306328
}
307329

308330
/// Returns the `build.build-std` or the `target.{}.build-std` part of `Cross.toml`
309-
pub fn build_std(&self, target: &Target) -> (Option<bool>, Option<bool>) {
310-
self.get_value(target, |b| b.build_std, |t| t.build_std)
331+
pub fn build_std(&self, target: &Target) -> (Option<&BuildStd>, Option<&BuildStd>) {
332+
self.get_ref(target, |b| b.build_std.as_ref(), |t| t.build_std.as_ref())
311333
}
312334

313335
/// Returns the `{}.zig` or `{}.zig.version` part of `Cross.toml`
@@ -647,7 +669,7 @@ mod tests {
647669
volumes: Some(vec![p!("VOL1_ARG"), p!("VOL2_ARG")]),
648670
},
649671
xargo: Some(false),
650-
build_std: Some(true),
672+
build_std: Some(BuildStd::Bool(true)),
651673
zig: None,
652674
image: Some("test-image".into()),
653675
runner: None,
@@ -923,7 +945,7 @@ mod tests {
923945
passthrough = ["VAR3"]
924946
925947
[build]
926-
build-std = true
948+
build-std = ["core", "alloc"]
927949
xargo = false
928950
default-target = "aarch64-unknown-linux-gnu"
929951
@@ -962,7 +984,7 @@ mod tests {
962984
passthrough = ["VAR3"]
963985
964986
[build]
965-
build-std = true
987+
build-std = ["core", "alloc"]
966988
xargo = false
967989
default-target = "aarch64-unknown-linux-gnu"
968990
@@ -983,7 +1005,13 @@ mod tests {
9831005
// need to test individual values. i've broken this down into
9841006
// tests on values for better error reporting
9851007
let build = &cfg_expected.build;
986-
assert_eq!(build.build_std, Some(true));
1008+
assert_eq!(
1009+
build.build_std,
1010+
Some(BuildStd::Crates(vec![
1011+
"core".to_owned(),
1012+
"alloc".to_owned()
1013+
]))
1014+
);
9871015
assert_eq!(build.xargo, Some(false));
9881016
assert_eq!(build.default_target, Some(p!("aarch64-unknown-linux-gnu")));
9891017
assert_eq!(build.pre_build, None);
@@ -993,7 +1021,7 @@ mod tests {
9931021

9941022
let targets = &cfg_expected.targets;
9951023
let aarch64 = &targets[&Target::new_built_in("aarch64-unknown-linux-gnu")];
996-
assert_eq!(aarch64.build_std, Some(true));
1024+
assert_eq!(aarch64.build_std, Some(BuildStd::Bool(true)));
9971025
assert_eq!(aarch64.xargo, Some(false));
9981026
assert_eq!(aarch64.image, Some(p!("test-image1")));
9991027
assert_eq!(aarch64.pre_build, None);
@@ -1002,7 +1030,7 @@ mod tests {
10021030
assert_eq!(aarch64.env.volumes, Some(vec![p!("VOL1_ARG")]));
10031031

10041032
let target2 = &targets[&Target::new_custom("target2")];
1005-
assert_eq!(target2.build_std, Some(false));
1033+
assert_eq!(target2.build_std, Some(BuildStd::Bool(false)));
10061034
assert_eq!(target2.xargo, Some(false));
10071035
assert_eq!(target2.image, Some(p!("test-image2-precedence")));
10081036
assert_eq!(target2.pre_build, None);
@@ -1011,7 +1039,7 @@ mod tests {
10111039
assert_eq!(target2.env.volumes, Some(vec![p!("VOL2_ARG_PRECEDENCE")]));
10121040

10131041
let target3 = &targets[&Target::new_custom("target3")];
1014-
assert_eq!(target3.build_std, Some(true));
1042+
assert_eq!(target3.build_std, Some(BuildStd::Bool(true)));
10151043
assert_eq!(target3.xargo, Some(false));
10161044
assert_eq!(target3.image, Some(p!("test-image3")));
10171045
assert_eq!(target3.pre_build, None);

src/lib.rs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ use cli::Args;
5454
use color_eyre::owo_colors::OwoColorize;
5555
use color_eyre::{Help, SectionExt};
5656
use config::Config;
57+
use cross_toml::BuildStd;
5758
use rustc::{QualifiedToolchain, Toolchain};
5859
use rustc_version::Channel;
5960
use serde::{Deserialize, Serialize, Serializer};
@@ -541,7 +542,7 @@ pub fn run(
541542
target,
542543
uses_xargo,
543544
uses_zig,
544-
uses_build_std,
545+
build_std,
545546
zig_version,
546547
toolchain,
547548
is_remote,
@@ -586,22 +587,16 @@ pub fn run(
586587
rustup::setup_components(
587588
&target,
588589
uses_xargo,
589-
uses_build_std,
590+
build_std.enabled(),
590591
&toolchain,
591592
is_nightly,
592593
available_targets,
593594
&args,
594595
msg_info,
595596
)?;
596597

597-
let filtered_args = get_filtered_args(
598-
zig_version,
599-
&args,
600-
&target,
601-
&config,
602-
is_nightly,
603-
uses_build_std,
604-
);
598+
let filtered_args =
599+
get_filtered_args(zig_version, &args, &target, &config, is_nightly, &build_std);
605600

606601
let needs_docker = args
607602
.subcommand
@@ -693,7 +688,7 @@ pub fn get_filtered_args(
693688
target: &Target,
694689
config: &Config,
695690
is_nightly: bool,
696-
uses_build_std: bool,
691+
build_std: &BuildStd,
697692
) -> Vec<String> {
698693
let add_libc = |triple: &str| add_libc_version(triple, zig_version.as_deref());
699694
let mut filtered_args = if args
@@ -746,9 +741,16 @@ pub fn get_filtered_args(
746741
if is_test && config.doctests().unwrap_or_default() && is_nightly {
747742
filtered_args.push("-Zdoctest-xcompile".to_owned());
748743
}
749-
if uses_build_std {
750-
filtered_args.push("-Zbuild-std".to_owned());
744+
745+
if build_std.enabled() {
746+
let mut arg = "-Zbuild-std".to_owned();
747+
if let BuildStd::Crates(crates) = build_std {
748+
arg.push('=');
749+
arg.push_str(&crates.join(","));
750+
}
751+
filtered_args.push(arg);
751752
}
753+
752754
filtered_args.extend(args.rest_args.iter().cloned());
753755
filtered_args
754756
}
@@ -769,8 +771,8 @@ pub fn setup(
769771
.clone()
770772
.or_else(|| config.target(&target_list))
771773
.unwrap_or_else(|| Target::from(host.triple(), &target_list));
772-
let uses_build_std = config.build_std(&target).unwrap_or(false);
773-
let uses_xargo = !uses_build_std && config.xargo(&target).unwrap_or(!target.is_builtin());
774+
let build_std = config.build_std(&target)?.unwrap_or_default();
775+
let uses_xargo = !build_std.enabled() && config.xargo(&target).unwrap_or(!target.is_builtin());
774776
let uses_zig = config.zig(&target).unwrap_or(false);
775777
let zig_version = config.zig_version(&target)?;
776778
let image = match docker::get_image(&config, &target, uses_zig) {
@@ -815,7 +817,7 @@ To override the toolchain mounted in the image, set `target.{target}.image.toolc
815817
target,
816818
uses_xargo,
817819
uses_zig,
818-
uses_build_std,
820+
build_std,
819821
zig_version,
820822
toolchain,
821823
is_remote,
@@ -830,7 +832,7 @@ pub struct CrossSetup {
830832
pub target: Target,
831833
pub uses_xargo: bool,
832834
pub uses_zig: bool,
833-
pub uses_build_std: bool,
835+
pub build_std: BuildStd,
834836
pub zig_version: Option<String>,
835837
pub toolchain: QualifiedToolchain,
836838
pub is_remote: bool,

0 commit comments

Comments
 (0)