@@ -459,10 +459,15 @@ mod c_vendor {
459
459
460
460
#[ cfg( feature = "c-system" ) ]
461
461
mod c_system {
462
+ extern crate ar;
463
+
464
+ use std:: collections:: HashMap ;
462
465
use std:: env;
466
+ use std:: fs:: File ;
463
467
use std:: process:: { Command , Output } ;
464
468
use std:: str;
465
- use std:: path:: Path ;
469
+ use std:: path:: { Path , PathBuf } ;
470
+
466
471
use sources;
467
472
468
473
fn success_output ( err : & str , cmd : & mut Command ) -> Output {
@@ -502,57 +507,99 @@ mod c_system {
502
507
r. to_string ( )
503
508
}
504
509
510
+ fn find_library < I > ( dirs : I , libname : & str ) -> Result < PathBuf , Vec < String > >
511
+ where
512
+ I : Iterator < Item = PathBuf >
513
+ {
514
+ let mut paths = Vec :: new ( ) ;
515
+ for dir in dirs {
516
+ let try_path = dir. join ( format ! ( "lib{}.a" , libname) ) ;
517
+ if try_path. exists ( ) {
518
+ return Ok ( try_path. to_path_buf ( ) ) ;
519
+ } else {
520
+ paths. push ( format ! ( "{:?}" , try_path) )
521
+ }
522
+ }
523
+ Err ( paths)
524
+ }
525
+
505
526
/// Link against system clang runtime libraries
506
527
pub fn compile ( llvm_target : & [ & str ] ) {
507
528
let target = env:: var ( "TARGET" ) . unwrap ( ) ;
508
529
let target_os = env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap ( ) ;
509
530
let compiler_rt_arch = get_arch_name_for_compiler_rtlib ( ) ;
531
+ let out_dir = env:: var ( "OUT_DIR" ) . unwrap ( ) ;
510
532
511
533
if ALL_SUPPORTED_ARCHES . split ( ";" ) . find ( |x| * x == compiler_rt_arch) == None {
512
534
return ;
513
535
}
514
536
515
- if let Ok ( clang) = env:: var ( "CLANG" ) {
537
+ println ! ( "cargo:rerun-if-env-changed=CLANG" ) ;
538
+ println ! ( "cargo:rerun-if-env-changed=LLVM_CONFIG" ) ;
539
+
540
+ let fullpath = if let Ok ( clang) = env:: var ( "CLANG" ) {
516
541
let output = success_output (
517
542
"failed to find clang's compiler-rt" ,
518
543
Command :: new ( clang)
519
544
. arg ( format ! ( "--target={}" , target) )
520
545
. arg ( "--rtlib=compiler-rt" )
521
546
. arg ( "--print-libgcc-file-name" ) ,
522
547
) ;
523
- let fullpath = Path :: new ( str:: from_utf8 ( & output. stdout ) . unwrap ( ) ) ;
524
- let libpath = fullpath. parent ( ) . unwrap ( ) . display ( ) ;
525
- let libname = fullpath
526
- . file_stem ( )
527
- . unwrap ( )
528
- . to_str ( )
529
- . unwrap ( )
530
- . trim_start_matches ( "lib" ) ;
531
- println ! ( "cargo:rustc-link-search=native={}" , libpath) ;
532
- println ! ( "cargo:rustc-link-lib=static={}" , libname) ;
548
+ let path = str:: from_utf8 ( & output. stdout ) . unwrap ( ) . trim_end ( ) ;
549
+ Path :: new ( path) . to_path_buf ( )
533
550
} else if let Ok ( llvm_config) = env:: var ( "LLVM_CONFIG" ) {
534
551
// fallback if clang is not installed
535
552
let ( subpath, libname) = match target_os. as_str ( ) {
536
553
"linux" => ( "linux" , format ! ( "clang_rt.builtins-{}" , & compiler_rt_arch) ) ,
537
554
"macos" => ( "darwin" , "clang_rt.builtins_osx_dynamic" . to_string ( ) ) ,
538
555
_ => panic ! ( "unsupported target os: {}" , target_os) ,
539
556
} ;
540
- let cmd = format ! ( "ls -1d $({} --libdir)/clang/*/lib/{}" , llvm_config, subpath) ;
541
557
let output = success_output (
542
- "failed to find clang 's lib dir" ,
543
- Command :: new ( "sh" ) . args ( & [ "-ec" , & cmd ] ) ,
558
+ "failed to find llvm-config 's lib dir" ,
559
+ Command :: new ( llvm_config ) . arg ( "--libdir" ) ,
544
560
) ;
545
- for search_dir in str:: from_utf8 ( & output. stdout ) . unwrap ( ) . lines ( ) {
546
- println ! ( "cargo:rustc-link-search=native={}" , search_dir) ;
561
+ let libdir = str:: from_utf8 ( & output. stdout ) . unwrap ( ) . trim_end ( ) ;
562
+ let paths = std:: fs:: read_dir ( Path :: new ( libdir) . join ( "clang" ) ) . unwrap ( ) . map ( |e| {
563
+ e. unwrap ( ) . path ( ) . join ( "lib" ) . join ( subpath)
564
+ } ) ;
565
+ match find_library ( paths, & libname) {
566
+ Ok ( p) => p,
567
+ Err ( paths) => panic ! ( "failed to find llvm-config's compiler-rt: {}" , paths. join( ":" ) ) ,
547
568
}
548
- println ! ( "cargo:rustc-link-lib=static={}" , libname) ;
549
569
} else {
550
570
panic ! ( "neither CLANG nor LLVM_CONFIG could be read" ) ;
571
+ } ;
572
+
573
+ let mut index = 0 ;
574
+ let mut files = HashMap :: new ( ) ;
575
+ let mut orig = ar:: Archive :: new ( File :: open ( & fullpath) . unwrap ( ) ) ;
576
+ while let Some ( entry_result) = orig. next_entry ( ) {
577
+ let entry = entry_result. unwrap ( ) ;
578
+ let name = str:: from_utf8 ( entry. header ( ) . identifier ( ) ) . unwrap ( ) ;
579
+ files. insert ( name. to_owned ( ) , index) ;
580
+ index += 1 ;
551
581
}
552
582
553
583
let sources = sources:: get_sources ( llvm_target) ;
584
+ let mut new = ar:: Builder :: new ( File :: create ( Path :: new ( & out_dir) . join ( "libcompiler-rt.a" ) ) . unwrap ( ) ) ;
554
585
for ( sym, _src) in sources. map . iter ( ) {
586
+ let & i = {
587
+ let sym_ = if sym. starts_with ( "__" ) { & sym[ 2 ..] } else { & sym } ;
588
+ match files. get ( & format ! ( "{}.c.o" , sym_) ) {
589
+ Some ( i) => i,
590
+ None => match files. get ( & format ! ( "{}.S.o" , sym_) ) {
591
+ Some ( i) => i,
592
+ None => panic ! ( "could not find expected symbol {} in {:?}" , sym, & fullpath) ,
593
+ } ,
594
+ }
595
+ } ;
596
+ let mut entry = orig. jump_to_entry ( i) . unwrap ( ) ;
597
+ // TODO: ar really should have an append_entry to avoid the clone
598
+ new. append ( & entry. header ( ) . clone ( ) , & mut entry) . unwrap ( ) ;
555
599
println ! ( "cargo:rustc-cfg={}=\" optimized-c\" " , sym) ;
556
600
}
601
+
602
+ println ! ( "cargo:rustc-link-search=native={}" , out_dir) ;
603
+ println ! ( "cargo:rustc-link-lib=static={}" , "compiler-rt" ) ;
557
604
}
558
605
}
0 commit comments