@@ -24,11 +24,13 @@ use rustc_span::source_map::FileLoader;
24
24
use rustc_span:: symbol:: { sym, Symbol } ;
25
25
use smallvec:: SmallVec ;
26
26
use std:: env;
27
+ use std:: env:: consts:: { DLL_PREFIX , DLL_SUFFIX } ;
27
28
use std:: io:: { self , Write } ;
28
29
use std:: lazy:: SyncOnceCell ;
29
30
use std:: mem;
30
31
use std:: ops:: DerefMut ;
31
32
use std:: path:: { Path , PathBuf } ;
33
+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
32
34
use std:: sync:: { Arc , Mutex , Once } ;
33
35
#[ cfg( not( parallel_compiler) ) ]
34
36
use std:: { panic, thread} ;
@@ -238,7 +240,19 @@ pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
238
240
static mut LOAD : fn ( ) -> Box < dyn CodegenBackend > = || unreachable ! ( ) ;
239
241
240
242
INIT . call_once ( || {
241
- let codegen_name = sopts. debugging_opts . codegen_backend . as_deref ( ) . unwrap_or ( "llvm" ) ;
243
+ #[ cfg( feature = "llvm" ) ]
244
+ const DEFAULT_CODEGEN_BACKEND : & ' static str = "llvm" ;
245
+
246
+ #[ cfg( not( feature = "llvm" ) ) ]
247
+ const DEFAULT_CODEGEN_BACKEND : & ' static str = "cranelift" ;
248
+
249
+ let codegen_name = sopts
250
+ . debugging_opts
251
+ . codegen_backend
252
+ . as_ref ( )
253
+ . map ( |name| & name[ ..] )
254
+ . unwrap_or ( DEFAULT_CODEGEN_BACKEND ) ;
255
+
242
256
let backend = match codegen_name {
243
257
filename if filename. contains ( '.' ) => load_backend_from_dylib ( filename. as_ref ( ) ) ,
244
258
codegen_name => get_builtin_codegen_backend ( codegen_name) ,
@@ -367,15 +381,102 @@ fn sysroot_candidates() -> Vec<PathBuf> {
367
381
}
368
382
369
383
pub fn get_builtin_codegen_backend ( backend_name : & str ) -> fn ( ) -> Box < dyn CodegenBackend > {
370
- #[ cfg( feature = "llvm" ) ]
371
- {
372
- if backend_name == "llvm" {
373
- return rustc_codegen_llvm:: LlvmCodegenBackend :: new;
384
+ match backend_name {
385
+ #[ cfg( feature = "llvm" ) ]
386
+ "llvm" => rustc_codegen_llvm:: LlvmCodegenBackend :: new,
387
+ _ => get_codegen_sysroot ( backend_name) ,
388
+ }
389
+ }
390
+
391
+ pub fn get_codegen_sysroot ( backend_name : & str ) -> fn ( ) -> Box < dyn CodegenBackend > {
392
+ // For now we only allow this function to be called once as it'll dlopen a
393
+ // few things, which seems to work best if we only do that once. In
394
+ // general this assertion never trips due to the once guard in `get_codegen_backend`,
395
+ // but there's a few manual calls to this function in this file we protect
396
+ // against.
397
+ static LOADED : AtomicBool = AtomicBool :: new ( false ) ;
398
+ assert ! (
399
+ !LOADED . fetch_or( true , Ordering :: SeqCst ) ,
400
+ "cannot load the default codegen backend twice"
401
+ ) ;
402
+
403
+ let target = session:: config:: host_triple ( ) ;
404
+ let sysroot_candidates = sysroot_candidates ( ) ;
405
+
406
+ let sysroot = sysroot_candidates
407
+ . iter ( )
408
+ . map ( |sysroot| {
409
+ let libdir = filesearch:: relative_target_lib_path ( & sysroot, & target) ;
410
+ sysroot. join ( libdir) . with_file_name ( "codegen-backends" )
411
+ } )
412
+ . filter ( |f| {
413
+ info ! ( "codegen backend candidate: {}" , f. display( ) ) ;
414
+ f. exists ( )
415
+ } )
416
+ . next ( ) ;
417
+ let sysroot = sysroot. unwrap_or_else ( || {
418
+ let candidates = sysroot_candidates
419
+ . iter ( )
420
+ . map ( |p| p. display ( ) . to_string ( ) )
421
+ . collect :: < Vec < _ > > ( )
422
+ . join ( "\n * " ) ;
423
+ let err = format ! (
424
+ "failed to find a `codegen-backends` folder \
425
+ in the sysroot candidates:\n * {}",
426
+ candidates
427
+ ) ;
428
+ early_error ( ErrorOutputType :: default ( ) , & err) ;
429
+ } ) ;
430
+ info ! ( "probing {} for a codegen backend" , sysroot. display( ) ) ;
431
+
432
+ let d = sysroot. read_dir ( ) . unwrap_or_else ( |e| {
433
+ let err = format ! (
434
+ "failed to load default codegen backend, couldn't \
435
+ read `{}`: {}",
436
+ sysroot. display( ) ,
437
+ e
438
+ ) ;
439
+ early_error ( ErrorOutputType :: default ( ) , & err) ;
440
+ } ) ;
441
+
442
+ let mut file: Option < PathBuf > = None ;
443
+
444
+ let expected_name =
445
+ format ! ( "rustc_codegen_{}-{}" , backend_name, release_str( ) . expect( "CFG_RELEASE" ) ) ;
446
+ for entry in d. filter_map ( |e| e. ok ( ) ) {
447
+ let path = entry. path ( ) ;
448
+ let filename = match path. file_name ( ) . and_then ( |s| s. to_str ( ) ) {
449
+ Some ( s) => s,
450
+ None => continue ,
451
+ } ;
452
+ if !( filename. starts_with ( DLL_PREFIX ) && filename. ends_with ( DLL_SUFFIX ) ) {
453
+ continue ;
374
454
}
455
+ let name = & filename[ DLL_PREFIX . len ( ) ..filename. len ( ) - DLL_SUFFIX . len ( ) ] ;
456
+ if name != expected_name {
457
+ continue ;
458
+ }
459
+ if let Some ( ref prev) = file {
460
+ let err = format ! (
461
+ "duplicate codegen backends found\n \
462
+ first: {}\n \
463
+ second: {}\n \
464
+ ",
465
+ prev. display( ) ,
466
+ path. display( )
467
+ ) ;
468
+ early_error ( ErrorOutputType :: default ( ) , & err) ;
469
+ }
470
+ file = Some ( path. clone ( ) ) ;
375
471
}
376
472
377
- let err = format ! ( "unsupported builtin codegen backend `{}`" , backend_name) ;
378
- early_error ( ErrorOutputType :: default ( ) , & err) ;
473
+ match file {
474
+ Some ( ref s) => load_backend_from_dylib ( s) ,
475
+ None => {
476
+ let err = format ! ( "unsupported builtin codegen backend `{}`" , backend_name) ;
477
+ early_error ( ErrorOutputType :: default ( ) , & err) ;
478
+ }
479
+ }
379
480
}
380
481
381
482
pub ( crate ) fn compute_crate_disambiguator ( session : & Session ) -> CrateDisambiguator {
@@ -782,3 +883,23 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
782
883
noop_visit_mac ( mac, self )
783
884
}
784
885
}
886
+
887
+ /// Returns a version string such as "rustc 1.46.0 (04488afe3 2020-08-24)"
888
+ pub fn version_str ( ) -> Option < & ' static str > {
889
+ option_env ! ( "CFG_VERSION" )
890
+ }
891
+
892
+ /// Returns a version string such as "0.12.0-dev".
893
+ pub fn release_str ( ) -> Option < & ' static str > {
894
+ option_env ! ( "CFG_RELEASE" )
895
+ }
896
+
897
+ /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
898
+ pub fn commit_hash_str ( ) -> Option < & ' static str > {
899
+ option_env ! ( "CFG_VER_HASH" )
900
+ }
901
+
902
+ /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
903
+ pub fn commit_date_str ( ) -> Option < & ' static str > {
904
+ option_env ! ( "CFG_VER_DATE" )
905
+ }
0 commit comments