@@ -7,16 +7,63 @@ use crate::spirv_source::{
7
7
use crate :: { cache_dir, spirv_source:: SpirvSource } ;
8
8
use anyhow:: Context as _;
9
9
use cargo_metadata:: Metadata ;
10
- use log:: { info, trace} ;
11
10
use spirv_builder:: SpirvBuilder ;
12
11
use std:: path:: { Path , PathBuf } ;
13
12
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
+
14
60
/// Args for an install
15
61
#[ expect(
16
62
clippy:: struct_excessive_bools,
17
63
reason = "cmdline args have many bools"
18
64
) ]
19
65
#[ derive( clap:: Parser , Debug , Clone , serde:: Deserialize , serde:: Serialize ) ]
66
+ #[ non_exhaustive]
20
67
pub struct Install {
21
68
/// Directory containing the shader crate to compile.
22
69
#[ clap( long, default_value = "./" ) ]
@@ -44,6 +91,8 @@ pub struct Install {
44
91
pub rebuild_codegen : bool ,
45
92
46
93
/// Assume "yes" to "Install Rust toolchain: [y/n]" prompt.
94
+ ///
95
+ /// Defaults to `false` in cli, `true` in [`Default`]
47
96
#[ clap( long, action) ]
48
97
pub auto_install_rust_toolchain : bool ,
49
98
@@ -77,46 +126,22 @@ pub struct Install {
77
126
pub force_overwrite_lockfiles_v4_to_v3 : bool ,
78
127
}
79
128
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
105
131
#[ inline]
106
- fn default ( ) -> Self {
132
+ #[ must_use]
133
+ pub const fn from_shader_crate ( shader_crate : PathBuf ) -> Self {
107
134
Self {
108
- shader_crate : PathBuf :: from ( "./" ) ,
135
+ shader_crate,
109
136
spirv_builder_source : None ,
110
137
spirv_builder_version : None ,
111
138
rebuild_codegen : false ,
112
- auto_install_rust_toolchain : false ,
139
+ auto_install_rust_toolchain : true ,
113
140
clear_target : true ,
114
141
force_overwrite_lockfiles_v4_to_v3 : false ,
115
142
}
116
143
}
117
- }
118
144
119
- impl Install {
120
145
/// Create the `rustc_codegen_spirv_dummy` crate that depends on `rustc_codegen_spirv`
121
146
fn write_source_files ( source : & SpirvSource , checkout : & Path ) -> anyhow:: Result < ( ) > {
122
147
// skip writing a dummy project if we use a local rust-gpu checkout
@@ -129,15 +154,14 @@ impl Install {
129
154
) ;
130
155
131
156
{
132
- trace ! ( "writing dummy main.rs" ) ;
133
- let main = "fn main() {}" ;
157
+ log:: trace!( "writing dummy lib.rs" ) ;
134
158
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'" ) ?;
137
161
} ;
138
162
139
163
{
140
- trace ! ( "writing dummy Cargo.toml" ) ;
164
+ log :: trace!( "writing dummy Cargo.toml" ) ;
141
165
let version_spec = match & source {
142
166
SpirvSource :: CratesIO ( version) => {
143
167
format ! ( "version = \" {version}\" " )
@@ -174,11 +198,6 @@ package = "rustc_codegen_spirv"
174
198
175
199
/// Copy spec files from one dir to another, assuming no subdirectories
176
200
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
- ) ;
182
201
std:: fs:: create_dir_all ( dst) ?;
183
202
let dir = std:: fs:: read_dir ( src) ?;
184
203
for dir_entry in dir {
@@ -193,7 +212,6 @@ package = "rustc_codegen_spirv"
193
212
194
213
/// Add the target spec files to the crate.
195
214
fn update_spec_files (
196
- & self ,
197
215
source : & SpirvSource ,
198
216
install_dir : & Path ,
199
217
dummy_metadata : & Metadata ,
@@ -204,6 +222,11 @@ package = "rustc_codegen_spirv"
204
222
if let Ok ( target_specs) =
205
223
dummy_metadata. find_package ( "rustc_codegen_spirv-target-specs" )
206
224
{
225
+ log:: info!(
226
+ "target-specs: found crate `rustc_codegen_spirv-target-specs` with manifest at `{}`" ,
227
+ target_specs. manifest_path
228
+ ) ;
229
+
207
230
let target_specs_src = target_specs
208
231
. manifest_path
209
232
. as_std_path ( )
@@ -215,9 +238,17 @@ package = "rustc_codegen_spirv"
215
238
. context ( "Could not find `target-specs` directory within `rustc_codegen_spirv-target-specs` dependency" ) ?;
216
239
if source. is_path ( ) {
217
240
// skip copy
241
+ log:: info!(
242
+ "target-specs: source is local path, use target-specs from `{}`" ,
243
+ target_specs_src. display( )
244
+ ) ;
218
245
target_specs_dst = target_specs_src;
219
246
} else {
220
247
// copy over the target-specs
248
+ log:: info!(
249
+ "target-specs: Copy target specs from `{}`" ,
250
+ target_specs_src. display( )
251
+ ) ;
221
252
Self :: copy_spec_files ( & target_specs_src, & target_specs_dst)
222
253
. context ( "copying target-specs json files" ) ?;
223
254
}
@@ -231,14 +262,22 @@ package = "rustc_codegen_spirv"
231
262
// and hope parallel runs don't shred each other
232
263
target_specs_dst = cache_dir ( ) ?. join ( "legacy-target-specs-for-local-checkout" ) ;
233
264
}
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) ?;
235
270
}
236
271
}
237
272
238
273
Ok ( target_specs_dst)
239
274
}
240
275
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]
242
281
#[ expect( clippy:: too_many_lines, reason = "it's fine" ) ]
243
282
pub fn run ( & self ) -> anyhow:: Result < InstalledBackend > {
244
283
// Ensure the cache dir exists
@@ -299,9 +338,9 @@ package = "rustc_codegen_spirv"
299
338
log:: info!( "selected toolchain channel `{toolchain_channel:?}`" ) ;
300
339
301
340
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" ) ?;
305
344
306
345
if !skip_rebuild {
307
346
log:: debug!( "ensure_toolchain_and_components_exist" ) ;
0 commit comments