@@ -464,26 +464,25 @@ fn is_writeable(p: &Path) -> bool {
464
464
465
465
pub fn filename_for_input ( sess : & Session ,
466
466
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) ;
470
470
match crate_type {
471
471
config:: CrateTypeRlib => {
472
- out_filename . with_file_name ( & format ! ( "lib{}.rlib" , libname) )
472
+ outputs . out_directory . join ( & format ! ( "lib{}.rlib" , libname) )
473
473
}
474
474
config:: CrateTypeDylib => {
475
475
let ( prefix, suffix) = ( & sess. target . target . options . dll_prefix ,
476
476
& 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) )
481
479
}
482
480
config:: CrateTypeStaticlib => {
483
- out_filename . with_file_name ( & format ! ( "lib{}.a" , libname) )
481
+ outputs . out_directory . join ( & format ! ( "lib{}.a" , libname) )
484
482
}
485
483
config:: CrateTypeExecutable => {
486
484
let suffix = & sess. target . target . options . exe_suffix ;
485
+ let out_filename = outputs. path ( OutputTypeExe ) ;
487
486
if suffix. is_empty ( ) {
488
487
out_filename. to_path_buf ( )
489
488
} else {
@@ -501,10 +500,7 @@ fn link_binary_output(sess: &Session,
501
500
let objects = object_filenames ( sess, outputs) ;
502
501
let out_filename = match outputs. single_output_file {
503
502
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) ,
508
504
} ;
509
505
510
506
// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
@@ -551,6 +547,19 @@ fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
551
547
return search;
552
548
}
553
549
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
+
554
563
// Create an 'rlib'
555
564
//
556
565
// An rlib in its current incarnation is essentially a renamed .a file. The
@@ -562,17 +571,7 @@ fn link_rlib<'a>(sess: &'a Session,
562
571
objects : & [ PathBuf ] ,
563
572
out_filename : & Path ) -> ArchiveBuilder < ' a > {
564
573
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) ) ;
576
575
for obj in objects {
577
576
ab. add_file ( obj) . unwrap ( ) ;
578
577
}
@@ -1131,7 +1130,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
1131
1130
add_dynamic_crate ( cmd, sess, & src. dylib . unwrap ( ) . 0 )
1132
1131
}
1133
1132
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 )
1135
1134
}
1136
1135
}
1137
1136
@@ -1147,71 +1146,80 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
1147
1146
}
1148
1147
1149
1148
// 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.
1150
1176
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
1180
1205
}
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
1193
1214
}
1194
1215
}
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
+ } ) ;
1215
1223
}
1216
1224
1217
1225
// Same thing as above, but for dynamic crates instead of static crates.
0 commit comments