From 2f19f07ae3a7bb794686430c47460e8a585c90a8 Mon Sep 17 00:00:00 2001 From: Thomas Buckley-Houston Date: Tue, 17 Dec 2024 21:17:28 +0100 Subject: [PATCH] Use shader's Cargo.toml for rust-gpu version/toolchain We can still override the version and toolchain with CLI args. This commit just changes the defaults. I feel like there could be a lot of edge cases for this implementation. So I consider it more of a first draft. Notable changes: * `Spirv` renamed to `SpirvCLI`. * New `impl SpirvSource` that does all the shader crate querying. * CLI args change: `--spirv-builder` is now split into `--spirv-builder-source` and `--spirv-builder-version`. * `--shader-crate` now lives on the `install` subcommand, which because it is inherited by `build` (where it was originally), means it doesn't make much of a difference. * The full build test now has a teardown function making it idempotent. * Cache folder structure now has sub folders for `spirv-builder-cli`'s and `rust-gpu` repos. Things to consider: * Can we remove `TARGET_SPECS` now, because we have a copy of the `rust-gpu` repo, we can get them from there instead? * We have to copy the `shader-crate-template` outside of the workspace to get the tests to run. This is because recent Cargo now uses version 4 in `Cargo.lock` and the shader crate toolchain uses an older version of Cargo that doesn't recognise that version. But that doesn't seem right. Why is Cargo looking outside of the `shader-crate-template` anyway?? * What's the UX expectations for changing `spirv-std` versions or overriding `rust-gpu` versions and toolchain? I think in most cases `spirv-builder-cli` rebuilds should occur because the changes will cause cache directory changes. But I think it'd be good to at least manually test this. * Should the main build test be moved out into an integrations tests folder? Also it'd be good to have each test run in its own cache folder so that we can run more than one full build test at once. I'd still like to test each `spirv-builder-cli` feature, ie: `spirv-builder-pre-cli` and `spirv-builder-0_10`. We're currently only testing `spirv-builder-pre-cli`. --- Cargo.lock | 209 ++++++++++++++++++++- Cargo.toml | 5 +- README.md | 72 +++++--- crates/cargo-gpu/Cargo.toml | 3 + crates/cargo-gpu/src/build.rs | 58 ++++-- crates/cargo-gpu/src/install.rs | 93 +++++++--- crates/cargo-gpu/src/main.rs | 91 +++++---- crates/cargo-gpu/src/spirv_cli.rs | 123 +++++++------ crates/cargo-gpu/src/spirv_source.rs | 264 +++++++++++++++++++++++++++ crates/cargo-gpu/src/toml.rs | 41 +++-- crates/spirv-builder-cli/Cargo.toml | 33 ++-- 11 files changed, 796 insertions(+), 196 deletions(-) create mode 100644 crates/cargo-gpu/src/spirv_source.rs diff --git a/Cargo.lock b/Cargo.lock index e27864f..37d3787 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -85,12 +85,13 @@ dependencies = [ "chrono", "clap", "directories", - "env_logger", + "env_logger 0.10.2", "log", "relative-path", "serde", "serde_json", "spirv-builder-cli", + "test-log", "toml", ] @@ -176,6 +177,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", +] + [[package]] name = "env_home" version = "0.1.0" @@ -195,6 +205,18 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -287,6 +309,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.161" @@ -315,12 +343,31 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -331,12 +378,30 @@ dependencies = [ "libm", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + [[package]] name = "proc-macro2" version = "1.0.89" @@ -374,8 +439,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -386,9 +460,15 @@ checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.5", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.5" @@ -456,12 +536,21 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "spirv-builder-cli" version = "0.1.0" dependencies = [ "env_home", - "env_logger", + "env_logger 0.10.2", "log", "serde", "serde_json", @@ -536,6 +625,28 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "test-log" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" +dependencies = [ + "env_logger 0.11.5", + "test-log-macros", + "tracing-subscriber", +] + +[[package]] +name = "test-log-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "thiserror" version = "1.0.68" @@ -556,6 +667,16 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "toml" version = "0.8.19" @@ -590,6 +711,54 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "unicode-ident" version = "1.0.13" @@ -602,12 +771,34 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -617,6 +808,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 9dd7fcb..9dd7f6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ relative-path = "1.9.3" serde = { version = "1.0.214", features = ["derive"] } serde_json = "1.0.132" toml = "0.8.19" +test-log = "0.2.16" [workspace.lints.rust] missing_docs = "warn" @@ -46,7 +47,9 @@ pattern_type_mismatch = { level = "allow", priority = 1 } print_stdout = { level = "allow", priority = 1 } std_instead_of_alloc = { level = "allow", priority = 1 } -# TODO: Try to not depend on these lints +# TODO: Try to not depend on allowing these lints unwrap_used = { level = "allow", priority = 1 } +get_unwrap = { level = "allow", priority = 1 } +expect_used = { level = "allow", priority = 1 } panic = { level = "allow", priority = 1 } diff --git a/README.md b/README.md index 382fdfd..9e6bc3a 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,24 @@ # cargo-gpu + Command line tool for building Rust shaders using rust-gpu. ## Getting Started ### Installation -To install the tool ensure you have `rustup`. Then run: + +To install the tool ensure you have `rustup`. Then run: ``` cargo install --git https://github.com/rust-gpu/cargo-gpu ``` -After that you can use `cargo gpu` to compile your shader crates with: +After that you can use `cargo gpu` to compile your shader crates with: ``` cargo gpu build ``` -This plain invocation will compile the crate in the current directory and +This plain invocation will compile the crate in the current directory and place the compiled shaders in the current directory. Use `cargo gpu help` to see other options :) @@ -35,11 +37,12 @@ cargo gpu build ## Usage -``` +```` Commands: install Install rust-gpu compiler artifacts build Compile a shader crate to SPIR-V toml Compile a shader crate according to the `cargo gpu build` parameters found in the given toml file + show Show some useful values help Print this message or the help of the given subcommand(s) Options: @@ -57,17 +60,25 @@ Install rust-gpu compiler artifacts Usage: cargo-gpu install [OPTIONS] Options: - --spirv-builder - spirv-builder dependency, written just like in a Cargo.toml file + --shader-crate + Directory containing the shader crate to compile + + [default: ./] + + --spirv-builder-source + Source of `spirv-builder` dependency Eg: "https://github.com/Rust-GPU/rust-gpu" - [default: "{ git = \"https://github.com/Rust-GPU/rust-gpu.git\" }"] + --spirv-builder-version + Version of `spirv-builder` dependency. + * If `--spirv_builder_source` is not set, then this is assumed to be a crates.io semantic + version such as "0.9.0". + * If `--spirv_builder_source` is set, then this is assumed to be a Git "commitsh", such + as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. --rust-toolchain Rust toolchain channel to use to build `spirv-builder`. - This must match the `spirv_builder` argument. - - [default: nightly-2024-04-24] + This must be compatible with the `spirv_builder` argument as defined in the `rust-gpu` repo. --force-spirv-cli-rebuild Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt @@ -83,26 +94,29 @@ Compile a shader crate to SPIR-V Usage: cargo-gpu build [OPTIONS] Options: - --spirv-builder - spirv-builder dependency, written just like in a Cargo.toml file + --shader-crate + Directory containing the shader crate to compile - [default: "{ git = \"https://github.com/Rust-GPU/rust-gpu.git\" }"] + [default: ./] + + --spirv-builder-source + Source of `spirv-builder` dependency Eg: "https://github.com/Rust-GPU/rust-gpu" + + --spirv-builder-version + Version of `spirv-builder` dependency. + * If `--spirv_builder_source` is not set, then this is assumed to be a crates.io semantic + version such as "0.9.0". + * If `--spirv_builder_source` is set, then this is assumed to be a Git "commitsh", such + as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. --rust-toolchain Rust toolchain channel to use to build `spirv-builder`. - This must match the `spirv_builder` argument. - - [default: nightly-2024-04-24] + This must be compatible with the `spirv_builder` argument as defined in the `rust-gpu` repo. --force-spirv-cli-rebuild Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt - --shader-crate - Directory containing the shader crate to compile - - [default: ./] - --shader-target Shader target @@ -161,4 +175,18 @@ Options: -h, --help Print help (see a summary with '-h') -``` + +* Show + +Show some useful values + +Usage: cargo-gpu show [OPTIONS] + +Options: + --cache-directory + Displays the location of the cache directory + + -h, --help + Print help + +```` diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index 0935ad9..c567e2e 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -20,6 +20,9 @@ serde_json.workspace = true toml.workspace = true chrono.workspace = true +[dev-dependencies] +test-log.workspace = true + # Enable incremental by default in release mode. [profile.release] incremental = true diff --git a/crates/cargo-gpu/src/build.rs b/crates/cargo-gpu/src/build.rs index 665dd20..a562e56 100644 --- a/crates/cargo-gpu/src/build.rs +++ b/crates/cargo-gpu/src/build.rs @@ -12,11 +12,7 @@ use crate::{install::Install, target_spec_dir}; pub struct Build { /// Install the `rust-gpu` compiler and components #[clap(flatten)] - install: Install, - - /// Directory containing the shader crate to compile. - #[clap(long, default_value = "./")] - pub shader_crate: std::path::PathBuf, + pub install: Install, /// Shader target. #[clap(long, default_value = "spirv-unknown-vulkan1.2")] @@ -46,17 +42,17 @@ impl Build { self.output_dir = self.output_dir.canonicalize().unwrap(); // Ensure the shader crate exists - self.shader_crate = self.shader_crate.canonicalize().unwrap(); + self.install.shader_crate = self.install.shader_crate.canonicalize().unwrap(); assert!( - self.shader_crate.exists(), + self.install.shader_crate.exists(), "shader crate '{}' does not exist. (Current dir is '{}')", - self.shader_crate.display(), + self.install.shader_crate.display(), std::env::current_dir().unwrap().display() ); let spirv_builder_args = spirv_builder_cli::Args { dylib_path, - shader_crate: self.shader_crate.clone(), + shader_crate: self.install.shader_crate.clone(), shader_target: self.shader_target.clone(), path_to_target_spec: target_spec_dir().join(format!("{}.json", self.shader_target)), no_default_features: self.no_default_features, @@ -101,8 +97,10 @@ impl Build { use relative_path::PathExt as _; let path = self.output_dir.join(filepath.file_name().unwrap()); std::fs::copy(&filepath, &path).unwrap(); - let path_relative_to_shader_crate = - path.relative_to(&self.shader_crate).unwrap().to_path(""); + let path_relative_to_shader_crate = path + .relative_to(&self.install.shader_crate) + .unwrap() + .to_path(""); Linkage::new(entry, path_relative_to_shader_crate) }, ) @@ -140,3 +138,41 @@ impl Build { } } } + +#[cfg(test)] +mod test { + use crate::{cache_dir, Cli, Command}; + + use super::*; + + #[test_log::test] + fn builder_from_params() { + crate::test::tests_teardown(); + + // We need to copy the shader crate template so that the workspace doesn't interfere with compilation. + let shader_crate_source = std::path::PathBuf::from("../shader-crate-template"); + let shader_crate_destination = cache_dir().join("shader-crate-template"); + let output_dir = shader_crate_destination.join("shaders"); + crate::test::copy_dir_all(shader_crate_source, shader_crate_destination.clone()).unwrap(); + + let args = [ + "target/debug/cargo-gpu", + "build", + "--shader-crate", + &format!("{}", shader_crate_destination.display()), + "--output-dir", + &format!("{}", output_dir.display()), + ]; + if let Cli { + command: Command::Build(mut build), + } = Cli::parse_from(args) + { + assert_eq!(shader_crate_destination, build.install.shader_crate); + assert_eq!(output_dir, build.output_dir); + + build.run(); + } else { + panic!("was not a build command"); + } + } +} diff --git a/crates/cargo-gpu/src/install.rs b/crates/cargo-gpu/src/install.rs index 68d4f4c..ae3072d 100644 --- a/crates/cargo-gpu/src/install.rs +++ b/crates/cargo-gpu/src/install.rs @@ -1,7 +1,7 @@ //! Install a dedicated per-shader crate that has the `rust-gpu` compiler in it. use std::io::Write as _; -use crate::{cache_dir, spirv_cli::Spirv, target_spec_dir}; +use crate::{cache_dir, spirv_cli::SpirvCLI, spirv_source::SpirvSource, target_spec_dir}; /// These are the files needed to create the dedicated, per-shader `rust-gpu` builder create. const SPIRV_BUILDER_FILES: &[(&str, &str)] = &[ @@ -86,15 +86,32 @@ const TARGET_SPECS: &[(&str, &str)] = &[ /// `cargo gpu install` #[derive(clap::Parser, Debug)] pub struct Install { - /// spirv-builder dependency, written just like in a Cargo.toml file. - #[clap(long, default_value = Spirv::DEFAULT_DEP)] - spirv_builder: String, + /// Directory containing the shader crate to compile. + #[clap(long, default_value = "./")] + pub shader_crate: std::path::PathBuf, + + #[expect( + clippy::doc_markdown, + reason = "The URL should appear literally like this. But Clippy wants it to be a in markdown clickable link" + )] + /// Source of `spirv-builder` dependency + /// Eg: "https://github.com/Rust-GPU/rust-gpu" + #[clap(long)] + spirv_builder_source: Option, + + /// Version of `spirv-builder` dependency. + /// * If `--spirv_builder_source` is not set, then this is assumed to be a crates.io semantic + /// version such as "0.9.0". + /// * If `--spirv_builder_source` is set, then this is assumed to be a Git "commitsh", such + /// as a Git commit hash or a Git tag, therefore anything that `git checkout` can resolve. + #[clap(long, verbatim_doc_comment)] + spirv_builder_version: Option, /// Rust toolchain channel to use to build `spirv-builder`. /// /// This must be compatible with the `spirv_builder` argument as defined in the `rust-gpu` repo. - #[clap(long, default_value = Spirv::DEFAULT_CHANNEL)] - rust_toolchain: String, + #[clap(long)] + rust_toolchain: Option, /// Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt. #[clap(long)] @@ -102,30 +119,60 @@ pub struct Install { } impl Install { - /// Returns a [`Spirv`] instance, responsible for ensuring the right version of the `spirv-builder-cli` crate. - fn spirv_cli(&self) -> Spirv { - Spirv { - dep: self.spirv_builder.clone(), - channel: self.rust_toolchain.clone(), - } + /// Returns a [`SpirvCLI`] instance, responsible for ensuring the right version of the `spirv-builder-cli` crate. + fn spirv_cli(&self, shader_crate_path: &std::path::PathBuf) -> SpirvCLI { + SpirvCLI::new( + shader_crate_path, + self.spirv_builder_source.clone(), + self.spirv_builder_version.clone(), + self.rust_toolchain.clone(), + ) } /// Create the `spirv-builder-cli` crate. fn write_source_files(&self) { - let cli = self.spirv_cli(); - let checkout = cli.cached_checkout_path(); + let spirv_cli = self.spirv_cli(&self.shader_crate); + let checkout = spirv_cli.cached_checkout_path(); std::fs::create_dir_all(checkout.join("src")).unwrap(); for (filename, contents) in SPIRV_BUILDER_FILES { log::debug!("writing {filename}"); let path = checkout.join(filename); let mut file = std::fs::File::create(&path).unwrap(); - let replaced_contents = contents - .replace("${SPIRV_BUILDER_SOURCE}", &cli.dep) - .replace("${CHANNEL}", &cli.channel); + let mut replaced_contents = contents.replace("${CHANNEL}", &spirv_cli.channel); + if filename == &"Cargo.toml" { + replaced_contents = Self::update_cargo_toml(&replaced_contents, &spirv_cli.source); + } file.write_all(replaced_contents.as_bytes()).unwrap(); } } + /// Create the `spirv-builder-cli` crate. + fn update_cargo_toml(contents: &str, spirv_source: &SpirvSource) -> String { + let updated = contents.lines().map(|line| { + if line.contains("${AUTO-REPLACE-SOURCE}") { + let replaced_line = match spirv_source { + SpirvSource::CratesIO(_) => String::new(), + SpirvSource::Git((repo, _)) => format!("git = \"{repo}\""), + }; + return format!("{replaced_line}\n"); + } + + if line.contains("${AUTO-REPLACE-VERSION}") { + let replaced_line = match spirv_source { + SpirvSource::CratesIO(version) => { + format!("version = \"{}\"", version.replace('v', "")) + } + SpirvSource::Git((_, revision)) => format!("rev = \"{revision}\""), + }; + return format!("{replaced_line}\n"); + } + + format!("{line}\n") + }); + + updated.collect() + } + /// Add the target spec files to the crate. fn write_target_spec_files(&self) { for (filename, contents) in TARGET_SPECS { @@ -150,8 +197,7 @@ impl Install { panic!("could not create cache dir"); }); - let spirv_version = self.spirv_cli(); - spirv_version.ensure_version_channel_compatibility(); + let spirv_version = self.spirv_cli(&self.shader_crate); spirv_version.ensure_toolchain_and_components_exist(); let checkout = spirv_version.cached_checkout_path(); @@ -191,7 +237,7 @@ impl Install { command.args([ "--features", - &Self::get_required_spirv_builder_version(&spirv_version.channel), + &Self::get_required_spirv_builder_version(spirv_version.date), ]); log::debug!("building artifacts with `{:?}`", command); @@ -237,16 +283,13 @@ impl Install { /// here we choose the right Cargo feature to enable/disable code in `spirv-builder-cli`. /// /// TODO: - /// * Download the actual `rust-gpu` repo as pinned in the shader's `Cargo.lock` and get the - /// `spirv-builder` version from there. /// * Warn the user that certain `cargo-gpu` features aren't available when building with /// older versions of `spirv-builder`, eg setting the target spec. - fn get_required_spirv_builder_version(toolchain_channel: &str) -> String { + fn get_required_spirv_builder_version(date: chrono::NaiveDate) -> String { let parse_date = chrono::NaiveDate::parse_from_str; - let datetime = parse_date(toolchain_channel, "nightly-%Y-%m-%d").unwrap(); let pre_cli_date = parse_date("2024-04-24", "%Y-%m-%d").unwrap(); - if datetime < pre_cli_date { + if date < pre_cli_date { "spirv-builder-pre-cli" } else { "spirv-builder-0_10" diff --git a/crates/cargo-gpu/src/main.rs b/crates/cargo-gpu/src/main.rs index 542b847..d23b3a5 100644 --- a/crates/cargo-gpu/src/main.rs +++ b/crates/cargo-gpu/src/main.rs @@ -60,6 +60,7 @@ mod build; mod install; mod show; mod spirv_cli; +mod spirv_source; mod toml; fn main() { @@ -118,13 +119,19 @@ pub(crate) struct Cli { } fn cache_dir() -> std::path::PathBuf { - directories::BaseDirs::new() + let dir = directories::BaseDirs::new() .unwrap_or_else(|| { log::error!("could not find the user home directory"); panic!("cache_dir failed"); }) .cache_dir() - .join("rust-gpu") + .join("rust-gpu"); + + if cfg!(test) { + dir.join("tests") + } else { + dir + } } /// Location of the target spec metadata files @@ -171,55 +178,45 @@ fn write_help(buffer: &mut impl std::io::Write, cmd: &mut clap::Command, _depth: } } +/// Returns a string suitable to use as a directory. +/// +/// Created from the spirv-builder source dep and the rustc channel. +fn to_dirname(text: &str) -> String { + text.replace( + [std::path::MAIN_SEPARATOR, '\\', '/', '.', ':', '@', '='], + "_", + ) + .split(['{', '}', ' ', '\n', '"', '\'']) + .collect::>() + .concat() +} + #[cfg(test)] mod test { - use spirv_cli::Spirv as SpirvCLI; - - use super::*; - - #[test] - fn cached_checkout_dir_sanity() { - // Test that - let spirv = SpirvCLI::default(); - let dir = spirv.cached_checkout_path(); - let name = dir - .file_name() - .unwrap() - .to_str() - .map(std::string::ToString::to_string) - .unwrap(); - assert_eq!( - "git_https___github_com_Rust-GPU_rust-gpu_git+nightly-2024-04-24", - &name - ); + use crate::cache_dir; + + pub fn shader_crate_template_path() -> std::path::PathBuf { + std::path::PathBuf::from("../shader-crate-template") + } + + pub fn tests_teardown() { + std::fs::remove_dir_all(cache_dir()).unwrap(); } - #[test] - fn builder_from_params() { - let shader_crate = std::path::PathBuf::from("../shader-crate-template"); - let output_dir = std::path::PathBuf::from("../shader-crate-template/shaders"); - let args = [ - "target/debug/cargo-gpu", - "build", - "--shader-crate", - &format!("{}", shader_crate.display()), - "--output-dir", - &format!("{}", output_dir.display()), - ]; - if let Cli { - command: Command::Build(mut build), - } = Cli::parse_from(args) - { - assert_eq!(shader_crate, build.shader_crate); - assert_eq!(output_dir, build.output_dir); - - // TODO: - // What's the best way to reset caches for this? For example we could add a - // `--force-spirv-cli-rebuild`, but that would slow down each test. But without - // something like that we might not be getting actual idempotent tests. - build.run(); - } else { - panic!("was not a build command"); + pub fn copy_dir_all( + src: impl AsRef, + dst: impl AsRef, + ) -> std::io::Result<()> { + std::fs::create_dir_all(&dst)?; + for maybe_entry in std::fs::read_dir(src)? { + let entry = maybe_entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } } + Ok(()) } } diff --git a/crates/cargo-gpu/src/spirv_cli.rs b/crates/cargo-gpu/src/spirv_cli.rs index 4c114b0..7a66a8b 100644 --- a/crates/cargo-gpu/src/spirv_cli.rs +++ b/crates/cargo-gpu/src/spirv_cli.rs @@ -1,64 +1,70 @@ -//! Install the relevant Rust compiler and toolchain components required by the version of -//! `rust-gpu` defined in the shader. -use crate::cache_dir; +//! Query the shader crate to find what version of `rust-gpu` it depends on. +//! Then ensure that the relevant Rust toolchain and components are installed. -/// The canonical pairs of `rust-gpu` version to `rust-gpu` Rust toolchain channel. -/// -/// TODO: We may be able to automate this by checking out the locked version of `spirv-std` in the -/// shader's crate. -const SPIRV_STD_TOOLCHAIN_PAIRS: &[(&str, &str)] = &[("0.10", "nightly-2024-04-24")]; +use crate::spirv_source::SpirvSource; /// Cargo dependency for `spirv-builder` and the rust toolchain channel. #[derive(Debug, Clone)] -pub struct Spirv { - /// The version of `rust-gpu`, eg `"0.10"` or `"{ git = "https://github.com/Rust-GPU/rust-gpu.git" }` - pub dep: String, - //// The toolchain that `rust-gpu` uses, eg "nightly-2024-04-24" +pub struct SpirvCLI { + #[expect( + clippy::doc_markdown, + reason = "The URL should appear literally like this. But Clippy wants it to be a in markdown clickable link" + )] + /// The source and version of `rust-gpu`. + /// Eg: + /// * From crates.io with version "0.10.0" + /// * From Git with: + /// - a repo of "https://github.com/Rust-GPU/rust-gpu.git" + /// - a revision of "abc213" + pub source: SpirvSource, + /// The toolchain channel that `rust-gpu` uses, eg "nightly-2024-04-24" pub channel: String, + /// The date of the pinned version of `rust-gpu` + pub date: chrono::NaiveDate, } -impl Default for Spirv { - fn default() -> Self { - Self { - dep: Self::DEFAULT_DEP.into(), - channel: Self::DEFAULT_CHANNEL.into(), - } - } -} - -impl core::fmt::Display for Spirv { +impl core::fmt::Display for SpirvCLI { #[expect( clippy::min_ident_chars, reason = "It's a core library trait implementation" )] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - format!("{}+{}", self.dep, self.channel).fmt(f) + format!("{}+{}", self.source, self.channel).fmt(f) } } -impl Spirv { - /// The default `rust-gpu` dependency defintion - pub const DEFAULT_DEP: &str = r#"{ git = "https://github.com/Rust-GPU/rust-gpu.git" }"#; - /// The default `rust-gpu` toolchain - pub const DEFAULT_CHANNEL: &str = "nightly-2024-04-24"; +impl SpirvCLI { + /// Create instance + pub fn new( + shader_crate_path: &std::path::PathBuf, + maybe_rust_gpu_source: Option, + maybe_rust_gpu_version: Option, + maybe_rust_gpu_channel: Option, + ) -> Self { + let (default_rust_gpu_source, rust_gpu_date, default_rust_gpu_channel) = + SpirvSource::get_rust_gpu_deps_from_shader(shader_crate_path); - /// Returns a string suitable to use as a directory. - /// - /// Created from the spirv-builder source dep and the rustc channel. - fn to_dirname(&self) -> String { - self.to_string() - .replace( - [std::path::MAIN_SEPARATOR, '\\', '/', '.', ':', '@', '='], - "_", - ) - .split(['{', '}', ' ', '\n', '"', '\'']) - .collect::>() - .concat() + let mut maybe_spirv_source: Option = None; + if let Some(rust_gpu_version) = maybe_rust_gpu_version { + let mut source = SpirvSource::CratesIO(rust_gpu_version.clone()); + if let Some(rust_gpu_source) = maybe_rust_gpu_source { + source = SpirvSource::Git((rust_gpu_source, rust_gpu_version)); + } + maybe_spirv_source = Some(source); + } + + Self { + source: maybe_spirv_source.unwrap_or(default_rust_gpu_source), + channel: maybe_rust_gpu_channel.unwrap_or(default_rust_gpu_channel), + date: rust_gpu_date, + } } /// Create and/or return the cache directory pub fn cached_checkout_path(&self) -> std::path::PathBuf { - let checkout_dir = cache_dir().join(self.to_dirname()); + let checkout_dir = crate::cache_dir() + .join("spirv-builder-clis") + .join(crate::to_dirname(self.to_string().as_ref())); std::fs::create_dir_all(&checkout_dir).unwrap_or_else(|error| { log::error!( "could not create checkout dir '{}': {error}", @@ -70,20 +76,6 @@ impl Spirv { checkout_dir } - /// Ensure that the requested `rust-gpu` version/toolchain are known to be canonically - /// compatible. - /// - /// TODO: We may be able to automatically get the pair by downloading the `rust-gpu` repo as defined by the - /// `spriv-std` dependency in the shader. - pub fn ensure_version_channel_compatibility(&self) { - for (version, channel) in SPIRV_STD_TOOLCHAIN_PAIRS { - assert!( - !(version.starts_with(&self.dep) && channel != &self.channel), - "expected spirv-std version to be matched with rust toolchain channel {channel}" - ); - } - } - /// Use `rustup` to install the toolchain and components, if not already installed. /// /// Pretty much runs: @@ -158,3 +150,24 @@ impl Spirv { } } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn cached_checkout_dir_sanity() { + let spirv = SpirvCLI::new(&"./".into(), None, None, None); + let dir = spirv.cached_checkout_path(); + let name = dir + .file_name() + .unwrap() + .to_str() + .map(std::string::ToString::to_string) + .unwrap(); + assert_eq!( + "https___github_com_Rust-GPU_rust-gpu+v0_9_0+nightly-2023-05-27", + &name + ); + } +} diff --git a/crates/cargo-gpu/src/spirv_source.rs b/crates/cargo-gpu/src/spirv_source.rs new file mode 100644 index 0000000..23acd0e --- /dev/null +++ b/crates/cargo-gpu/src/spirv_source.rs @@ -0,0 +1,264 @@ +//! Use the shader that we're compiling as the default source for which version of `rust-gpu` to use. +//! +//! We do this by calling `cargo tree` inside the shader's crate to get the defined `spirv-std` +//! version. Then with that we `git checkout` the `rust-gpu` repo that corresponds to that version. +//! From there we can look at the source code to get the required Rust toolchain. + +/// The canonical `rust-gpu` URI +const RUST_GPU_REPO: &str = "https://github.com/Rust-GPU/rust-gpu"; + +/// The various sources that the `rust-gpu` repo can have. +/// Most commonly it will simply be the canonical version on crates.io. But it could also be the +/// Git version, or a fork. +#[derive(Eq, PartialEq, Clone, Debug)] +pub enum SpirvSource { + /// If the shader specifies a simple version like `spirv-std = "0.9.0"` then the source of + /// `rust-gpu` is the conventional crates.io version. + /// + /// `String` is the simple version like, "0.9.0" + CratesIO(String), + /// If the shader specifies a version like: + /// `spirv-std = { git = "https://github.com..." ... }` + /// then the source of `rust-gpu` is `Git`. + /// + /// `(String, String)` is the repo source and revision hash or tag. + Git((String, String)), +} + +impl core::fmt::Display for SpirvSource { + #[expect( + clippy::min_ident_chars, + reason = "It's a core library trait implementation" + )] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + format!("{}+{}", self.to_repo(), self.to_version()).fmt(f) + } +} + +impl SpirvSource { + /// Look into the shader crate to get the version of `rust-gpu` it's using. + pub fn get_rust_gpu_deps_from_shader( + shader_crate_path: &std::path::PathBuf, + ) -> (Self, chrono::NaiveDate, String) { + let rust_gpu_source = Self::get_spirv_std_dep_defintiion(shader_crate_path); + + rust_gpu_source.ensure_repo_is_installed(); + rust_gpu_source.checkout(); + + let date = rust_gpu_source.get_version_date(); + let channel = Self::get_channel_from_toolchain_toml(&rust_gpu_source.to_dirname()); + + log::debug!("Parsed version, date and toolchain channel from shader-defined `rust-gpu`: {rust_gpu_source:?}, {date}, {channel}"); + + (rust_gpu_source, date, channel) + } + + /// Convert the source to just its version. + pub fn to_version(&self) -> String { + match self { + Self::CratesIO(version) => version.to_string(), + Self::Git((_, revision)) => revision.to_string(), + } + } + + /// Convert the source to just its repo. + fn to_repo(&self) -> String { + match self { + Self::CratesIO(_) => RUST_GPU_REPO.to_owned(), + Self::Git((repo, _)) => repo.to_owned(), + } + } + + /// Convert the `rust-gpu` source into a string that can be used as a directory. + /// It needs to be dynamically created because an end-user might want to swap out the source, + /// maybe using their own fork for example. + fn to_dirname(&self) -> std::path::PathBuf { + let dir = crate::to_dirname(self.to_string().as_ref()); + crate::cache_dir().join("rust-gpu_repos").join(dir) + } + + /// Checkout the `rust-gpu` to the requested version. + fn checkout(&self) { + log::debug!( + "Checking out `rust-gpu` repo at {} to {}", + self.to_dirname().display(), + self.to_version() + ); + let output_checkout = std::process::Command::new("git") + .current_dir(self.to_dirname()) + .args(["checkout", self.to_version().as_ref()]) + .output() + .unwrap(); + assert!( + output_checkout.status.success(), + "couldn't checkout revision '{}' of `rust-gpu` at {}", + self.to_version(), + self.to_dirname().to_string_lossy() + ); + } + + /// Get the date of the version of `rust-gpu` used by the shader. This allows us to know what + /// features we can use in the `spirv-builder` crate. + fn get_version_date(&self) -> chrono::NaiveDate { + let date_format = "%Y-%m-%d"; + + log::debug!( + "Getting `rust-gpu` version date from {}", + self.to_dirname().display(), + ); + let output_date = std::process::Command::new("git") + .current_dir(self.to_dirname()) + .args([ + "show", + "--no-patch", + "--format=%cd", + format!("--date=format:'{date_format}'").as_ref(), + self.to_version().as_ref(), + ]) + .output() + .unwrap(); + assert!( + output_date.status.success(), + "couldn't get `rust-gpu` version date at for {} at {}", + self.to_version(), + self.to_dirname().to_string_lossy() + ); + let date_string = String::from_utf8_lossy(&output_date.stdout) + .to_string() + .trim() + .replace('\'', ""); + + log::debug!( + "Parsed date for version {}: {date_string}", + self.to_version() + ); + + chrono::NaiveDate::parse_from_str(&date_string, date_format).unwrap() + } + + /// Parse the `rust-toolchain.toml` in the working tree of the checked-out version of the `rust-gpu` repo. + fn get_channel_from_toolchain_toml(path: &std::path::PathBuf) -> String { + log::debug!("Parsing `rust-toolchain.toml` at {path:?} for the used toolchain"); + + let contents = std::fs::read_to_string(path.join("rust-toolchain.toml")).unwrap(); + let toml: toml::Table = toml::from_str(&contents).unwrap(); + let Some(toolchain) = toml.get("toolchain") else { + panic!("Couldn't find `[toolchain]` section in `rust-toolchain.toml` at {path:?}"); + }; + let Some(channel) = toolchain.get("channel") else { + panic!("Couldn't find `channel` field in `rust-toolchain.toml` at {path:?}"); + }; + + channel.to_string().replace('"', "") + } + + /// Get the shader crate's `spirv_std = ...` definition in its `Cargo.toml` + fn get_spirv_std_dep_defintiion(shader_crate_path: &std::path::PathBuf) -> Self { + log::debug!("Running `cargo tree` on {}", shader_crate_path.display()); + let output_cargo_tree = std::process::Command::new("cargo") + .current_dir(shader_crate_path) + .args(["tree", "--workspace", "--depth", "1", "--prefix", "none"]) + .output() + .unwrap(); + assert!( + output_cargo_tree.status.success(), + "could not query shader's `Cargo.toml` for `spirv-std` dependency" + ); + let cargo_tree_string = String::from_utf8_lossy(&output_cargo_tree.stdout); + + let maybe_spirv_std_def = cargo_tree_string + .lines() + .find(|line| line.contains("spirv-std")); + + let Some(spirv_std_def) = maybe_spirv_std_def else { + panic!(""); + }; + + Self::parse_spirv_std_source_and_version(spirv_std_def) + } + + /// Parse a string like: + /// `spirv-std v0.9.0 (https://github.com/EmbarkStudios/rust-gpu#54f6978c) (*)` + /// Which would return: + /// `("54f6978c", SpirvSource::Git("https://github.com/EmbarkStudios/rust-gpu"))` + fn parse_spirv_std_source_and_version(spirv_std_def: &str) -> Self { + let parts: Vec = spirv_std_def.split_whitespace().map(String::from).collect(); + let version = parts + .get(1) + .expect("Couldn't find `spirv_std` version in shader crate") + .to_owned(); + let mut source = Self::CratesIO(version); + + if parts.len() > 2 { + let revision_marker = "#"; + let mut source_string = parts.get(2).unwrap().to_owned(); + source_string = source_string.replace(['(', ')'], ""); + if source_string.contains(revision_marker) { + let source_parts: Vec = source_string + .split(revision_marker) + .map(String::from) + .collect(); + let repo = source_parts.first().unwrap().to_owned(); + let revision = source_parts.last().unwrap().to_owned(); + source = Self::Git((repo, revision)); + } + } + + log::debug!("Parsed `rust-gpu` source and version: {source:?}"); + + source + } + + /// `git clone` the `rust-gpu` repo. We use it to get the required Rust toolchain to compile + /// the shader. + fn ensure_repo_is_installed(&self) { + if self.to_dirname().exists() { + log::debug!( + "Not cloning `rust-gpu` repo ({}) as it already exists at {}", + self.to_repo(), + self.to_dirname().to_string_lossy().as_ref(), + ); + return; + } + + log::debug!( + "Cloning `rust-gpu` repo {} to {}", + self.to_repo(), + self.to_dirname().to_string_lossy().as_ref(), + ); + + std::process::Command::new("git") + .args([ + "clone", + self.to_repo().as_ref(), + self.to_dirname().to_string_lossy().as_ref(), + ]) + .output() + .unwrap(); + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn parsing_spirv_std_dep_for_shader_template() { + let shader_template_path = crate::test::shader_crate_template_path(); + let source = SpirvSource::get_spirv_std_dep_defintiion(&shader_template_path); + assert_eq!(source, SpirvSource::CratesIO("v0.9.0".to_owned())); + } + + #[test] + fn parsing_spirv_std_dep_for_git_source() { + let definition = "spirv-std v9.9.9 (https://github.com/Rust-GPU/rust-gpu#54f6978c) (*)"; + let source = SpirvSource::parse_spirv_std_source_and_version(definition); + assert_eq!( + source, + SpirvSource::Git(( + "https://github.com/Rust-GPU/rust-gpu".to_owned(), + "54f6978c".to_owned() + )) + ); + } +} diff --git a/crates/cargo-gpu/src/toml.rs b/crates/cargo-gpu/src/toml.rs index ab360ef..cf76f7d 100644 --- a/crates/cargo-gpu/src/toml.rs +++ b/crates/cargo-gpu/src/toml.rs @@ -37,25 +37,9 @@ pub struct Toml { impl Toml { /// Entrypoint pub fn run(&self) { - // Find the path to the toml file to use - let path = if self.path.is_file() && self.path.ends_with(".toml") { - self.path.clone() - } else { - let path = self.path.join("Cargo.toml"); - if path.is_file() { - path - } else { - log::error!("toml file '{}' is not a file", self.path.display()); - panic!("toml file '{}' is not a file", self.path.display()); - } - }; - - log::info!("using toml file '{}'", path.display()); + let (path, toml) = Self::parse_cargo_toml(self.path.clone()); // Determine if this is a workspace's Cargo.toml or a crate's Cargo.toml - let contents = std::fs::read_to_string(&path).unwrap(); - let toml: toml::Table = toml::from_str(&contents).unwrap(); - let (toml_type, table) = if toml.contains_key("workspace") { let table = Self::get_metadata_rustgpu_table(&toml, "workspace") .unwrap_or_else(|| { @@ -134,6 +118,29 @@ impl Toml { } } + /// Parse the contents of the shader's `Cargo.toml` + pub fn parse_cargo_toml(mut path: std::path::PathBuf) -> (std::path::PathBuf, toml::Table) { + // Find the path to the toml file to use + let parsed_path = if path.is_file() && path.ends_with(".toml") { + path + } else { + path = path.join("Cargo.toml"); + if path.is_file() { + path + } else { + log::error!("toml file '{}' is not a file", path.display()); + panic!("toml file '{}' is not a file", path.display()); + } + }; + + log::info!("using toml file '{}'", parsed_path.display()); + + let contents = std::fs::read_to_string(&parsed_path).unwrap(); + let toml: toml::Table = toml::from_str(&contents).unwrap(); + + (parsed_path, toml) + } + /// Parse the `[package.metadata.rust-gpu]` section. fn get_metadata_rustgpu_table<'toml>( toml: &'toml toml::Table, diff --git a/crates/spirv-builder-cli/Cargo.toml b/crates/spirv-builder-cli/Cargo.toml index 67f9ee8..c89b824 100644 --- a/crates/spirv-builder-cli/Cargo.toml +++ b/crates/spirv-builder-cli/Cargo.toml @@ -4,6 +4,11 @@ version = "0.1.0" edition = "2021" [lib] +path = "src/lib.rs" + +[[bin]] +name = "spirv-builder-cli" +path = "src/main.rs" [dependencies] env_home = "0.1.0" @@ -13,18 +18,6 @@ serde = "1.0.214" serde_json = "1.0.132" toml = "0.8.19" -[dependencies.spirv-builder-pre-cli] -package = "spirv-builder" -optional = true -git = "https://github.com/Rust-GPU/rust-gpu" -rev = "4c633aec" - -[dependencies.spirv-builder-0_10] -package = "spirv-builder" -optional = true -git = "https://github.com/Rust-GPU/rust-gpu" -rev = "60dcb82" - [features] default = ["spirv-builder-0_10"] # The `spirv-builder` before `cargo gpu` existed. It has an incompatible `SpirvBuilder` interface. @@ -32,3 +25,19 @@ spirv-builder-pre-cli = ["dep:spirv-builder-pre-cli"] # The first version that introduced `cargo gpu`. It has some extra `.builder()` args that make # dynamically changing build dependencies easier. spirv-builder-0_10 = ["dep:spirv-builder-0_10"] + +# NB: All the `${AUTO-REPLACE*}` tokens in each feature get replaced with the same values. +# This is because only one feature can ever be used at once and it makes it easier to just +# replace each token rather than figure out to what feature each token belongs. + +[dependencies.spirv-builder-pre-cli] +package = "spirv-builder" +optional = true +git = "https://github.com/Rust-GPU/rust-gpu" # ${AUTO-REPLACE-SOURCE} +rev = "4c633aec" # ${AUTO-REPLACE-VERSION} + +[dependencies.spirv-builder-0_10] +package = "spirv-builder" +optional = true +git = "https://github.com/Rust-GPU/rust-gpu" # ${AUTO-REPLACE-SOURCE} +rev = "60dcb82" # ${AUTO-REPLACE-VERSION}