From 2280193ada89f57ef6eb711eea34508febe91228 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 12:06:12 +0100 Subject: [PATCH 1/8] install-crate: move crate properties (version, edition) to workspace --- Cargo.toml | 8 ++++++++ crates/cargo-gpu/Cargo.toml | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7c66d0a..8d3b5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,14 @@ exclude = [ resolver = "2" +[workspace.package] +version = "0.1.0" +edition = "2021" +repository = "https://github.com/Rust-GPU/cargo-gpu" +readme = "./README.md" +keywords = ["gpu", "compiler", "rust-gpu"] +license = "MIT OR Apache-2.0" + [workspace.dependencies] spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "823b0c275e3eb8ab44ada5a6d989bdb57e8f9409", default-features = false } anyhow = "1.0.98" diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index 81c8a87..d451396 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "cargo-gpu" -version = "0.1.0" -edition = "2021" +version.workspace = true +edition.workspace = true description = "Generates shader .spv files from rust-gpu shader crates" -repository = "https://github.com/Rust-GPU/cargo-gpu" -readme = "../../README.md" -keywords = ["gpu", "compiler", "rust-gpu"] -license = "MIT OR Apache-2.0" +repository.workspace = true +readme.workspace = true +keywords.workspace = true +license.workspace = true default-run = "cargo-gpu" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 7dacbb7946a6ede1b3323b74179312a9555e01d0 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 12:18:03 +0100 Subject: [PATCH 2/8] install-crate: move install action to new `cargo-gpu-install` crate --- Cargo.lock | 23 ++++++ Cargo.toml | 2 + crates/cargo-gpu-install/Cargo.toml | 36 +++++++++ crates/cargo-gpu-install/README.md | 43 ++++++++++ .../src/install.rs | 0 .../src/install_toolchain.rs | 0 crates/cargo-gpu-install/src/lib.rs | 64 +++++++++++++++ .../src/spirv_source.rs | 0 .../src/test.rs | 2 +- crates/cargo-gpu/Cargo.toml | 2 + crates/cargo-gpu/src/lib.rs | 80 +++---------------- 11 files changed, 180 insertions(+), 72 deletions(-) create mode 100644 crates/cargo-gpu-install/Cargo.toml create mode 100644 crates/cargo-gpu-install/README.md rename crates/{cargo-gpu => cargo-gpu-install}/src/install.rs (100%) rename crates/{cargo-gpu => cargo-gpu-install}/src/install_toolchain.rs (100%) create mode 100644 crates/cargo-gpu-install/src/lib.rs rename crates/{cargo-gpu => cargo-gpu-install}/src/spirv_source.rs (100%) rename crates/{cargo-gpu => cargo-gpu-install}/src/test.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 4bf2427..1946e5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,29 @@ dependencies = [ [[package]] name = "cargo-gpu" version = "0.1.0" +dependencies = [ + "anyhow", + "cargo-gpu-install", + "cargo-util-schemas", + "cargo_metadata", + "clap", + "crossterm", + "directories", + "dunce", + "env_logger", + "log", + "relative-path", + "semver", + "serde", + "serde_json", + "spirv-builder", + "tempfile", + "test-log", +] + +[[package]] +name = "cargo-gpu-install" +version = "0.1.0" dependencies = [ "anyhow", "cargo-util-schemas", diff --git a/Cargo.toml b/Cargo.toml index 8d3b5fd..b9ad742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "crates/cargo-gpu", + "crates/cargo-gpu-install", "crates/xtask", ] @@ -24,6 +25,7 @@ license = "MIT OR Apache-2.0" [workspace.dependencies] spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "823b0c275e3eb8ab44ada5a6d989bdb57e8f9409", default-features = false } +cargo-gpu-install = { path = "./crates/cargo-gpu-install" } anyhow = "1.0.98" clap = { version = "4.5.41", features = ["derive"] } crossterm = "0.29.0" diff --git a/crates/cargo-gpu-install/Cargo.toml b/crates/cargo-gpu-install/Cargo.toml new file mode 100644 index 0000000..d7d3407 --- /dev/null +++ b/crates/cargo-gpu-install/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "cargo-gpu-install" +version.workspace = true +edition.workspace = true +description = "Install rust-gpu and it's required toolchain automatically" +repository.workspace = true +readme.workspace = true +keywords.workspace = true +license.workspace = true + +[features] +test = ["dep:tempfile"] + +[dependencies] +cargo_metadata.workspace = true +anyhow.workspace = true +spirv-builder = { workspace = true, features = ["clap", "watch"] } +clap.workspace = true +directories.workspace = true +env_logger.workspace = true +log.workspace = true +relative-path.workspace = true +serde.workspace = true +serde_json.workspace = true +crossterm.workspace = true +semver.workspace = true +dunce.workspace = true +tempfile = { workspace = true, optional = true } + +[dev-dependencies] +test-log.workspace = true +cargo_metadata = { workspace = true, features = ["builder"] } +cargo-util-schemas = "0.8.2" + +[lints] +workspace = true diff --git a/crates/cargo-gpu-install/README.md b/crates/cargo-gpu-install/README.md new file mode 100644 index 0000000..5068029 --- /dev/null +++ b/crates/cargo-gpu-install/README.md @@ -0,0 +1,43 @@ +# cargo-gpu-install + +`cargo-gpu-install` is the install action of `cargo-gpu`, separated into its own crate. It's intended to be used +by build scripts and other binaries that need automated installation of rust-gpu and it's required toolchain, +without having to pull all the other cli dependencies of the full `cargo-gpu` (like clap). + +## Example + +This is an example build script meant to be placed in your "main" std crate, to build a secondary no-std "shader" crate. +But you can just as well use this in your executable directly, with some minor adjustments. +```rust,no_run +# use std::path::PathBuf; +# use cargo_gpu_install::install::Install; +# use cargo_gpu_install::spirv_builder::SpirvMetadata; + +pub fn main() -> Result<(), Box> { + // path to your shader crate + let shader_crate = PathBuf::from("./shaders"); + + // install the toolchain and build the `rustc_codegen_spirv` codegen backend with it + let backend = Install::from_shader_crate(shader_crate.clone()).run()?; + + // build the shader crate + let mut builder = backend.to_spirv_builder(shader_crate, "spirv-unknown-vulkan1.2"); + // set to true when you're in a build script, false when outside one + builder.build_script.defaults = true; + // enable debug information in the shaders + builder.spirv_metadata = SpirvMetadata::Full; + let spv_result = builder.build()?; + let path_to_spv = spv_result.module.unwrap_single(); + + // emit path to the artifact into env var, use it anywhere in your crate like: + // > include_str!(env!("MY_SHADER_PATH")) + println!( + "cargo::rustc-env=MY_SHADER_PATH={}", + path_to_spv.display() + ); + + // you could also generate some rust source code into the `std::env::var("OUT_DIR")` dir + // and use `include!(concat!(env!("OUT_DIR"), "/shader_symbols.rs"));` to include it + Ok(()) +} +``` diff --git a/crates/cargo-gpu/src/install.rs b/crates/cargo-gpu-install/src/install.rs similarity index 100% rename from crates/cargo-gpu/src/install.rs rename to crates/cargo-gpu-install/src/install.rs diff --git a/crates/cargo-gpu/src/install_toolchain.rs b/crates/cargo-gpu-install/src/install_toolchain.rs similarity index 100% rename from crates/cargo-gpu/src/install_toolchain.rs rename to crates/cargo-gpu-install/src/install_toolchain.rs diff --git a/crates/cargo-gpu-install/src/lib.rs b/crates/cargo-gpu-install/src/lib.rs new file mode 100644 index 0000000..e9b2889 --- /dev/null +++ b/crates/cargo-gpu-install/src/lib.rs @@ -0,0 +1,64 @@ +#![expect(clippy::pub_use, reason = "pub use for build scripts")] +#![doc = include_str!("../README.md")] + +pub mod install; +mod install_toolchain; +pub mod spirv_source; +pub mod test; + +pub use spirv_builder; + +/// Central function to write to the user. +#[macro_export] +macro_rules! user_output { + ($($args: tt)*) => { { + #[allow( + clippy::allow_attributes, + clippy::useless_attribute, + unused_imports, + reason = "`std::io::Write` is only sometimes called??" + )] + use std::io::Write as _; + + #[expect( + clippy::non_ascii_literal, + reason = "CRAB GOOD. CRAB IMPORTANT." + )] + { + print!("🦀 "); + } + print!($($args)*); + std::io::stdout().flush().unwrap(); + } } +} + +/// The central cache directory of cargo gpu +/// +/// # Errors +/// may fail if we can't find the user home directory +#[inline] +#[cfg(not(test))] +#[expect(clippy::cfg_not_test, reason = "tests use different cache_dir")] +pub fn cache_dir() -> anyhow::Result { + use anyhow::Context as _; + Ok(directories::BaseDirs::new() + .with_context(|| "could not find the user home directory")? + .cache_dir() + .join("rust-gpu")) +} + +#[cfg(test)] +pub use test::test_cache_dir as cache_dir; + +/// 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() +} diff --git a/crates/cargo-gpu/src/spirv_source.rs b/crates/cargo-gpu-install/src/spirv_source.rs similarity index 100% rename from crates/cargo-gpu/src/spirv_source.rs rename to crates/cargo-gpu-install/src/spirv_source.rs diff --git a/crates/cargo-gpu/src/test.rs b/crates/cargo-gpu-install/src/test.rs similarity index 99% rename from crates/cargo-gpu/src/test.rs rename to crates/cargo-gpu-install/src/test.rs index 4fb6a8d..8cdc5cf 100644 --- a/crates/cargo-gpu/src/test.rs +++ b/crates/cargo-gpu-install/src/test.rs @@ -1,5 +1,5 @@ //! utilities for tests -#![cfg(test)] +#![cfg(any(feature = "test", test))] use anyhow::Context; use std::cell::RefCell; diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index d451396..40a29de 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -14,6 +14,7 @@ default-run = "cargo-gpu" cargo_metadata.workspace = true anyhow.workspace = true spirv-builder = { workspace = true, features = ["clap", "watch"] } +cargo-gpu-install.workspace = true clap.workspace = true directories.workspace = true env_logger.workspace = true @@ -26,6 +27,7 @@ semver.workspace = true dunce.workspace = true [dev-dependencies] +cargo-gpu-install = { workspace = true, features = ["test"] } tempfile.workspace = true test-log.workspace = true cargo_metadata = { workspace = true, features = ["builder"] } diff --git a/crates/cargo-gpu/src/lib.rs b/crates/cargo-gpu/src/lib.rs index d482278..6b345b5 100644 --- a/crates/cargo-gpu/src/lib.rs +++ b/crates/cargo-gpu/src/lib.rs @@ -1,4 +1,4 @@ -#![expect(clippy::pub_use, reason = "pub use for build scripts")] +#![expect(clippy::pub_use, reason = "reexports from cargo_gpu_install crate")] //! Rust GPU shader crate builder. //! @@ -50,62 +50,31 @@ //! conduct other post-processing, like converting the `spv` files into `wgsl` files, //! for example. -use crate::dump_usage::dump_full_usage_for_readme; -use build::Build; -use show::Show; +#[cfg(test)] +pub use cargo_gpu_install::test; +pub use cargo_gpu_install::{cache_dir, install, spirv_builder, spirv_source, user_output}; +pub use metadata::MetadataCache; mod build; mod config; mod dump_usage; -mod install; -mod install_toolchain; mod linkage; mod lockfile; mod metadata; mod show; -mod spirv_source; -mod test; - -pub use install::*; -pub use metadata::MetadataCache; -pub use spirv_builder; - -/// Central function to write to the user. -#[macro_export] -macro_rules! user_output { - ($($args: tt)*) => { { - #[allow( - clippy::allow_attributes, - clippy::useless_attribute, - unused_imports, - reason = "`std::io::Write` is only sometimes called??" - )] - use std::io::Write as _; - - #[expect( - clippy::non_ascii_literal, - reason = "CRAB GOOD. CRAB IMPORTANT." - )] - { - print!("🦀 "); - } - print!($($args)*); - std::io::stdout().flush().unwrap(); - } } -} /// All of the available subcommands for `cargo gpu` #[derive(clap::Subcommand)] #[non_exhaustive] pub enum Command { /// Install rust-gpu compiler artifacts. - Install(Box), + Install(Box), /// Compile a shader crate to SPIR-V. - Build(Box), + Build(Box), /// Show some useful values. - Show(Show), + Show(show::Show), /// A hidden command that can be used to recursively print out all the subcommand help messages: /// `cargo gpu dump-usage` @@ -157,7 +126,7 @@ impl Command { command.run()?; } Self::Show(show) => show.run()?, - Self::DumpUsage => dump_full_usage_for_readme()?, + Self::DumpUsage => dump_usage::dump_full_usage_for_readme()?, } Ok(()) @@ -173,34 +142,3 @@ pub struct Cli { #[clap(subcommand)] pub command: Command, } - -/// The central cache directory of cargo gpu -/// -/// # Errors -/// may fail if we can't find the user home directory -#[inline] -#[cfg(not(test))] -#[expect(clippy::cfg_not_test, reason = "tests use different cache_dir")] -pub fn cache_dir() -> anyhow::Result { - use anyhow::Context as _; - Ok(directories::BaseDirs::new() - .with_context(|| "could not find the user home directory")? - .cache_dir() - .join("rust-gpu")) -} - -#[cfg(test)] -pub use test::test_cache_dir as cache_dir; - -/// 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() -} From 1345effc9026b54a30984e91132e4159d87a0a31 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 12:58:19 +0100 Subject: [PATCH 3/8] install-crate: fix clippy --- crates/cargo-gpu-install/src/lib.rs | 7 ++++++- crates/cargo-gpu-install/src/spirv_source.rs | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/cargo-gpu-install/src/lib.rs b/crates/cargo-gpu-install/src/lib.rs index e9b2889..5b9fc1b 100644 --- a/crates/cargo-gpu-install/src/lib.rs +++ b/crates/cargo-gpu-install/src/lib.rs @@ -1,5 +1,10 @@ #![expect(clippy::pub_use, reason = "pub use for build scripts")] -#![doc = include_str!("../README.md")] +#![expect( + missing_docs, + clippy::missing_docs_in_private_items, + reason = "crate docs are cfg'ed out" +)] +#![cfg_attr(doc, doc = include_str!("../README.md"))] pub mod install; mod install_toolchain; diff --git a/crates/cargo-gpu-install/src/spirv_source.rs b/crates/cargo-gpu-install/src/spirv_source.rs index 1775a99..d0ae054 100644 --- a/crates/cargo-gpu-install/src/spirv_source.rs +++ b/crates/cargo-gpu-install/src/spirv_source.rs @@ -22,6 +22,7 @@ use std::path::{Path, PathBuf}; /// - a repo of "https://github.com/Rust-GPU/rust-gpu.git" /// - a revision of "abc213" /// * a local Path +#[non_exhaustive] #[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 @@ -69,6 +70,9 @@ impl core::fmt::Display for SpirvSource { impl SpirvSource { /// Figures out which source of `rust-gpu` to use + /// + /// # Errors + /// Crate may not depend on `spirv-std` or is otherwise malformed pub fn new( shader_crate_path: &Path, maybe_rust_gpu_source: Option<&str>, @@ -95,6 +99,9 @@ impl SpirvSource { } /// Look into the shader crate to get the version of `rust-gpu` it's using. + /// + /// # Errors + /// Crate may not depend on `spirv-std` or is otherwise malformed pub fn get_rust_gpu_deps_from_shader(shader_crate_path: &Path) -> anyhow::Result { let crate_metadata = query_metadata(shader_crate_path)?; let spirv_std_package = crate_metadata.find_package("spirv-std")?; @@ -110,6 +117,9 @@ impl SpirvSource { /// Convert the `SpirvSource` to a cache directory in which we can build it. /// It needs to be dynamically created because an end-user might want to swap out the source, /// maybe using their own fork for example. + /// + /// # Errors + /// [`crate::cache_dir`] may fail pub fn install_dir(&self) -> anyhow::Result { match self { Self::Path { @@ -123,6 +133,7 @@ impl SpirvSource { } /// Returns true if self is a Path + #[must_use] pub const fn is_path(&self) -> bool { matches!(self, Self::Path { .. }) } @@ -182,6 +193,9 @@ impl SpirvSource { } /// get the Package metadata from some crate +/// +/// # Errors +/// metadata query may fail pub fn query_metadata(crate_path: &Path) -> anyhow::Result { log::debug!("Running `cargo metadata` on `{}`", crate_path.display()); let metadata = MetadataCommand::new() @@ -197,6 +211,9 @@ pub fn query_metadata(crate_path: &Path) -> anyhow::Result { /// implements [`Self::find_package`] pub trait FindPackage { /// Search for a package or return a nice error + /// + /// # Errors + /// package may not be found or crate may be malformed fn find_package(&self, crate_name: &str) -> anyhow::Result<&Package>; } @@ -219,6 +236,9 @@ impl FindPackage for Metadata { } /// Parse the `rust-toolchain.toml` in the working tree of the checked-out version of the `rust-gpu` repo. +/// +/// # Errors +/// parsing may fail pub fn get_channel_from_rustc_codegen_spirv_build_script( rustc_codegen_spirv_package: &Package, ) -> anyhow::Result { From 09151d55ab28504dda14351682fc8e4333e6a559 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 12:21:06 +0100 Subject: [PATCH 4/8] install-crate: cargo shear --- Cargo.lock | 9 --------- crates/cargo-gpu-install/Cargo.toml | 5 ----- crates/cargo-gpu/Cargo.toml | 4 ---- 3 files changed, 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1946e5f..467f451 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,11 +103,8 @@ version = "0.1.0" dependencies = [ "anyhow", "cargo-gpu-install", - "cargo-util-schemas", "cargo_metadata", "clap", - "crossterm", - "directories", "dunce", "env_logger", "log", @@ -116,7 +113,6 @@ dependencies = [ "serde", "serde_json", "spirv-builder", - "tempfile", "test-log", ] @@ -130,13 +126,8 @@ dependencies = [ "clap", "crossterm", "directories", - "dunce", - "env_logger", "log", - "relative-path", - "semver", "serde", - "serde_json", "spirv-builder", "tempfile", "test-log", diff --git a/crates/cargo-gpu-install/Cargo.toml b/crates/cargo-gpu-install/Cargo.toml index d7d3407..108e44d 100644 --- a/crates/cargo-gpu-install/Cargo.toml +++ b/crates/cargo-gpu-install/Cargo.toml @@ -17,14 +17,9 @@ anyhow.workspace = true spirv-builder = { workspace = true, features = ["clap", "watch"] } clap.workspace = true directories.workspace = true -env_logger.workspace = true log.workspace = true -relative-path.workspace = true serde.workspace = true -serde_json.workspace = true crossterm.workspace = true -semver.workspace = true -dunce.workspace = true tempfile = { workspace = true, optional = true } [dev-dependencies] diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index 40a29de..3fee087 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -16,22 +16,18 @@ anyhow.workspace = true spirv-builder = { workspace = true, features = ["clap", "watch"] } cargo-gpu-install.workspace = true clap.workspace = true -directories.workspace = true env_logger.workspace = true log.workspace = true relative-path.workspace = true serde.workspace = true serde_json.workspace = true -crossterm.workspace = true semver.workspace = true dunce.workspace = true [dev-dependencies] cargo-gpu-install = { workspace = true, features = ["test"] } -tempfile.workspace = true test-log.workspace = true cargo_metadata = { workspace = true, features = ["builder"] } -cargo-util-schemas = "0.8.2" [lints] workspace = true From 4b520d6a464d6a8fb9322a27b68ae770929cb1fb Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 12:26:01 +0100 Subject: [PATCH 5/8] install-crate: clap and watch feature for optional deps --- crates/cargo-gpu-install/Cargo.toml | 6 ++++-- crates/cargo-gpu-install/src/install.rs | 22 +++++++++++++--------- crates/cargo-gpu/Cargo.toml | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/crates/cargo-gpu-install/Cargo.toml b/crates/cargo-gpu-install/Cargo.toml index 108e44d..5aa0261 100644 --- a/crates/cargo-gpu-install/Cargo.toml +++ b/crates/cargo-gpu-install/Cargo.toml @@ -9,13 +9,15 @@ keywords.workspace = true license.workspace = true [features] +clap = ["dep:clap", "spirv-builder/clap"] +watch = ["spirv-builder/watch"] test = ["dep:tempfile"] [dependencies] cargo_metadata.workspace = true anyhow.workspace = true -spirv-builder = { workspace = true, features = ["clap", "watch"] } -clap.workspace = true +spirv-builder.workspace = true +clap = { workspace = true, optional = true } directories.workspace = true log.workspace = true serde.workspace = true diff --git a/crates/cargo-gpu-install/src/install.rs b/crates/cargo-gpu-install/src/install.rs index c9ea0ec..0de9403 100644 --- a/crates/cargo-gpu-install/src/install.rs +++ b/crates/cargo-gpu-install/src/install.rs @@ -54,19 +54,23 @@ impl InstalledBackend { clippy::struct_excessive_bools, reason = "cmdline args have many bools" )] -#[derive(clap::Parser, Debug, Clone, serde::Deserialize, serde::Serialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +#[cfg_attr(feature = "clap", derive(clap::Parser))] #[non_exhaustive] pub struct Install { /// Cargo target to compile. /// /// Conflicts with `--shader-crate`. - #[clap(short, long, conflicts_with("shader_crate"))] + #[cfg_attr(feature = "clap", clap(short, long, conflicts_with("shader_crate")))] pub package: Option, /// Directory containing the shader crate to compile. /// /// Conflicts with `--package` or `-p`. - #[clap(long, default_value = "./", conflicts_with("package"))] + #[cfg_attr( + feature = "clap", + clap(long, default_value = "./", conflicts_with("package")) + )] pub shader_crate: PathBuf, #[expect( @@ -75,7 +79,7 @@ pub struct Install { )] /// Source of `spirv-builder` dependency /// Eg: "https://github.com/Rust-GPU/rust-gpu" - #[clap(long)] + #[cfg_attr(feature = "clap", clap(long))] pub spirv_builder_source: Option, /// Version of `spirv-builder` dependency. @@ -83,22 +87,22 @@ pub struct Install { /// 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)] + #[cfg_attr(feature = "clap", clap(long, verbatim_doc_comment))] pub spirv_builder_version: Option, /// Force `rustc_codegen_spirv` to be rebuilt. - #[clap(long)] + #[cfg_attr(feature = "clap", clap(long))] pub rebuild_codegen: bool, /// Assume "yes" to "Install Rust toolchain: [y/n]" prompt. /// /// Defaults to `false` in cli, `true` in [`Default`] - #[clap(long, action)] + #[cfg_attr(feature = "clap", clap(long, action))] pub auto_install_rust_toolchain: bool, /// Clear target dir of `rustc_codegen_spirv` build after a successful build, saves about /// 200MiB of disk space. - #[clap(long = "no-clear-target", default_value = "true", action = clap::ArgAction::SetFalse)] + #[cfg_attr(feature = "clap", clap(long = "no-clear-target", default_value = "true", action = clap::ArgAction::SetFalse))] pub clear_target: bool, /// There is a tricky situation where a shader crate that depends on workspace config can have @@ -122,7 +126,7 @@ pub struct Install { /// way source URLs are encoded. See these PRs for more details: /// * /// * - #[clap(long, action, verbatim_doc_comment)] + #[cfg_attr(feature = "clap", clap(long, action, verbatim_doc_comment))] pub force_overwrite_lockfiles_v4_to_v3: bool, } diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index 3fee087..edf04cc 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -14,7 +14,7 @@ default-run = "cargo-gpu" cargo_metadata.workspace = true anyhow.workspace = true spirv-builder = { workspace = true, features = ["clap", "watch"] } -cargo-gpu-install.workspace = true +cargo-gpu-install = { workspace = true, features = ["clap", "watch"] } clap.workspace = true env_logger.workspace = true log.workspace = true From 3ffed8ba6d2ba2c82566ca09f4629dcc17902265 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 12:40:33 +0100 Subject: [PATCH 6/8] install-crate: tty feature to make crossterm and user output optional --- Cargo.lock | 49 +++---------------- Cargo.toml | 2 +- crates/cargo-gpu-install/Cargo.toml | 3 +- .../src/install_toolchain.rs | 27 ++++++++-- crates/cargo-gpu-install/src/lib.rs | 8 +++ crates/cargo-gpu/Cargo.toml | 2 +- 6 files changed, 41 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 467f451..e7c85fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,15 +226,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" -[[package]] -name = "convert_case" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "crossterm" version = "0.29.0" @@ -243,7 +234,6 @@ checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ "bitflags 2.9.0", "crossterm_winapi", - "derive_more", "document-features", "mio", "parking_lot", @@ -328,27 +318,6 @@ dependencies = [ "syn", ] -[[package]] -name = "derive_more" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "directories" version = "6.0.0" @@ -1178,9 +1147,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -1188,9 +1157,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio", @@ -1199,9 +1168,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -1489,12 +1458,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index b9ad742..3e93182 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "823b0c275 cargo-gpu-install = { path = "./crates/cargo-gpu-install" } anyhow = "1.0.98" clap = { version = "4.5.41", features = ["derive"] } -crossterm = "0.29.0" +crossterm = { version = "0.29.0", default-features = false, features = ["events", "windows"] } directories = "6.0.0" env_logger = "0.11.8" log = "0.4" diff --git a/crates/cargo-gpu-install/Cargo.toml b/crates/cargo-gpu-install/Cargo.toml index 5aa0261..8a914c7 100644 --- a/crates/cargo-gpu-install/Cargo.toml +++ b/crates/cargo-gpu-install/Cargo.toml @@ -12,6 +12,7 @@ license.workspace = true clap = ["dep:clap", "spirv-builder/clap"] watch = ["spirv-builder/watch"] test = ["dep:tempfile"] +tty = ["dep:crossterm"] [dependencies] cargo_metadata.workspace = true @@ -21,7 +22,7 @@ clap = { workspace = true, optional = true } directories.workspace = true log.workspace = true serde.workspace = true -crossterm.workspace = true +crossterm = { workspace = true, optional = true } tempfile = { workspace = true, optional = true } [dev-dependencies] diff --git a/crates/cargo-gpu-install/src/install_toolchain.rs b/crates/cargo-gpu-install/src/install_toolchain.rs index 98d35d5..300ddb8 100644 --- a/crates/cargo-gpu-install/src/install_toolchain.rs +++ b/crates/cargo-gpu-install/src/install_toolchain.rs @@ -1,6 +1,7 @@ //! toolchain installation logic use anyhow::Context as _; +#[cfg(feature = "tty")] use crossterm::tty::IsTty as _; use crate::user_output; @@ -98,6 +99,20 @@ pub fn ensure_toolchain_and_components_exist( Ok(()) } +#[cfg(not(feature = "tty"))] +/// Prompt user if they want to install a new Rust toolchain. +fn get_consent_for_toolchain_install( + _prompt: &str, + skip_toolchain_install_consent: bool, +) -> anyhow::Result<()> { + if skip_toolchain_install_consent { + Ok(()) + } else { + no_tty() + } +} + +#[cfg(feature = "tty")] /// Prompt user if they want to install a new Rust toolchain. fn get_consent_for_toolchain_install( prompt: &str, @@ -108,10 +123,7 @@ fn get_consent_for_toolchain_install( } if !std::io::stdout().is_tty() { - user_output!("No TTY detected so can't ask for consent to install Rust toolchain."); - log::error!("Attempted to ask for consent when there's no TTY"); - #[expect(clippy::exit, reason = "can't ask for user consent if there's no TTY")] - std::process::exit(1); + no_tty() } log::debug!("asking for consent to install the required toolchain"); @@ -143,3 +155,10 @@ fn get_consent_for_toolchain_install( std::process::exit(0); } } + +fn no_tty() -> ! { + user_output!("No TTY detected so can't ask for consent to install Rust toolchain."); + log::error!("Attempted to ask for consent when there's no TTY"); + #[expect(clippy::exit, reason = "can't ask for user consent if there's no TTY")] + std::process::exit(1); +} diff --git a/crates/cargo-gpu-install/src/lib.rs b/crates/cargo-gpu-install/src/lib.rs index 5b9fc1b..f59d39c 100644 --- a/crates/cargo-gpu-install/src/lib.rs +++ b/crates/cargo-gpu-install/src/lib.rs @@ -15,6 +15,7 @@ pub use spirv_builder; /// Central function to write to the user. #[macro_export] +#[cfg(feature = "tty")] macro_rules! user_output { ($($args: tt)*) => { { #[allow( @@ -37,6 +38,13 @@ macro_rules! user_output { } } } +/// Central function to write to the user. +#[macro_export] +#[cfg(not(feature = "tty"))] +macro_rules! user_output { + ($($args: tt)*) => {{}}; +} + /// The central cache directory of cargo gpu /// /// # Errors diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index edf04cc..41c8dc3 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -14,7 +14,7 @@ default-run = "cargo-gpu" cargo_metadata.workspace = true anyhow.workspace = true spirv-builder = { workspace = true, features = ["clap", "watch"] } -cargo-gpu-install = { workspace = true, features = ["clap", "watch"] } +cargo-gpu-install = { workspace = true, features = ["clap", "watch", "tty"] } clap.workspace = true env_logger.workspace = true log.workspace = true From 440ecf5df182419a89803a8ac6e1b51361226d21 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 12:41:53 +0100 Subject: [PATCH 7/8] install-crate: remove spirv-builder direct dep in cargo-gpu --- Cargo.lock | 1 - crates/cargo-gpu/Cargo.toml | 1 - crates/cargo-gpu/src/build.rs | 2 +- crates/cargo-gpu/src/config.rs | 6 ++---- crates/cargo-gpu/src/lockfile.rs | 2 +- crates/cargo-gpu/src/show.rs | 7 ++++--- 6 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7c85fa..7efe3c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,6 @@ dependencies = [ "semver", "serde", "serde_json", - "spirv-builder", "test-log", ] diff --git a/crates/cargo-gpu/Cargo.toml b/crates/cargo-gpu/Cargo.toml index 41c8dc3..951e884 100644 --- a/crates/cargo-gpu/Cargo.toml +++ b/crates/cargo-gpu/Cargo.toml @@ -13,7 +13,6 @@ default-run = "cargo-gpu" [dependencies] cargo_metadata.workspace = true anyhow.workspace = true -spirv-builder = { workspace = true, features = ["clap", "watch"] } cargo-gpu-install = { workspace = true, features = ["clap", "watch", "tty"] } clap.workspace = true env_logger.workspace = true diff --git a/crates/cargo-gpu/src/build.rs b/crates/cargo-gpu/src/build.rs index e8e620c..22a5a73 100644 --- a/crates/cargo-gpu/src/build.rs +++ b/crates/cargo-gpu/src/build.rs @@ -5,8 +5,8 @@ use crate::install::Install; use crate::linkage::Linkage; use crate::lockfile::LockfileMismatchHandler; +use crate::spirv_builder::{CompileResult, ModuleResult, SpirvBuilder, SpirvBuilderError}; use anyhow::Context as _; -use spirv_builder::{CompileResult, ModuleResult, SpirvBuilder, SpirvBuilderError}; use std::io::Write as _; use std::path::PathBuf; diff --git a/crates/cargo-gpu/src/config.rs b/crates/cargo-gpu/src/config.rs index 3c3d667..5fe2adb 100644 --- a/crates/cargo-gpu/src/config.rs +++ b/crates/cargo-gpu/src/config.rs @@ -89,6 +89,7 @@ impl Config { mod test { use super::*; + use crate::spirv_builder::Capability; use crate::test::TestEnv; use std::io::Write as _; @@ -223,10 +224,7 @@ mod test { .unwrap(); assert_eq!( args.build.spirv_builder.capabilities, - vec![ - spirv_builder::Capability::AtomicStorage, - spirv_builder::Capability::Matrix - ] + vec![Capability::AtomicStorage, Capability::Matrix] ); } diff --git a/crates/cargo-gpu/src/lockfile.rs b/crates/cargo-gpu/src/lockfile.rs index bce1487..89aaad6 100644 --- a/crates/cargo-gpu/src/lockfile.rs +++ b/crates/cargo-gpu/src/lockfile.rs @@ -2,9 +2,9 @@ //! v0.9.0 uses an old toolchain requiring v3 and will refuse to build with a v4 lockfile being //! present. This module takes care of warning the user and potentially downgrading the lockfile. +use crate::spirv_builder::query_rustc_version; use anyhow::Context as _; use semver::Version; -use spirv_builder::query_rustc_version; use std::io::Write as _; /// `Cargo.lock` manifest version 4 became the default in Rust 1.83.0. Conflicting manifest diff --git a/crates/cargo-gpu/src/show.rs b/crates/cargo-gpu/src/show.rs index 1e318c4..491550c 100644 --- a/crates/cargo-gpu/src/show.rs +++ b/crates/cargo-gpu/src/show.rs @@ -1,6 +1,7 @@ //! Display various information about `cargo gpu`, eg its cache directory. use crate::cache_dir; +use crate::spirv_builder::Capability; use crate::spirv_source::SpirvSource; /// Show the computed source of the spirv-std dependency. @@ -69,11 +70,11 @@ impl Show { } /// Iterator over all `Capability` variants. - fn capability_variants_iter() -> impl Iterator { + fn capability_variants_iter() -> impl Iterator { // Since spirv::Capability is repr(u32) we can iterate over // u32s until some maximum #[expect(clippy::as_conversions, reason = "We know all variants are repr(u32)")] - let last_capability = spirv_builder::Capability::CacheControlsINTEL as u32; - (0..=last_capability).filter_map(spirv_builder::Capability::from_u32) + let last_capability = Capability::CacheControlsINTEL as u32; + (0..=last_capability).filter_map(Capability::from_u32) } } From d43927a5c21c8b70d32d90af9154fc268a42e815 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 23 Dec 2025 15:11:16 +0100 Subject: [PATCH 8/8] install-crate: fix test instability unintentionally started sharing the cache dir between tests --- crates/cargo-gpu-install/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cargo-gpu-install/src/lib.rs b/crates/cargo-gpu-install/src/lib.rs index f59d39c..d7b2210 100644 --- a/crates/cargo-gpu-install/src/lib.rs +++ b/crates/cargo-gpu-install/src/lib.rs @@ -50,7 +50,7 @@ macro_rules! user_output { /// # Errors /// may fail if we can't find the user home directory #[inline] -#[cfg(not(test))] +#[cfg(not(any(feature = "test", test)))] #[expect(clippy::cfg_not_test, reason = "tests use different cache_dir")] pub fn cache_dir() -> anyhow::Result { use anyhow::Context as _; @@ -60,7 +60,7 @@ pub fn cache_dir() -> anyhow::Result { .join("rust-gpu")) } -#[cfg(test)] +#[cfg(any(feature = "test", test))] pub use test::test_cache_dir as cache_dir; /// Returns a string suitable to use as a directory.