Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] run-make-support: Calculate artifact names for target platform, not host platform #139242

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/doc/rustc-dev-guide/src/tests/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,13 @@ settings:
specified atomic widths, e.g. the test with `//@ needs-target-has-atomic: 8,
16, ptr` will only run if it supports the comma-separated list of atomic
widths.
- `needs-dynamic-linking` - ignores if target does not support dynamic linking
- `needs-dynamic-linking` ignores if target does not support dynamic linking
(which is orthogonal to it being unable to create `dylib` and `cdylib` crate types)
- `needs-crate-type` — ignores if target platform does not support one or more
of the comma-delimited list of specified crate types. For example,
`//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored
on `wasm32-unknown-unknown` target because the target does not support the
`proc-macro` crate type.

The following directives will check LLVM support:

Expand Down
31 changes: 31 additions & 0 deletions src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ pub struct Config {

pub target_cfgs: OnceLock<TargetCfgs>,
pub builtin_cfg_names: OnceLock<HashSet<String>>,
pub supported_crate_types: OnceLock<HashSet<String>>,

pub nocapture: bool,

Expand Down Expand Up @@ -475,6 +476,11 @@ impl Config {
self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self))
}

/// Get the list of crate types that the target platform supports.
pub fn supported_crate_types(&self) -> &HashSet<String> {
self.supported_crate_types.get_or_init(|| supported_crate_types(self))
}

pub fn has_threads(&self) -> bool {
// Wasm targets don't have threads unless `-threads` is in the target
// name, such as `wasm32-wasip1-threads`.
Expand Down Expand Up @@ -748,6 +754,31 @@ fn builtin_cfg_names(config: &Config) -> HashSet<String> {
.collect()
}

pub const KNOWN_CRATE_TYPES: &[&str] =
&["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"];

fn supported_crate_types(config: &Config) -> HashSet<String> {
let crate_types: HashSet<_> = rustc_output(
config,
&["--target", &config.target, "--print=supported-crate-types", "-Zunstable-options"],
Default::default(),
)
.lines()
.map(|l| l.to_string())
.collect();

for crate_type in crate_types.iter() {
assert!(
KNOWN_CRATE_TYPES.contains(&crate_type.as_str()),
"unexpected crate type `{}`: known crate types are {:?}",
crate_type,
KNOWN_CRATE_TYPES
);
}

crate_types
}

fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
let mut command = Command::new(&config.rustc_path);
add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/directive-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"min-llvm-version",
"min-system-llvm-version",
"needs-asm-support",
"needs-crate-type",
"needs-deterministic-layouts",
"needs-dlltool",
"needs-dynamic-linking",
Expand Down
48 changes: 46 additions & 2 deletions src/tools/compiletest/src/header/needs.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::common::{Config, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
use crate::header::{IgnoreDecision, llvm_has_libzstd};

pub(super) fn handle_needs(
cache: &CachedNeedsConditions,
config: &Config,
ln: &str,
) -> IgnoreDecision {
// Note thet we intentionally still put the needs- prefix here to make the file show up when
// Note that we intentionally still put the needs- prefix here to make the file show up when
// grepping for a directive name, even though we could technically strip that.
let needs = &[
Need {
Expand Down Expand Up @@ -224,6 +224,50 @@ pub(super) fn handle_needs(
}
}

// FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above.
if name == "needs-crate-type" {
let Some(rest) = rest else {
return IgnoreDecision::Error {
message:
"expected `needs-crate-type` to have a comma-separated list of crate types"
.to_string(),
};
};

// Expect directive value to be a list of comma-separated crate-types.
let specified_crate_types = rest
.split(',')
.map(|crate_type| crate_type.trim())
.map(ToString::to_string)
.collect::<Vec<String>>();

for crate_type in &specified_crate_types {
if !KNOWN_CRATE_TYPES.contains(&crate_type.as_str()) {
return IgnoreDecision::Error {
message: format!(
"unknown crate type specified in `needs-crate-type`: `{crate_type}` is not \
a known crate type, known values are `{:?}`",
KNOWN_CRATE_TYPES
),
};
}
}

let satisfies_all_crate_types = specified_crate_types
.iter()
.all(|specified| config.supported_crate_types().contains(specified));
if satisfies_all_crate_types {
return IgnoreDecision::Continue;
} else {
return IgnoreDecision::Ignore {
reason: format!(
"skipping test as target does not support all of the crate types `{:?}`",
specified_crate_types
),
};
}
}

if !name.starts_with("needs-") {
return IgnoreDecision::Continue;
}
Expand Down
39 changes: 39 additions & 0 deletions src/tools/compiletest/src/header/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,3 +905,42 @@ fn test_rustc_abi() {
assert!(!check_ignore(&config, "//@ ignore-rustc_abi-x86-sse2"));
assert!(check_ignore(&config, "//@ only-rustc_abi-x86-sse2"));
}

#[cfg(not(bootstrap))]
#[test]
fn test_supported_crate_types() {
// Basic assumptions check on under-test compiler's `--print=supported-crate-types` output based
// on knowledge about the cherry-picked `x86_64-unknown-linux-gnu` and `wasm32-unknown-unknown`
// targets. Also smoke tests the `needs-crate-type` directive itself.

use std::collections::HashSet;

let config = cfg().target("x86_64-unknown-linux-gnu").build();
assert_eq!(
config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
HashSet::from(["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]),
);
assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
assert!(!check_ignore(&config, "//@ needs-crate-type: dylib"));
assert!(!check_ignore(
&config,
"//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
));

let config = cfg().target("wasm32-unknown-unknown").build();
assert_eq!(
config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
HashSet::from(["bin", "cdylib", "lib", "rlib", "staticlib"]),
);

// rlib is supported
assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
// dylib is not
assert!(check_ignore(&config, "//@ needs-crate-type: dylib"));
// If multiple crate types are specified, then all specified crate types need to be supported.
assert!(check_ignore(&config, "//@ needs-crate-type: cdylib, dylib"));
assert!(check_ignore(
&config,
"//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
));
}
1 change: 1 addition & 0 deletions src/tools/compiletest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ pub fn parse_config(args: Vec<String>) -> Config {

target_cfgs: OnceLock::new(),
builtin_cfg_names: OnceLock::new(),
supported_crate_types: OnceLock::new(),

nocapture: matches.opt_present("no-capture"),

Expand Down
53 changes: 40 additions & 13 deletions src/tools/run-make-support/src/artifact_names.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! A collection of helpers to construct artifact names, such as names of dynamic or static
//! librarys which are target-dependent.
// FIXME(jieyouxu): convert these to return `PathBuf`s instead of strings!
//! libraries which are target-dependent.
use crate::target;
use crate::targets::is_msvc;

/// Construct the static library name based on the target.
#[track_caller]
#[must_use]
pub fn static_lib_name(name: &str) -> String {
assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
Expand All @@ -14,15 +14,34 @@ pub fn static_lib_name(name: &str) -> String {
}

/// Construct the dynamic library name based on the target.
#[track_caller]
#[must_use]
pub fn dynamic_lib_name(name: &str) -> String {
assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");

format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
format!("{}{name}.{}", dynamic_lib_prefix(), dynamic_lib_extension())
}

fn dynamic_lib_prefix() -> &'static str {
if target().contains("windows") { "" } else { "lib" }
}

/// Construct the name of the import library for the dynamic library, exclusive to MSVC and
/// accepted by link.exe.
/// Construct the dynamic library extension based on the target.
#[must_use]
pub fn dynamic_lib_extension() -> &'static str {
let target = target();

if target.contains("apple") {
"dylib"
} else if target.contains("windows") {
"dll"
} else {
"so"
}
}

/// Construct the name of the import library for the dynamic library, exclusive to MSVC and accepted
/// by link.exe.
#[track_caller]
#[must_use]
pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
Expand All @@ -32,20 +51,28 @@ pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
format!("{name}.dll.lib")
}

/// Construct the dynamic library extension based on the target.
#[must_use]
pub fn dynamic_lib_extension() -> &'static str {
std::env::consts::DLL_EXTENSION
}

/// Construct the name of a rust library (rlib).
#[track_caller]
#[must_use]
pub fn rust_lib_name(name: &str) -> String {
format!("lib{name}.rlib")
}

/// Construct the binary (executable) name based on the target.
#[track_caller]
#[must_use]
pub fn bin_name(name: &str) -> String {
format!("{name}{}", std::env::consts::EXE_SUFFIX)
let target = target();

if target.contains("windows") {
format!("{name}.exe")
} else if target.contains("uefi") {
format!("{name}.efi")
} else if target.contains("wasm") {
format!("{name}.wasm")
} else if target.contains("nvptx") {
format!("{name}.ptx")
} else {
name.to_string()
}
}
32 changes: 27 additions & 5 deletions tests/run-make/crate-data-smoke/rmake.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
use run_make_support::{bin_name, rust_lib_name, rustc};
use run_make_support::{bin_name, rust_lib_name, rustc, target};

fn main() {
rustc().print("crate-name").input("crate.rs").run().assert_stdout_equals("foo");
rustc().print("file-names").input("crate.rs").run().assert_stdout_equals(bin_name("foo"));
rustc()
.target(target())
.print("crate-name")
.input("crate.rs")
.run()
.assert_stdout_equals("foo");
rustc()
.target(target())
.print("file-names")
.input("crate.rs")
.run()
.assert_stdout_equals(bin_name("foo"));
rustc()
.target(target())
.print("file-names")
.crate_type("lib")
.arg("--test")
.input("crate.rs")
.run()
.assert_stdout_equals(bin_name("foo"));
rustc()
.target(target())
.print("file-names")
.arg("--test")
.input("lib.rs")
.run()
.assert_stdout_equals(bin_name("mylib"));
rustc().print("file-names").input("lib.rs").run().assert_stdout_equals(rust_lib_name("mylib"));
rustc().print("file-names").input("rlib.rs").run().assert_stdout_equals(rust_lib_name("mylib"));
rustc()
.target(target())
.print("file-names")
.input("lib.rs")
.run()
.assert_stdout_equals(rust_lib_name("mylib"));
rustc()
.target(target())
.print("file-names")
.input("rlib.rs")
.run()
.assert_stdout_equals(rust_lib_name("mylib"));
}
12 changes: 7 additions & 5 deletions tests/run-make/crate-name-priority/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
// and the compiler flags, and checks that the flag is favoured each time.
// See https://github.com/rust-lang/rust/pull/15518

use run_make_support::{bin_name, rfs, rustc};
//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`)

use run_make_support::{bin_name, rfs, rustc, target};

fn main() {
rustc().input("foo.rs").run();
rustc().target(target()).input("foo.rs").run();
rfs::remove_file(bin_name("foo"));
rustc().input("foo.rs").crate_name("bar").run();
rustc().target(target()).input("foo.rs").crate_name("bar").run();
rfs::remove_file(bin_name("bar"));
rustc().input("foo1.rs").run();
rustc().target(target()).input("foo1.rs").run();
rfs::remove_file(bin_name("foo"));
rustc().input("foo1.rs").output(bin_name("bar1")).run();
rustc().target(target()).input("foo1.rs").output(bin_name("bar1")).run();
rfs::remove_file(bin_name("bar1"));
}
8 changes: 6 additions & 2 deletions tests/run-make/extra-filename-with-temp-outputs/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
// are named as expected.
// See https://github.com/rust-lang/rust/pull/15686

use run_make_support::{bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files};
//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`)

use run_make_support::{
bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files, target,
};

fn main() {
rustc().extra_filename("bar").input("foo.rs").arg("-Csave-temps").run();
rustc().target(target()).extra_filename("bar").input("foo.rs").arg("-Csave-temps").run();
let object_files = shallow_find_files(cwd(), |path| {
has_prefix(path, "foobar.foo") && has_suffix(path, "0.rcgu.o")
});
Expand Down
Loading
Loading