@@ -7,16 +7,63 @@ use crate::spirv_source::{
77use crate :: { cache_dir, spirv_source:: SpirvSource } ;
88use anyhow:: Context as _;
99use cargo_metadata:: Metadata ;
10- use log:: { info, trace} ;
1110use spirv_builder:: SpirvBuilder ;
1211use std:: path:: { Path , PathBuf } ;
1312
13+ /// Represents a functional backend installation, whether it was cached or just installed.
14+ #[ derive( Clone , Debug ) ]
15+ #[ non_exhaustive]
16+ pub struct InstalledBackend {
17+ /// path to the `rustc_codegen_spirv` dylib
18+ pub rustc_codegen_spirv_location : PathBuf ,
19+ /// toolchain channel name
20+ pub toolchain_channel : String ,
21+ /// directory with target-specs json files
22+ pub target_spec_dir : PathBuf ,
23+ }
24+
25+ impl InstalledBackend {
26+ /// Creates a new `SpirvBuilder` configured to use this installed backend.
27+ #[ expect(
28+ clippy:: unreachable,
29+ reason = "it's unreachable, no need to return a Result"
30+ ) ]
31+ #[ expect( clippy:: impl_trait_in_params, reason = "forwarding spirv-builder API" ) ]
32+ #[ inline]
33+ pub fn to_spirv_builder (
34+ & self ,
35+ path_to_crate : impl AsRef < Path > ,
36+ target : impl Into < String > ,
37+ ) -> SpirvBuilder {
38+ let mut builder = SpirvBuilder :: new ( path_to_crate, target) ;
39+ self . configure_spirv_builder ( & mut builder)
40+ . unwrap_or_else ( |_| unreachable ! ( "we set target before calling this function" ) ) ;
41+ builder
42+ }
43+
44+ /// Configures the supplied [`SpirvBuilder`]. `SpirvBuilder.target` must be set and must not change after calling this function.
45+ ///
46+ /// # Errors
47+ /// if `SpirvBuilder.target` is not set
48+ #[ inline]
49+ pub fn configure_spirv_builder ( & self , builder : & mut SpirvBuilder ) -> anyhow:: Result < ( ) > {
50+ builder. rustc_codegen_spirv_location = Some ( self . rustc_codegen_spirv_location . clone ( ) ) ;
51+ builder. toolchain_overwrite = Some ( self . toolchain_channel . clone ( ) ) ;
52+ builder. path_to_target_spec = Some ( self . target_spec_dir . join ( format ! (
53+ "{}.json" ,
54+ builder. target. as_ref( ) . context( "expect target to be set" ) ?
55+ ) ) ) ;
56+ Ok ( ( ) )
57+ }
58+ }
59+
1460/// Args for an install
1561#[ expect(
1662 clippy:: struct_excessive_bools,
1763 reason = "cmdline args have many bools"
1864) ]
1965#[ derive( clap:: Parser , Debug , Clone , serde:: Deserialize , serde:: Serialize ) ]
66+ #[ non_exhaustive]
2067pub struct Install {
2168 /// Directory containing the shader crate to compile.
2269 #[ clap( long, default_value = "./" ) ]
@@ -44,6 +91,8 @@ pub struct Install {
4491 pub rebuild_codegen : bool ,
4592
4693 /// Assume "yes" to "Install Rust toolchain: [y/n]" prompt.
94+ ///
95+ /// Defaults to `false` in cli, `true` in [`Default`]
4796 #[ clap( long, action) ]
4897 pub auto_install_rust_toolchain : bool ,
4998
@@ -77,46 +126,22 @@ pub struct Install {
77126 pub force_overwrite_lockfiles_v4_to_v3 : bool ,
78127}
79128
80- /// Represents a functional backend installation, whether it was cached or just installed.
81- #[ derive( Clone , Debug ) ]
82- pub struct InstalledBackend {
83- /// path to the `rustc_codegen_spirv` dylib
84- pub rustc_codegen_spirv_location : PathBuf ,
85- /// toolchain channel name
86- pub toolchain_channel : String ,
87- /// directory with target-specs json files
88- pub target_spec_dir : PathBuf ,
89- }
90-
91- impl InstalledBackend {
92- /// Configures the supplied [`SpirvBuilder`]. `SpirvBuilder.target` must be set and must not change after calling this function.
93- pub fn configure_spirv_builder ( & self , builder : & mut SpirvBuilder ) -> anyhow:: Result < ( ) > {
94- builder. rustc_codegen_spirv_location = Some ( self . rustc_codegen_spirv_location . clone ( ) ) ;
95- builder. toolchain_overwrite = Some ( self . toolchain_channel . clone ( ) ) ;
96- builder. path_to_target_spec = Some ( self . target_spec_dir . join ( format ! (
97- "{}.json" ,
98- builder. target. as_ref( ) . context( "expect target to be set" ) ?
99- ) ) ) ;
100- Ok ( ( ) )
101- }
102- }
103-
104- impl Default for Install {
129+ impl Install {
130+ /// Create a default install for a shader crate of some path
105131 #[ inline]
106- fn default ( ) -> Self {
132+ #[ must_use]
133+ pub const fn from_shader_crate ( shader_crate : PathBuf ) -> Self {
107134 Self {
108- shader_crate : PathBuf :: from ( "./" ) ,
135+ shader_crate,
109136 spirv_builder_source : None ,
110137 spirv_builder_version : None ,
111138 rebuild_codegen : false ,
112- auto_install_rust_toolchain : false ,
139+ auto_install_rust_toolchain : true ,
113140 clear_target : true ,
114141 force_overwrite_lockfiles_v4_to_v3 : false ,
115142 }
116143 }
117- }
118144
119- impl Install {
120145 /// Create the `rustc_codegen_spirv_dummy` crate that depends on `rustc_codegen_spirv`
121146 fn write_source_files ( source : & SpirvSource , checkout : & Path ) -> anyhow:: Result < ( ) > {
122147 // skip writing a dummy project if we use a local rust-gpu checkout
@@ -129,15 +154,14 @@ impl Install {
129154 ) ;
130155
131156 {
132- trace ! ( "writing dummy main.rs" ) ;
133- let main = "fn main() {}" ;
157+ log:: trace!( "writing dummy lib.rs" ) ;
134158 let src = checkout. join ( "src" ) ;
135- std:: fs:: create_dir_all ( & src) . context ( "creating directory for 'src'" ) ?;
136- std:: fs:: write ( src. join ( "main .rs" ) , main ) . context ( "writing 'main .rs'" ) ?;
159+ std:: fs:: create_dir_all ( & src) . context ( "creating 'src' directory " ) ?;
160+ std:: fs:: File :: create ( src. join ( "lib .rs" ) ) . context ( "creating 'src/lib .rs'" ) ?;
137161 } ;
138162
139163 {
140- trace ! ( "writing dummy Cargo.toml" ) ;
164+ log :: trace!( "writing dummy Cargo.toml" ) ;
141165 let version_spec = match & source {
142166 SpirvSource :: CratesIO ( version) => {
143167 format ! ( "version = \" {version}\" " )
@@ -174,11 +198,6 @@ package = "rustc_codegen_spirv"
174198
175199 /// Copy spec files from one dir to another, assuming no subdirectories
176200 fn copy_spec_files ( src : & Path , dst : & Path ) -> anyhow:: Result < ( ) > {
177- info ! (
178- "Copy target specs from {:?} to {:?}" ,
179- src. display( ) ,
180- dst. display( )
181- ) ;
182201 std:: fs:: create_dir_all ( dst) ?;
183202 let dir = std:: fs:: read_dir ( src) ?;
184203 for dir_entry in dir {
@@ -193,7 +212,6 @@ package = "rustc_codegen_spirv"
193212
194213 /// Add the target spec files to the crate.
195214 fn update_spec_files (
196- & self ,
197215 source : & SpirvSource ,
198216 install_dir : & Path ,
199217 dummy_metadata : & Metadata ,
@@ -204,6 +222,11 @@ package = "rustc_codegen_spirv"
204222 if let Ok ( target_specs) =
205223 dummy_metadata. find_package ( "rustc_codegen_spirv-target-specs" )
206224 {
225+ log:: info!(
226+ "target-specs: found crate `rustc_codegen_spirv-target-specs` with manifest at `{}`" ,
227+ target_specs. manifest_path
228+ ) ;
229+
207230 let target_specs_src = target_specs
208231 . manifest_path
209232 . as_std_path ( )
@@ -215,9 +238,17 @@ package = "rustc_codegen_spirv"
215238 . context ( "Could not find `target-specs` directory within `rustc_codegen_spirv-target-specs` dependency" ) ?;
216239 if source. is_path ( ) {
217240 // skip copy
241+ log:: info!(
242+ "target-specs: source is local path, use target-specs from `{}`" ,
243+ target_specs_src. display( )
244+ ) ;
218245 target_specs_dst = target_specs_src;
219246 } else {
220247 // copy over the target-specs
248+ log:: info!(
249+ "target-specs: Copy target specs from `{}`" ,
250+ target_specs_src. display( )
251+ ) ;
221252 Self :: copy_spec_files ( & target_specs_src, & target_specs_dst)
222253 . context ( "copying target-specs json files" ) ?;
223254 }
@@ -231,14 +262,22 @@ package = "rustc_codegen_spirv"
231262 // and hope parallel runs don't shred each other
232263 target_specs_dst = cache_dir ( ) ?. join ( "legacy-target-specs-for-local-checkout" ) ;
233264 }
234- write_legacy_target_specs ( & target_specs_dst, self . rebuild_codegen ) ?;
265+ log:: info!(
266+ "target-specs: Writing legacy target specs to `{}`" ,
267+ target_specs_dst. display( )
268+ ) ;
269+ write_legacy_target_specs ( & target_specs_dst) ?;
235270 }
236271 }
237272
238273 Ok ( target_specs_dst)
239274 }
240275
241- /// Install the binary pair and return the `(dylib_path, toolchain_channel)`.
276+ /// Install the binary pair and return the [`InstalledBackend`], from which you can create [`SpirvBuilder`] instances.
277+ ///
278+ /// # Errors
279+ /// If the installation somehow fails.
280+ #[ inline]
242281 #[ expect( clippy:: too_many_lines, reason = "it's fine" ) ]
243282 pub fn run ( & self ) -> anyhow:: Result < InstalledBackend > {
244283 // Ensure the cache dir exists
@@ -299,9 +338,9 @@ package = "rustc_codegen_spirv"
299338 log:: info!( "selected toolchain channel `{toolchain_channel:?}`" ) ;
300339
301340 log:: debug!( "update_spec_files" ) ;
302- let target_spec_dir = self
303- . update_spec_files ( & source, & install_dir, & dummy_metadata, skip_rebuild)
304- . context ( "writing target spec files" ) ?;
341+ let target_spec_dir =
342+ Self :: update_spec_files ( & source, & install_dir, & dummy_metadata, skip_rebuild)
343+ . context ( "writing target spec files" ) ?;
305344
306345 if !skip_rebuild {
307346 log:: debug!( "ensure_toolchain_and_components_exist" ) ;
0 commit comments