From 8681464af7e2500f371e5df6a95691cf29ecd16a Mon Sep 17 00:00:00 2001 From: Ashley Hauck Date: Fri, 23 Oct 2020 18:22:36 +0200 Subject: [PATCH] Add framework for compiler tests (#118) --- .github/workflows/ci.yaml | 1 + Cargo.lock | 1 + examples/example-runner/Cargo.toml | 6 +++ examples/example-shader/Cargo.toml | 3 ++ rustc_codegen_spirv/src/link.rs | 23 ++++++---- spirv-builder/Cargo.toml | 3 ++ spirv-builder/src/lib.rs | 5 ++- spirv-builder/src/test/basic.rs | 11 +++++ spirv-builder/src/test/mod.rs | 69 ++++++++++++++++++++++++++++++ spirv-std/Cargo.toml | 4 ++ 10 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 spirv-builder/src/test/basic.rs create mode 100644 spirv-builder/src/test/mod.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 88eb79c558..30754b2057 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,6 +32,7 @@ jobs: # Runs separately to add spir-v tools to Powershell's Path. run: echo "$HOME/spirv-tools/install/bin" >> $env:GITHUB_PATH - run: rustup component add rust-src rustc-dev llvm-tools-preview + - run: cargo build -p example-runner # See: https://github.com/EmbarkStudios/rust-gpu/issues/84 - if: ${{ runner.os == 'macOS' }} run: cargo test --workspace --exclude example-runner diff --git a/Cargo.lock b/Cargo.lock index 5bff8e86e4..7a58455a61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1195,6 +1195,7 @@ dependencies = [ name = "spirv-builder" version = "0.1.0" dependencies = [ + "lazy_static", "memchr", "raw-string", "rustc_codegen_spirv", diff --git a/examples/example-runner/Cargo.toml b/examples/example-runner/Cargo.toml index f309efb273..a2b08c032d 100644 --- a/examples/example-runner/Cargo.toml +++ b/examples/example-runner/Cargo.toml @@ -4,6 +4,12 @@ version = "0.1.0" authors = ["Embark "] edition = "2018" +# Note: Don't include this section in your own crates, these are just included here because our repo setup is weird. +[[bin]] +name = "example-runner" +doctest = false +test = false + [dependencies] ash = "0.31" ash-window = "0.5" diff --git a/examples/example-shader/Cargo.toml b/examples/example-shader/Cargo.toml index ced0d97744..bfd8e11a98 100644 --- a/examples/example-shader/Cargo.toml +++ b/examples/example-shader/Cargo.toml @@ -6,6 +6,9 @@ edition = "2018" [lib] crate-type = ["dylib"] +# Note: Don't include these two lines in your own crates, these are just included here because our repo setup is weird. +doctest = false +test = false [dependencies] spirv-std = { path = "../../spirv-std" } diff --git a/rustc_codegen_spirv/src/link.rs b/rustc_codegen_spirv/src/link.rs index ee7011a5d7..2550deb462 100644 --- a/rustc_codegen_spirv/src/link.rs +++ b/rustc_codegen_spirv/src/link.rs @@ -347,16 +347,23 @@ fn create_archive(files: &[&Path], metadata: &[u8], out_filename: &Path) { } pub fn read_metadata(rlib: &Path) -> Result { - for entry in Archive::new(File::open(rlib).unwrap()).entries().unwrap() { - let mut entry = entry.unwrap(); - if entry.path().unwrap() == Path::new(".metadata") { - let mut bytes = Vec::new(); - entry.read_to_end(&mut bytes).unwrap(); - let buf: OwningRef, [u8]> = OwningRef::new(bytes); - return Ok(rustc_erase_owner!(buf.map_owner_box())); + fn read_metadata_internal(rlib: &Path) -> Result, std::io::Error> { + for entry in Archive::new(File::open(rlib)?).entries()? { + let mut entry = entry?; + if entry.path()? == Path::new(".metadata") { + let mut bytes = Vec::new(); + entry.read_to_end(&mut bytes)?; + let buf: OwningRef, [u8]> = OwningRef::new(bytes); + return Ok(Some(rustc_erase_owner!(buf.map_owner_box()))); + } } + Ok(None) + } + match read_metadata_internal(rlib) { + Ok(Some(m)) => Ok(m), + Ok(None) => Err(format!("No .metadata file in rlib: {:?}", rlib)), + Err(io) => Err(format!("Failed to read rlib at {:?}: {}", rlib, io)), } - Err(format!("No .metadata file in rlib: {:?}", rlib)) } /// This is the actual guts of linking: the rest of the link-related functions are just digging through rustc's diff --git a/spirv-builder/Cargo.toml b/spirv-builder/Cargo.toml index 23c341da89..e49029d194 100644 --- a/spirv-builder/Cargo.toml +++ b/spirv-builder/Cargo.toml @@ -13,3 +13,6 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" # See comment in lib.rs invoke_rustc for why this is here rustc_codegen_spirv = { path = "../rustc_codegen_spirv" } + +[dev-dependencies] +lazy_static = "1.4" diff --git a/spirv-builder/src/lib.rs b/spirv-builder/src/lib.rs index d1cc52fe3b..43f29154c7 100644 --- a/spirv-builder/src/lib.rs +++ b/spirv-builder/src/lib.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod test; + mod depfile; use raw_string::{RawStr, RawString}; @@ -37,7 +40,7 @@ impl SpirvBuilder { } /// Whether to print build.rs cargo metadata (e.g. cargo:rustc-env=var=val). Defaults to true. - pub fn print_metadata(&mut self, v: bool) -> &mut Self { + pub fn print_metadata(mut self, v: bool) -> Self { self.print_metadata = v; self } diff --git a/spirv-builder/src/test/basic.rs b/spirv-builder/src/test/basic.rs new file mode 100644 index 0000000000..6d28e20687 --- /dev/null +++ b/spirv-builder/src/test/basic.rs @@ -0,0 +1,11 @@ +use super::val; + +#[test] +fn hello_world() { + val(r#" +#[allow(unused_attributes)] +#[spirv(entry = "fragment")] +pub fn main() { +} +"#); +} diff --git a/spirv-builder/src/test/mod.rs b/spirv-builder/src/test/mod.rs new file mode 100644 index 0000000000..4e7efa6f40 --- /dev/null +++ b/spirv-builder/src/test/mod.rs @@ -0,0 +1,69 @@ +mod basic; + +use lazy_static::lazy_static; +use std::error::Error; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; + +// Tests need to run serially, since they write project files to disk and whatnot. We don't want to +// create a new temp dir for every test, though, since then every test would need to build libcore. +// We could require the user to pass --thread-count 1 to cargo test, but that affects other tests. +// So make a global mutex wrapping every test. +lazy_static! { + static ref GLOBAL_MUTEX: Mutex<()> = Mutex::new(()); +} + +static CARGO_TOML: &str = r#"[package] +name = "test-project" +version = "0.1.0" +authors = ["Embark "] +edition = "2018" + +[lib] +crate-type = ["dylib"] + +[dependencies] +spirv-std = { path = "../../spirv-std" } + +[workspace] +"#; + +static SRC_PREFIX: &str = r#"#![no_std] +#![feature(lang_items, register_attr)] +#![register_attr(spirv)] +use core::panic::PanicInfo; +use spirv_std::*; +#[panic_handler] +fn panic(_: &PanicInfo) -> ! { + loop {} +} +#[lang = "eh_personality"] +extern "C" fn rust_eh_personality() {} +"#; + +fn setup(src: &str) -> Result> { + let project = Path::new("../target/test-spirv").to_owned(); + let cargo_toml = project.join("Cargo.toml"); + let lib_rs = project.join("src/lib.rs"); + std::fs::create_dir_all(lib_rs.parent().unwrap())?; + // don't write cargo.toml if unchanged, so it doesn't get deps refreshed + if std::fs::read(&cargo_toml).map_or(true, |b| b != CARGO_TOML.as_bytes()) { + std::fs::write(cargo_toml, CARGO_TOML)?; + } + std::fs::write(lib_rs, format!("{}{}", SRC_PREFIX, src))?; + Ok(project) +} + +fn build(src: &str) -> PathBuf { + let project = setup(src).expect("Failed to set up project"); + crate::SpirvBuilder::new(&project) + .print_metadata(false) + .build() + .expect("Failed to build test") +} + +fn val(src: &str) { + let _lock = GLOBAL_MUTEX.lock().unwrap(); + // spirv-val is included in building + build(src); +} diff --git a/spirv-std/Cargo.toml b/spirv-std/Cargo.toml index 5a32d7f970..521f1d7574 100644 --- a/spirv-std/Cargo.toml +++ b/spirv-std/Cargo.toml @@ -6,4 +6,8 @@ edition = "2018" license = "MIT OR Apache-2.0" repository = "https://github.com/EmbarkStudios/rust-gpu" +[lib] +doctest = false +test = false + [dependencies]