Skip to content

Commit 6fc4eaa

Browse files
committed
Add -Z json-target-spec
This adds the `-Z json-target-spec` CLI flag to assist with using custom `.json` target spec files. `rustc` recently switched so that it requires `-Z unstable-options` when using custom spec files (rust-lang/rust#151534). This can make it rather awkward to use spec files with cargo because it then requires setting RUSTFLAGS and RUSTDOCFLAGS to pass `-Zunstable-options`. It also ends up causing some confusing error messages. Now, using `--target` with `.json` extension files generates an error that explains you need `-Zjson-target-spec`. The only thing this flag does is disable that error, and automatically passes `-Zunstable-options` with the `--target` flag. This does not 100% cover json target spec files, because they can be placed in RUST_TARGET_PATH or the sysroot, and `rustc` will automatically search for them (without the `.json` extension in the `--target` arg). The user will just need to use RUSTFLAGS/RUSTDOCFLAGS in that situation (but I expect that to be rare). The majority of this change is changing `CompileTarget::new` to take a flag if `-Zjson-target-spec` is enabled, and then threading through all the places that call it. `CompileTarget::new` is responsible for generating an error if json is used without the Z flag.
1 parent 752745f commit 6fc4eaa

12 files changed

Lines changed: 134 additions & 65 deletions

File tree

src/cargo/core/compiler/build_context/target_info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ impl<'gctx> RustcTargetData<'gctx> {
959959
let mut target_config = HashMap::new();
960960
let mut target_info = HashMap::new();
961961
let target_applies_to_host = gctx.target_applies_to_host()?;
962-
let host_target = CompileTarget::new(&rustc.host)?;
962+
let host_target = CompileTarget::new(&rustc.host, gctx.cli_unstable().json_target_spec)?;
963963
let host_info = TargetInfo::new(gctx, requested_kinds, &rustc, CompileKind::Host)?;
964964

965965
// This config is used for link overrides and choosing a linker.

src/cargo/core/compiler/compile_kind.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,15 @@ impl CompileKind {
9494

9595
if value.as_str() == "host-tuple" {
9696
let host_triple = env!("RUST_HOST_TARGET");
97-
Ok(CompileKind::Target(CompileTarget::new(host_triple)?))
97+
Ok(CompileKind::Target(CompileTarget::new(
98+
host_triple,
99+
gctx.cli_unstable().json_target_spec,
100+
)?))
98101
} else {
99-
Ok(CompileKind::Target(CompileTarget::new(value.as_str())?))
102+
Ok(CompileKind::Target(CompileTarget::new(
103+
value.as_str(),
104+
gctx.cli_unstable().json_target_spec,
105+
)?))
100106
}
101107
})
102108
// First collect into a set to deduplicate any `--target` passed
@@ -186,7 +192,7 @@ pub enum CompileTarget {
186192
}
187193

188194
impl CompileTarget {
189-
pub fn new(name: &str) -> CargoResult<CompileTarget> {
195+
pub fn new(name: &str, unstable_json: bool) -> CargoResult<CompileTarget> {
190196
let name = name.trim();
191197
if name.is_empty() {
192198
bail!("target was empty");
@@ -195,6 +201,10 @@ impl CompileTarget {
195201
return Ok(CompileTarget::Tuple(name.into()));
196202
}
197203

204+
if !unstable_json {
205+
bail!("`.json` target specs require -Zjson-target-spec");
206+
}
207+
198208
// If `name` ends in `.json` then it's likely a custom target
199209
// specification. Canonicalize the path to ensure that different builds
200210
// with different paths always produce the same result.

src/cargo/core/dependency.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ impl Artifact {
496496
artifacts: &[impl AsRef<str>],
497497
is_lib: bool,
498498
target: Option<&str>,
499+
unstable_json: bool,
499500
) -> CargoResult<Self> {
500501
let kinds = ArtifactKind::validate(
501502
artifacts
@@ -506,7 +507,9 @@ impl Artifact {
506507
Ok(Artifact {
507508
inner: Arc::new(kinds),
508509
is_lib,
509-
target: target.map(ArtifactTarget::parse).transpose()?,
510+
target: target
511+
.map(|name| ArtifactTarget::parse(name, unstable_json))
512+
.transpose()?,
510513
})
511514
}
512515

@@ -536,10 +539,10 @@ pub enum ArtifactTarget {
536539
}
537540

538541
impl ArtifactTarget {
539-
pub fn parse(target: &str) -> CargoResult<ArtifactTarget> {
542+
pub fn parse(target: &str, unstable_json: bool) -> CargoResult<ArtifactTarget> {
540543
Ok(match target {
541544
"target" => ArtifactTarget::BuildDependencyAssumeTarget,
542-
name => ArtifactTarget::Force(CompileTarget::new(name)?),
545+
name => ArtifactTarget::Force(CompileTarget::new(name, unstable_json)?),
543546
})
544547
}
545548

src/cargo/core/features.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ unstable_cli_options!(
870870
#[serde(deserialize_with = "deserialize_gitoxide_features")]
871871
gitoxide: Option<GitoxideFeatures> = ("Use gitoxide for the given git interactions, or all of them if no argument is given"),
872872
host_config: bool = ("Enable the `[host]` section in the .cargo/config.toml file"),
873+
json_target_spec: bool = ("Enable `.json` target spec files"),
873874
lockfile_path: bool = ("Enable the `resolver.lockfile-path` config option"),
874875
minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
875876
msrv_policy: bool = ("Enable rust-version aware policy within cargo"),
@@ -1409,6 +1410,7 @@ impl CliUnstable {
14091410
)?
14101411
}
14111412
"host-config" => self.host_config = parse_empty(k, v)?,
1413+
"json-target-spec" => self.json_target_spec = parse_empty(k, v)?,
14121414
"lockfile-path" => self.lockfile_path = parse_empty(k, v)?,
14131415
"next-lockfile-bump" => self.next_lockfile_bump = parse_empty(k, v)?,
14141416
"minimal-versions" => self.minimal_versions = parse_empty(k, v)?,

src/cargo/core/resolver/features.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,7 @@ impl<'a, 'gctx> FeatureResolver<'a, 'gctx> {
811811
pkg_id: PackageId,
812812
dep: &Dependency,
813813
lib_fk: FeaturesFor,
814+
unstable_json_spec: bool,
814815
) -> CargoResult<Vec<FeaturesFor>> {
815816
let Some(artifact) = dep.artifact() else {
816817
return Ok(vec![lib_fk]);
@@ -844,7 +845,9 @@ impl<'a, 'gctx> FeatureResolver<'a, 'gctx> {
844845
ArtifactTarget::BuildDependencyAssumeTarget => {
845846
for kind in this.requested_targets {
846847
let target = match kind {
847-
CompileKind::Host => CompileTarget::new(&host_triple).unwrap(),
848+
CompileKind::Host => {
849+
CompileTarget::new(&host_triple, unstable_json_spec).unwrap()
850+
}
848851
CompileKind::Target(target) => *target,
849852
};
850853
activate_target(target)?;
@@ -859,6 +862,7 @@ impl<'a, 'gctx> FeatureResolver<'a, 'gctx> {
859862
Ok(result)
860863
}
861864

865+
let unstable_json_spec = self.ws.gctx().cli_unstable().json_target_spec;
862866
self.resolve
863867
.deps(pkg_id)
864868
.map(|(dep_id, deps)| {
@@ -915,7 +919,8 @@ impl<'a, 'gctx> FeatureResolver<'a, 'gctx> {
915919
fk
916920
};
917921

918-
let dep_fks = artifact_features_for(self, pkg_id, dep, lib_fk)?;
922+
let dep_fks =
923+
artifact_features_for(self, pkg_id, dep, lib_fk, unstable_json_spec)?;
919924
Ok(dep_fks.into_iter().map(move |dep_fk| (dep, dep_fk)))
920925
})
921926
.flatten_ok()

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,10 @@ pub fn create_bcx<'a, 'gctx>(
398398
// If `--target` has not been specified, then the unit graph is built
399399
// assuming `--target $HOST` was specified. See
400400
// `rebuild_unit_graph_shared` for more on why this is done.
401-
let explicit_host_kind = CompileKind::Target(CompileTarget::new(&target_data.rustc.host)?);
401+
let explicit_host_kind = CompileKind::Target(CompileTarget::new(
402+
&target_data.rustc.host,
403+
gctx.cli_unstable().json_target_spec,
404+
)?);
402405
let explicit_host_kinds: Vec<_> = build_config
403406
.requested_kinds
404407
.iter()

src/cargo/sources/registry/index/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,18 @@ impl IndexSummary {
195195
}
196196
}
197197

198-
fn index_package_to_summary(pkg: &IndexPackage<'_>, source_id: SourceId) -> CargoResult<Summary> {
198+
fn index_package_to_summary(
199+
pkg: &IndexPackage<'_>,
200+
source_id: SourceId,
201+
cli_unstable: &CliUnstable,
202+
) -> CargoResult<Summary> {
199203
// ****CAUTION**** Please be extremely careful with returning errors, see
200204
// `IndexSummary::parse` for details
201205
let pkgid = PackageId::new(pkg.name.as_ref().into(), pkg.vers.clone(), source_id);
202206
let deps = pkg
203207
.deps
204208
.iter()
205-
.map(|dep| registry_dependency_into_dep(dep.clone(), source_id))
209+
.map(|dep| registry_dependency_into_dep(dep.clone(), source_id, cli_unstable))
206210
.collect::<CargoResult<Vec<_>>>()?;
207211
let mut features = pkg.features.clone();
208212
if let Some(features2) = pkg.features2.clone() {
@@ -651,7 +655,7 @@ impl IndexSummary {
651655
// values carefully when making changes here.
652656
let index_summary = (|| {
653657
let index = serde_json::from_slice::<IndexPackage<'_>>(line)?;
654-
let summary = index_package_to_summary(&index, source_id)?;
658+
let summary = index_package_to_summary(&index, source_id, cli_unstable)?;
655659
Ok((index, summary))
656660
})();
657661
let (index, summary, valid) = match index_summary {
@@ -683,7 +687,7 @@ impl IndexSummary {
683687
links: Default::default(),
684688
pubtime: Default::default(),
685689
};
686-
let summary = index_package_to_summary(&index, source_id)?;
690+
let summary = index_package_to_summary(&index, source_id, cli_unstable)?;
687691
(index, summary, false)
688692
}
689693
};
@@ -712,6 +716,7 @@ impl IndexSummary {
712716
fn registry_dependency_into_dep(
713717
dep: RegistryDependency<'_>,
714718
default: SourceId,
719+
cli_unstable: &CliUnstable,
715720
) -> CargoResult<Dependency> {
716721
let RegistryDependency {
717722
name,
@@ -768,7 +773,12 @@ fn registry_dependency_into_dep(
768773
}
769774

770775
if let Some(artifacts) = artifact {
771-
let artifact = Artifact::parse(&artifacts, lib, bindep_target.as_deref())?;
776+
let artifact = Artifact::parse(
777+
&artifacts,
778+
lib,
779+
bindep_target.as_deref(),
780+
cli_unstable.json_target_spec,
781+
)?;
772782
dep.set_artifact(artifact);
773783
}
774784

src/cargo/util/toml/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,13 +1792,13 @@ note: only a feature named `default` will be enabled by default"
17921792
let default_kind = normalized_package
17931793
.default_target
17941794
.as_ref()
1795-
.map(|t| CompileTarget::new(&*t))
1795+
.map(|t| CompileTarget::new(&*t, gctx.cli_unstable().json_target_spec))
17961796
.transpose()?
17971797
.map(CompileKind::Target);
17981798
let forced_kind = normalized_package
17991799
.forced_target
18001800
.as_ref()
1801-
.map(|t| CompileTarget::new(&*t))
1801+
.map(|t| CompileTarget::new(&*t, gctx.cli_unstable().json_target_spec))
18021802
.transpose()?
18031803
.map(CompileKind::Target);
18041804
let include = normalized_package
@@ -2311,7 +2311,12 @@ fn dep_to_dependency<P: ResolveToPath + Clone>(
23112311
orig.target.as_deref(),
23122312
) {
23132313
if manifest_ctx.gctx.cli_unstable().bindeps {
2314-
let artifact = Artifact::parse(&artifact.0, is_lib, target)?;
2314+
let artifact = Artifact::parse(
2315+
&artifact.0,
2316+
is_lib,
2317+
target,
2318+
manifest_ctx.gctx.cli_unstable().json_target_spec,
2319+
)?;
23152320
if dep.kind() != DepKind::Build
23162321
&& artifact.target() == Some(ArtifactTarget::BuildDependencyAssumeTarget)
23172322
{

src/doc/src/reference/unstable.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Each new feature described below should explain how to use it.
100100
* [panic-immediate-abort](#panic-immediate-abort) --- Passes `-Cpanic=immediate-abort` to the compiler.
101101
* [compile-time-deps](#compile-time-deps) --- Perma-unstable feature for rust-analyzer
102102
* [fine-grain-locking](#fine-grain-locking) --- Use fine grain locking instead of locking the entire build cache
103+
* [target-spec-json](#target-spec-json) --- Allows the use of `.json` custom target specs.
103104
* rustdoc
104105
* [rustdoc-map](#rustdoc-map) --- Provides mappings for documentation to link to external sites like [docs.rs](https://docs.rs/).
105106
* [scrape-examples](#scrape-examples) --- Shows examples within documentation.
@@ -2028,7 +2029,7 @@ cargo +nightly build --compile-time-deps -Z unstable-options
20282029
cargo +nightly check --compile-time-deps --all-targets -Z unstable-options
20292030
```
20302031

2031-
# `rustc-unicode`
2032+
## `rustc-unicode`
20322033
* Tracking Issue: [rust#148607](https://github.com/rust-lang/rust/issues/148607)
20332034

20342035
Enable `rustc`'s unicode error format in Cargo's error messages
@@ -2045,6 +2046,17 @@ so that `cargo doc` can merge cross-crate information
20452046
from separate output directories,
20462047
and run `rustdoc` in parallel.
20472048

2049+
## target-spec-json
2050+
* Tracking Issue: [rust-lang/rust#151528](https://github.com/rust-lang/rust/issues/151528)
2051+
2052+
The `-Z target-spec-json` CLI flag enables the ability to use [custom target spec JSON files](https://doc.rust-lang.org/nightly/rustc/targets/custom.html) as a target.
2053+
2054+
```console
2055+
cargo +nightly build --target my-target.json -Z target-spec-json
2056+
```
2057+
2058+
This usually must be combined with [build-std](#build-std).
2059+
20482060
# Stabilized and removed features
20492061

20502062
## Compile progress

tests/build-std/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ fn cross_custom() {
312312
.file("custom-target.json", target_spec_json())
313313
.build();
314314

315-
p.cargo("build --target custom-target.json -v")
315+
p.cargo("build --target custom-target.json -v -Zjson-target-spec")
316+
.masquerade_as_nightly_cargo(&["json_target_spec"])
316317
.build_std_arg("core")
317318
.run();
318319
}
@@ -352,7 +353,8 @@ fn custom_test_framework() {
352353
paths.insert(0, sysroot_bin);
353354
let new_path = env::join_paths(paths).unwrap();
354355

355-
p.cargo("test --target target.json --no-run -v")
356+
p.cargo("test --target target.json --no-run -v -Zjson-target-spec")
357+
.masquerade_as_nightly_cargo(&["json_target_spec"])
356358
.env("PATH", new_path)
357359
.build_std_arg("core")
358360
.run();

0 commit comments

Comments
 (0)