Skip to content
Merged
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
220 changes: 91 additions & 129 deletions tests/compiletests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ impl DepKind {

fn target_dir_suffix(self, target: &SpirvTarget) -> String {
match self {
Self::SpirvLib => format!("{}/debug/deps", target.target()),
Self::ProcMacro => "debug/deps".into(),
Self::SpirvLib => format!("{}/debug/build", target.target()),
Self::ProcMacro => "debug/build".into(),
}
}
}
Expand Down Expand Up @@ -101,27 +101,17 @@ impl Runner {
/// RUSTFLAGS passed to all test files.
fn test_rustc_flags(
codegen_backend_path: &Path,
deps: &TestDeps,
indirect_deps_dirs: &[&Path],
deps: &[TestDep],
search_dirs: &[PathBuf],
) -> String {
[
&*rust_flags(codegen_backend_path),
&*indirect_deps_dirs
&*search_dirs
.iter()
.map(|dir| format!("-L dependency={}", dir.display()))
.fold(String::new(), |a, b| b + " " + &a),
.join(" "),
"--edition 2021",
&*format!("--extern noprelude:core={}", deps.core.display()),
&*format!(
"--extern noprelude:compiler_builtins={}",
deps.compiler_builtins.display()
),
&*format!(
"--extern spirv_std_macros={}",
deps.spirv_std_macros.display()
),
&*format!("--extern spirv_std={}", deps.spirv_std.display()),
&*format!("--extern glam={}", deps.glam.display()),
&*deps.iter().map(TestDep::to_rustc_extern).join(" "),
"--crate-type dylib",
"-Zunstable-options",
"-Zcrate-attr=no_std",
Expand Down Expand Up @@ -166,18 +156,8 @@ impl Runner {
.unwrap();

let libs = self.build_deps(&target, &target_spec);
let mut flags = test_rustc_flags(
&self.codegen_backend_path,
&libs,
&[
&self
.deps_target_dir
.join(DepKind::SpirvLib.target_dir_suffix(&target)),
&self
.deps_target_dir
.join(DepKind::ProcMacro.target_dir_suffix(&target)),
],
);
let search_dirs = self.dep_search_dirs(&target);
let mut flags = test_rustc_flags(&self.codegen_backend_path, &libs, &search_dirs);
flags += variation.extra_flags;

let config = compiletest::Config {
Expand All @@ -199,7 +179,7 @@ impl Runner {
}

/// Runs the processes needed to build `spirv-std` & other deps.
fn build_deps(&self, target: &SpirvTarget, target_spec: &TargetSpec) -> TestDeps {
fn build_deps(&self, target: &SpirvTarget, target_spec: &TargetSpec) -> Vec<TestDep> {
// Build compiletests-deps-helper
let mut cmd = std::process::Command::new("cargo");
cmd.args([
Expand All @@ -208,6 +188,7 @@ impl Runner {
"compiletests-deps-helper",
"-Zbuild-std=core",
"-Zbuild-std-features=compiler-builtins-mem",
"-Zbuild-dir-new-layout",
]);
target_spec.append_to_cmd(&mut cmd);
cmd.arg("--target-dir")
Expand All @@ -219,44 +200,23 @@ impl Runner {
.and_then(map_status_to_result)
.unwrap();

let compiler_builtins = self.find_lib("compiler_builtins", DepKind::SpirvLib, target);
let core = self.find_lib("core", DepKind::SpirvLib, target);
let spirv_std = self.find_lib("spirv_std", DepKind::SpirvLib, target);
let glam = self.find_lib("glam", DepKind::SpirvLib, target);
let spirv_std_macros = self.find_lib("spirv_std_macros", DepKind::ProcMacro, target);

let all_libs = [
&compiler_builtins,
&core,
&spirv_std,
&glam,
&spirv_std_macros,
];
if all_libs.iter().any(|r| r.is_err()) {
// FIXME(eddyb) `missing_count` should always be `0` anyway.
// FIXME(eddyb) use `--message-format=json-render-diagnostics` to
// avoid caring about duplicates (or search within files at all).
let missing_count = all_libs
.iter()
.filter(|r| matches!(r, Err(FindLibError::Missing)))
.count();
let duplicate_count = all_libs
.iter()
.filter(|r| matches!(r, Err(FindLibError::Duplicate)))
.count();
eprintln!(
"warning: cleaning deps ({missing_count} missing libs, {duplicate_count} duplicated libs)"
);
let all_deps: Result<_, ()> = (|| {
Ok([
self.find_lib("compiler_builtins", DepKind::SpirvLib, target)?
.no_prelude(),
self.find_lib("core", DepKind::SpirvLib, target)?
.no_prelude(),
self.find_lib("spirv-std", DepKind::SpirvLib, target)?,
self.find_lib("glam", DepKind::SpirvLib, target)?,
self.find_lib("spirv-std-macros", DepKind::ProcMacro, target)?,
])
})();
if let Ok(all_deps) = all_deps {
Vec::from(all_deps)
} else {
eprintln!("warning: cleaning and rebuilding deps");
self.clean_deps();
self.build_deps(target, target_spec)
} else {
TestDeps {
core: core.ok().unwrap(),
glam: glam.ok().unwrap(),
compiler_builtins: compiler_builtins.ok().unwrap(),
spirv_std: spirv_std.ok().unwrap(),
spirv_std_macros: spirv_std_macros.ok().unwrap(),
}
}
}

Expand All @@ -271,81 +231,83 @@ impl Runner {
}
}

enum FindLibError {
Missing,
Duplicate,
}

impl Runner {
/// search for `out` dirs for all compiled libraries
fn dep_search_dirs(&self, target: &SpirvTarget) -> Vec<PathBuf> {
[
self.deps_target_dir
.join(DepKind::SpirvLib.target_dir_suffix(target)),
self.deps_target_dir
.join(DepKind::ProcMacro.target_dir_suffix(target)),
]
.iter()
.filter_map(|build_dir| std::fs::read_dir(build_dir).ok())
.flatten()
.filter_map(|crate_dir| std::fs::read_dir(crate_dir.ok()?.path()).ok())
.flatten()
.filter_map(|hash_dir| {
let out_dir = hash_dir.ok()?.path().join("out");
out_dir.is_dir().then_some(out_dir)
})
.collect()
}

/// Attempt find the rlib that matches `base`, if multiple rlibs are found then
/// a clean build is required and `Err(FindLibError::Duplicate)` is returned.
fn find_lib(
&self,
base: impl AsRef<Path>,
dep_kind: DepKind,
target: &SpirvTarget,
) -> Result<PathBuf, FindLibError> {
let base = base.as_ref();
let (expected_prefix, expected_extension) = dep_kind.prefix_and_extension();
let expected_name = format!("{}{}", expected_prefix, base.display());

let dir = self
fn find_lib(&self, name: &str, dep_kind: DepKind, target: &SpirvTarget) -> Result<TestDep, ()> {
let ident_name = name.replace("-", "_");
let (expected_prefix, expected_suffix) = dep_kind.prefix_and_extension();
let expected_prefix = format!("{expected_prefix}{}", ident_name);
let build_dir = self
.deps_target_dir
.join(dep_kind.target_dir_suffix(target));

std::fs::read_dir(dir)
.unwrap()
.map(|entry| entry.unwrap().path())
.filter(move |path| {
let name = {
let name = path.file_stem();
if name.is_none() {
return false;
}
name.unwrap()
};

let name_matches = name.to_str().unwrap().starts_with(&expected_name)
&& name.len() == expected_name.len() + 17 // we expect our name, '-', and then 16 hexadecimal digits
&& ends_with_dash_hash(name.to_str().unwrap());
let extension_matches = path
.extension()
.is_some_and(|ext| ext == expected_extension);

name_matches && extension_matches
.join(dep_kind.target_dir_suffix(target))
.join(name);

let rlib = std::fs::read_dir(&build_dir)
.unwrap_or_else(|_| panic!("Couldn't read dir {}", build_dir.display()))
.filter_map(|entry| {
let out_dir = entry.ok()?.path().join("out");
std::fs::read_dir(out_dir).ok()
})
.exactly_one()
.map_err(|mut iter| {
if iter.next().is_none() {
FindLibError::Missing
} else {
FindLibError::Duplicate
}
.flatten()
.filter_map(|entry| {
let path = entry.ok()?.path();
let file_name = path.file_name()?.to_str()?;
(file_name.starts_with(&expected_prefix) && file_name.ends_with(expected_suffix))
.then_some(path)
})
.exactly_one()
.map_err(|_e| ())?;
Ok(TestDep::new(ident_name, rlib))
}
}

/// Returns whether this string ends with a dash ('-'), followed by 16 lowercase hexadecimal characters
fn ends_with_dash_hash(s: &str) -> bool {
let n = s.len();
if n < 17 {
return false;
}
let mut bytes = s.bytes().skip(n - 17);
if bytes.next() != Some(b'-') {
return false;
struct TestDep {
name: String,
rlib: PathBuf,
no_prelude: bool,
}

impl TestDep {
pub fn new(name: String, rlib: PathBuf) -> Self {
Self {
name,
rlib,
no_prelude: false,
}
}

bytes.all(|b| b.is_ascii_hexdigit())
}
pub fn no_prelude(self) -> Self {
Self {
no_prelude: true,
..self
}
}

/// Paths to all of the library artifacts of dependencies needed to compile tests.
struct TestDeps {
core: PathBuf,
compiler_builtins: PathBuf,
spirv_std: PathBuf,
spirv_std_macros: PathBuf,
glam: PathBuf,
pub fn to_rustc_extern(&self) -> String {
let noprelude = if self.no_prelude { "noprelude:" } else { "" };
format!("--extern {noprelude}{}={}", self.name, self.rlib.display())
}
}

/// The RUSTFLAGS passed to all SPIR-V builds.
Expand Down
Loading