Rollup merge of #150151 - destabilise-target-spec-json, r=Kivooeo

Destabilise `target-spec-json`

Per rust-lang/compiler-team#944:

> Per https://github.com/rust-lang/rust/issues/71009, the ability to load target spec JSONs was stabilised accidentally. Within the team, we've always considered the format to be unstable and have changed it freely. This has been feasible as custom targets can only be used with core, like any other target, and so custom targets de-facto require nightly to be used (i.e. to build core manually or use Cargo's -Zbuild-std).
>
> Current build-std RFCs (https://github.com/rust-lang/rfcs/pull/3873, https://github.com/rust-lang/rfcs/pull/3874) propose a mechanism for building core on stable (at the request of Rust for Linux), which combined with a stable target-spec-json format, permit the current format to be used much more widely on stable toolchains. This would prevent us from improving the format - making it less tied to LLVM, switching to TOML, enabling keys in the spec to be stabilised individually, etc.
>
> De-stabilising the format gives us the opportunity to improve the format before it is too challenging to do so. Internal company toolchains and projects like Rust for Linux already use target-spec-json, but must use nightly at some point while doing so, so while it could be inconvenient for those users to destabilise this, it is hoped that an minimal alternative that we could choose to stabilise can be proposed relatively quickly.
This commit is contained in:
Jonathan Brouwer 2026-01-13 09:01:29 +01:00 committed by GitHub
commit a89683dd95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 38 additions and 8 deletions

View file

@ -1124,9 +1124,10 @@ fn get_backend_from_raw_matches(
let backend_name = debug_flags
.iter()
.find_map(|x| x.strip_prefix("codegen-backend=").or(x.strip_prefix("codegen_backend=")));
let unstable_options = debug_flags.iter().find(|x| *x == "unstable-options").is_some();
let target = parse_target_triple(early_dcx, matches);
let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
let target = config::build_target_config(early_dcx, &target, sysroot.path());
let target = config::build_target_config(early_dcx, &target, sysroot.path(), unstable_options);
get_codegen_backend(early_dcx, &sysroot, backend_name, &target)
}

View file

@ -435,6 +435,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
&early_dcx,
&config.opts.target_triple,
config.opts.sysroot.path(),
config.opts.unstable_opts.unstable_options,
);
let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
let path_mapping = config.opts.file_path_mapping();

View file

@ -46,6 +46,7 @@ where
&early_dcx,
&sessopts.target_triple,
sessopts.sysroot.path(),
sessopts.unstable_opts.unstable_options,
);
let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm();

View file

@ -1589,8 +1589,9 @@ pub fn build_target_config(
early_dcx: &EarlyDiagCtxt,
target: &TargetTuple,
sysroot: &Path,
unstable_options: bool,
) -> Target {
match Target::search(target, sysroot) {
match Target::search(target, sysroot, unstable_options) {
Ok((target, warnings)) => {
for warning in warnings.warning_messages() {
early_dcx.early_warn(warning)

View file

@ -1002,8 +1002,11 @@ pub fn build_session(
}
let host_triple = TargetTuple::from_tuple(config::host_tuple());
let (host, target_warnings) = Target::search(&host_triple, sopts.sysroot.path())
.unwrap_or_else(|e| dcx.handle().fatal(format!("Error loading host specification: {e}")));
let (host, target_warnings) =
Target::search(&host_triple, sopts.sysroot.path(), sopts.unstable_opts.unstable_options)
.unwrap_or_else(|e| {
dcx.handle().fatal(format!("Error loading host specification: {e}"))
});
for warning in target_warnings.warning_messages() {
dcx.handle().warn(warning)
}

View file

@ -3298,10 +3298,19 @@ impl Target {
pub fn search(
target_tuple: &TargetTuple,
sysroot: &Path,
unstable_options: bool,
) -> Result<(Target, TargetWarnings), String> {
use std::{env, fs};
fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
fn load_file(
path: &Path,
unstable_options: bool,
) -> Result<(Target, TargetWarnings), String> {
if !unstable_options {
return Err(
"custom targets are unstable and require `-Zunstable-options`".to_string()
);
}
let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
Target::from_json(&contents)
}
@ -3325,7 +3334,7 @@ impl Target {
for dir in env::split_paths(&target_path) {
let p = dir.join(&path);
if p.is_file() {
return load_file(&p);
return load_file(&p, unstable_options);
}
}
@ -3338,7 +3347,7 @@ impl Target {
Path::new("target.json"),
]);
if p.is_file() {
return load_file(&p);
return load_file(&p, unstable_options);
}
Err(format!("could not find specification for target {target_tuple:?}"))

View file

@ -15,11 +15,20 @@ fn main() {
.run_fail()
.assert_stderr_contains("error loading target specification");
rustc()
.arg("-Zunstable-options")
.input("foo.rs")
.target("my-incomplete-platform.json")
.run_fail()
.assert_stderr_contains("missing field `llvm-target`");
let test_platform = rustc()
.input("foo.rs")
.target("my-x86_64-unknown-linux-gnu-platform")
.crate_type("lib")
.emit("asm")
.run_fail()
.assert_stderr_contains("custom targets are unstable and require `-Zunstable-options`");
rustc()
.arg("-Zunstable-options")
.env("RUST_TARGET_PATH", ".")
.input("foo.rs")
.target("my-awesome-platform")
@ -27,6 +36,7 @@ fn main() {
.emit("asm")
.run();
rustc()
.arg("-Zunstable-options")
.env("RUST_TARGET_PATH", ".")
.input("foo.rs")
.target("my-x86_64-unknown-linux-gnu-platform")
@ -52,27 +62,31 @@ fn main() {
.actual_text("test-platform-2", test_platform_2)
.run();
rustc()
.arg("-Zunstable-options")
.input("foo.rs")
.target("endianness-mismatch")
.run_fail()
.assert_stderr_contains(r#""data-layout" claims architecture is little-endian"#);
rustc()
.arg("-Zunstable-options")
.input("foo.rs")
.target("mismatching-data-layout")
.crate_type("lib")
.run_fail()
.assert_stderr_contains("data-layout for target");
rustc()
.arg("-Zunstable-options")
.input("foo.rs")
.target("require-explicit-cpu")
.crate_type("lib")
.run_fail()
.assert_stderr_contains("target requires explicitly specifying a cpu");
rustc()
.arg("-Zunstable-options")
.input("foo.rs")
.target("require-explicit-cpu")
.crate_type("lib")
.arg("-Ctarget-cpu=generic")
.run();
rustc().target("require-explicit-cpu").arg("--print=target-cpus").run();
rustc().arg("-Zunstable-options").target("require-explicit-cpu").print("target-cpus").run();
}