@@ -464,26 +464,25 @@ fn is_writeable(p: &Path) -> bool {
464464
465465pub fn filename_for_input ( sess : & Session ,
466466 crate_type : config:: CrateType ,
467- name : & str ,
468- out_filename : & Path ) -> PathBuf {
469- let libname = format ! ( "{}{}" , name , sess. opts. cg. extra_filename) ;
467+ crate_name : & str ,
468+ outputs : & OutputFilenames ) -> PathBuf {
469+ let libname = format ! ( "{}{}" , crate_name , sess. opts. cg. extra_filename) ;
470470 match crate_type {
471471 config:: CrateTypeRlib => {
472- out_filename . with_file_name ( & format ! ( "lib{}.rlib" , libname) )
472+ outputs . out_directory . join ( & format ! ( "lib{}.rlib" , libname) )
473473 }
474474 config:: CrateTypeDylib => {
475475 let ( prefix, suffix) = ( & sess. target . target . options . dll_prefix ,
476476 & sess. target . target . options . dll_suffix ) ;
477- out_filename. with_file_name ( & format ! ( "{}{}{}" ,
478- prefix,
479- libname,
480- suffix) )
477+ outputs. out_directory . join ( & format ! ( "{}{}{}" , prefix, libname,
478+ suffix) )
481479 }
482480 config:: CrateTypeStaticlib => {
483- out_filename . with_file_name ( & format ! ( "lib{}.a" , libname) )
481+ outputs . out_directory . join ( & format ! ( "lib{}.a" , libname) )
484482 }
485483 config:: CrateTypeExecutable => {
486484 let suffix = & sess. target . target . options . exe_suffix ;
485+ let out_filename = outputs. path ( OutputTypeExe ) ;
487486 if suffix. is_empty ( ) {
488487 out_filename. to_path_buf ( )
489488 } else {
@@ -501,10 +500,7 @@ fn link_binary_output(sess: &Session,
501500 let objects = object_filenames ( sess, outputs) ;
502501 let out_filename = match outputs. single_output_file {
503502 Some ( ref file) => file. clone ( ) ,
504- None => {
505- let out_filename = outputs. path ( OutputTypeExe ) ;
506- filename_for_input ( sess, crate_type, crate_name, & out_filename)
507- }
503+ None => filename_for_input ( sess, crate_type, crate_name, outputs) ,
508504 } ;
509505
510506 // Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
@@ -551,6 +547,19 @@ fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
551547 return search;
552548}
553549
550+ fn archive_config < ' a > ( sess : & ' a Session ,
551+ output : & Path ) -> ArchiveConfig < ' a > {
552+ ArchiveConfig {
553+ handler : & sess. diagnostic ( ) . handler ,
554+ dst : output. to_path_buf ( ) ,
555+ lib_search_paths : archive_search_paths ( sess) ,
556+ slib_prefix : sess. target . target . options . staticlib_prefix . clone ( ) ,
557+ slib_suffix : sess. target . target . options . staticlib_suffix . clone ( ) ,
558+ ar_prog : get_ar_prog ( sess) ,
559+ command_path : command_path ( sess) ,
560+ }
561+ }
562+
554563// Create an 'rlib'
555564//
556565// An rlib in its current incarnation is essentially a renamed .a file. The
@@ -562,17 +571,7 @@ fn link_rlib<'a>(sess: &'a Session,
562571 objects : & [ PathBuf ] ,
563572 out_filename : & Path ) -> ArchiveBuilder < ' a > {
564573 info ! ( "preparing rlib from {:?} to {:?}" , objects, out_filename) ;
565- let handler = & sess. diagnostic ( ) . handler ;
566- let config = ArchiveConfig {
567- handler : handler,
568- dst : out_filename. to_path_buf ( ) ,
569- lib_search_paths : archive_search_paths ( sess) ,
570- slib_prefix : sess. target . target . options . staticlib_prefix . clone ( ) ,
571- slib_suffix : sess. target . target . options . staticlib_suffix . clone ( ) ,
572- ar_prog : get_ar_prog ( sess) ,
573- command_path : command_path ( sess) ,
574- } ;
575- let mut ab = ArchiveBuilder :: create ( config) ;
574+ let mut ab = ArchiveBuilder :: create ( archive_config ( sess, out_filename) ) ;
576575 for obj in objects {
577576 ab. add_file ( obj) . unwrap ( ) ;
578577 }
@@ -1131,7 +1130,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
11311130 add_dynamic_crate ( cmd, sess, & src. dylib . unwrap ( ) . 0 )
11321131 }
11331132 cstore:: RequireStatic => {
1134- add_static_crate ( cmd, sess, tmpdir, & src. rlib . unwrap ( ) . 0 )
1133+ add_static_crate ( cmd, sess, tmpdir, dylib , & src. rlib . unwrap ( ) . 0 )
11351134 }
11361135 }
11371136
@@ -1147,71 +1146,80 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
11471146 }
11481147
11491148 // Adds the static "rlib" versions of all crates to the command line.
1149+ // There's a bit of magic which happens here specifically related to LTO and
1150+ // dynamic libraries. Specifically:
1151+ //
1152+ // * For LTO, we remove upstream object files.
1153+ // * For dylibs we remove metadata and bytecode from upstream rlibs
1154+ //
1155+ // When performing LTO, all of the bytecode from the upstream libraries has
1156+ // already been included in our object file output. As a result we need to
1157+ // remove the object files in the upstream libraries so the linker doesn't
1158+ // try to include them twice (or whine about duplicate symbols). We must
1159+ // continue to include the rest of the rlib, however, as it may contain
1160+ // static native libraries which must be linked in.
1161+ //
1162+ // When making a dynamic library, linkers by default don't include any
1163+ // object files in an archive if they're not necessary to resolve the link.
1164+ // We basically want to convert the archive (rlib) to a dylib, though, so we
1165+ // *do* want everything included in the output, regardless of whether the
1166+ // linker thinks it's needed or not. As a result we must use the
1167+ // --whole-archive option (or the platform equivalent). When using this
1168+ // option the linker will fail if there are non-objects in the archive (such
1169+ // as our own metadata and/or bytecode). All in all, for rlibs to be
1170+ // entirely included in dylibs, we need to remove all non-object files.
1171+ //
1172+ // Note, however, that if we're not doing LTO or we're not producing a dylib
1173+ // (aka we're making an executable), we can just pass the rlib blindly to
1174+ // the linker (fast) because it's fine if it's not actually included as
1175+ // we're at the end of the dependency chain.
11501176 fn add_static_crate ( cmd : & mut Linker , sess : & Session , tmpdir : & Path ,
1151- cratepath : & Path ) {
1152- // When performing LTO on an executable output, all of the
1153- // bytecode from the upstream libraries has already been
1154- // included in our object file output. We need to modify all of
1155- // the upstream archives to remove their corresponding object
1156- // file to make sure we don't pull the same code in twice.
1157- //
1158- // We must continue to link to the upstream archives to be sure
1159- // to pull in native static dependencies. As the final caveat,
1160- // on Linux it is apparently illegal to link to a blank archive,
1161- // so if an archive no longer has any object files in it after
1162- // we remove `lib.o`, then don't link against it at all.
1163- //
1164- // If we're not doing LTO, then our job is simply to just link
1165- // against the archive.
1166- if sess. lto ( ) {
1167- let name = cratepath. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
1168- let name = & name[ 3 ..name. len ( ) - 5 ] ; // chop off lib/.rlib
1169- time ( sess. time_passes ( ) ,
1170- & format ! ( "altering {}.rlib" , name) ,
1171- ( ) , |( ) | {
1172- let dst = tmpdir. join ( cratepath. file_name ( ) . unwrap ( ) ) ;
1173- match fs:: copy ( & cratepath, & dst) {
1174- Ok ( ..) => { }
1175- Err ( e) => {
1176- sess. fatal ( & format ! ( "failed to copy {} to {}: {}" ,
1177- cratepath. display( ) ,
1178- dst. display( ) , e) ) ;
1179- }
1177+ dylib : bool , cratepath : & Path ) {
1178+ if !sess. lto ( ) && !dylib {
1179+ cmd. link_rlib ( & fix_windows_verbatim_for_gcc ( cratepath) ) ;
1180+ return
1181+ }
1182+
1183+ let dst = tmpdir. join ( cratepath. file_name ( ) . unwrap ( ) ) ;
1184+ let name = cratepath. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
1185+ let name = & name[ 3 ..name. len ( ) - 5 ] ; // chop off lib/.rlib
1186+
1187+ time ( sess. time_passes ( ) , & format ! ( "altering {}.rlib" , name) , ( ) , |( ) | {
1188+ let err = ( || {
1189+ io:: copy ( & mut try!( fs:: File :: open ( & cratepath) ) ,
1190+ & mut try!( fs:: File :: create ( & dst) ) )
1191+ } ) ( ) ;
1192+ if let Err ( e) = err {
1193+ sess. fatal ( & format ! ( "failed to copy {} to {}: {}" ,
1194+ cratepath. display( ) , dst. display( ) , e) ) ;
1195+ }
1196+
1197+ let mut archive = Archive :: open ( archive_config ( sess, & dst) ) ;
1198+ archive. remove_file ( METADATA_FILENAME ) ;
1199+
1200+ let mut any_objects = false ;
1201+ for f in archive. files ( ) {
1202+ if f. ends_with ( "bytecode.deflate" ) {
1203+ archive. remove_file ( & f) ;
1204+ continue
11801205 }
1181- // Fix up permissions of the copy, as fs::copy() preserves
1182- // permissions, but the original file may have been installed
1183- // by a package manager and may be read-only.
1184- match fs:: metadata ( & dst) . and_then ( |m| {
1185- let mut perms = m. permissions ( ) ;
1186- perms. set_readonly ( false ) ;
1187- fs:: set_permissions ( & dst, perms)
1188- } ) {
1189- Ok ( ..) => { }
1190- Err ( e) => {
1191- sess. fatal ( & format ! ( "failed to chmod {} when preparing \
1192- for LTO: {}", dst. display( ) , e) ) ;
1206+ let canonical = f. replace ( "-" , "_" ) ;
1207+ let canonical_name = name. replace ( "-" , "_" ) ;
1208+ if sess. lto ( ) && canonical. starts_with ( & canonical_name) &&
1209+ canonical. ends_with ( ".o" ) {
1210+ let num = & f[ name. len ( ) ..f. len ( ) - 2 ] ;
1211+ if num. len ( ) > 0 && num[ 1 ..] . parse :: < u32 > ( ) . is_ok ( ) {
1212+ archive. remove_file ( & f) ;
1213+ continue
11931214 }
11941215 }
1195- let handler = & sess. diagnostic ( ) . handler ;
1196- let config = ArchiveConfig {
1197- handler : handler,
1198- dst : dst. clone ( ) ,
1199- lib_search_paths : archive_search_paths ( sess) ,
1200- slib_prefix : sess. target . target . options . staticlib_prefix . clone ( ) ,
1201- slib_suffix : sess. target . target . options . staticlib_suffix . clone ( ) ,
1202- ar_prog : get_ar_prog ( sess) ,
1203- command_path : command_path ( sess) ,
1204- } ;
1205- let mut archive = Archive :: open ( config) ;
1206- archive. remove_file ( & format ! ( "{}.o" , name) ) ;
1207- let files = archive. files ( ) ;
1208- if files. iter ( ) . any ( |s| s. ends_with ( ".o" ) ) {
1209- cmd. link_rlib ( & dst) ;
1210- }
1211- } ) ;
1212- } else {
1213- cmd. link_rlib ( & fix_windows_verbatim_for_gcc ( cratepath) ) ;
1214- }
1216+ any_objects = true ;
1217+ }
1218+
1219+ if any_objects {
1220+ cmd. link_whole_rlib ( & fix_windows_verbatim_for_gcc ( & dst) ) ;
1221+ }
1222+ } ) ;
12151223 }
12161224
12171225 // Same thing as above, but for dynamic crates instead of static crates.
0 commit comments