11//! Install a dedicated per-shader crate that has the `rust-gpu` compiler in it.
22
33use crate :: spirv_source:: { CrateMetadata , get_channel_from_rustc_codegen_spirv_build_script} ;
4- use crate :: { cache_dir, spirv_source:: SpirvSource } ;
4+ use crate :: { cache_dir, spirv_source:: SpirvSource , user_output } ;
55use anyhow:: Context as _;
66use spirv_builder:: SpirvBuilder ;
77use std:: path:: { Path , PathBuf } ;
@@ -243,6 +243,7 @@ package = "rustc_codegen_spirv"
243243 self . spirv_builder_version . as_deref ( ) ,
244244 ) ?;
245245 let install_dir = source. install_dir ( ) ?;
246+ std:: fs:: create_dir_all ( & install_dir) ?;
246247
247248 let dylib_filename = format ! (
248249 "{}rustc_codegen_spirv{}" ,
@@ -263,30 +264,36 @@ package = "rustc_codegen_spirv"
263264 }
264265 }
265266
266- let ( dest_dylib_path, skip_rebuild) = if source. is_path ( ) {
267+ let mut _file_lock = None ;
268+ let ( dest_dylib_path, do_build) = if source. is_path ( ) {
267269 (
268- install_dir
269- . join ( "target" )
270- . join ( "release" )
271- . join ( & dylib_filename) ,
272- // if `source` is a path, always rebuild
273- false ,
270+ install_dir. join ( "target/release" ) . join ( & dylib_filename) ,
271+ // if `source` is a path, always rebuild and rely on incremental builds
272+ true ,
274273 )
275274 } else {
276275 let dest_dylib_path = install_dir. join ( & dylib_filename) ;
277- let artifacts_found = dest_dylib_path. is_file ( )
278- && install_dir. join ( "Cargo.toml" ) . is_file ( )
279- && install_dir. join ( "src" ) . join ( "lib.rs" ) . is_file ( ) ;
280- if artifacts_found {
281- log:: info!( "cargo-gpu artifacts found in '{}'" , install_dir. display( ) ) ;
276+ let needs_build = || {
277+ !( dest_dylib_path. is_file ( )
278+ && install_dir. join ( "Cargo.toml" ) . is_file ( )
279+ && install_dir. join ( "src/lib.rs" ) . is_file ( ) )
280+ } ;
281+ let mut do_build = needs_build ( ) ;
282+ if do_build {
283+ _file_lock = Some ( FileLock :: lock ( & install_dir. join ( "lockfile" ) ) ?) ;
284+ // check again after acquiring lock, another process could have built it in the meantime
285+ do_build = needs_build ( ) ;
282286 }
283- ( dest_dylib_path, artifacts_found && ! self . rebuild_codegen )
287+ ( dest_dylib_path, do_build || self . rebuild_codegen )
284288 } ;
285289
286- if skip_rebuild {
287- log:: info!( "...and so we are aborting the install step." ) ;
288- } else {
290+ if do_build {
289291 Self :: write_source_files ( & source, & install_dir) . context ( "writing source files" ) ?;
292+ } else {
293+ log:: info!(
294+ "cargo-gpu artifacts found in '{}', skipping install" ,
295+ install_dir. display( )
296+ ) ;
290297 }
291298
292299 // TODO cache toolchain channel in a file?
@@ -309,7 +316,7 @@ package = "rustc_codegen_spirv"
309316 )
310317 . context ( "ensuring toolchain and components exist" ) ?;
311318
312- if !skip_rebuild {
319+ if do_build {
313320 // to prevent unsupported version errors when using older toolchains
314321 if !source. is_path ( ) {
315322 log:: debug!( "remove Cargo.lock" ) ;
@@ -372,3 +379,21 @@ package = "rustc_codegen_spirv"
372379 } )
373380 }
374381}
382+
383+ #[ allow( dead_code) ]
384+ pub struct FileLock ( std:: fs:: File ) ;
385+
386+ impl FileLock {
387+ pub fn lock ( path : & Path ) -> std:: io:: Result < Self > {
388+ let file = std:: fs:: File :: create ( path) ?;
389+ match file. try_lock ( ) {
390+ Ok ( _) => ( ) ,
391+ Err ( std:: fs:: TryLockError :: WouldBlock ) => {
392+ user_output ! ( "Waiting for file lock on codegen backend build...\n " ) ;
393+ file. lock ( ) ?;
394+ }
395+ Err ( std:: fs:: TryLockError :: Error ( e) ) => return Err ( e) ,
396+ }
397+ Ok ( Self ( file) )
398+ }
399+ }
0 commit comments