@@ -24,11 +24,13 @@ use rustc_span::source_map::FileLoader;
2424use rustc_span:: symbol:: { sym, Symbol } ;
2525use smallvec:: SmallVec ;
2626use std:: env;
27+ use std:: env:: consts:: { DLL_PREFIX , DLL_SUFFIX } ;
2728use std:: io:: { self , Write } ;
2829use std:: lazy:: SyncOnceCell ;
2930use std:: mem;
3031use std:: ops:: DerefMut ;
3132use std:: path:: { Path , PathBuf } ;
33+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
3234use std:: sync:: { Arc , Mutex , Once } ;
3335#[ cfg( not( parallel_compiler) ) ]
3436use std:: { panic, thread} ;
@@ -238,7 +240,19 @@ pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
238240 static mut LOAD : fn ( ) -> Box < dyn CodegenBackend > = || unreachable ! ( ) ;
239241
240242 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+
242256 let backend = match codegen_name {
243257 filename if filename. contains ( '.' ) => load_backend_from_dylib ( filename. as_ref ( ) ) ,
244258 codegen_name => get_builtin_codegen_backend ( codegen_name) ,
@@ -367,15 +381,102 @@ fn sysroot_candidates() -> Vec<PathBuf> {
367381}
368382
369383pub 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 ;
374454 }
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 ( ) ) ;
375471 }
376472
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+ }
379480}
380481
381482pub ( crate ) fn compute_crate_disambiguator ( session : & Session ) -> CrateDisambiguator {
@@ -782,3 +883,23 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
782883 noop_visit_mac ( mac, self )
783884 }
784885}
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