@@ -1220,6 +1220,74 @@ fn add_local_native_libraries(args: &mut ~[~str], sess: Session) {
1220
1220
// the intermediate rlib version)
1221
1221
fn add_upstream_rust_crates ( args : & mut ~[ ~str ] , sess : Session ,
1222
1222
dylib : bool , tmpdir : & Path ) {
1223
+
1224
+ // As a limitation of the current implementation, we require that everything
1225
+ // must be static or everything must be dynamic. The reasons for this are a
1226
+ // little subtle, but as with staticlibs and rlibs, the goal is to prevent
1227
+ // duplicate copies of the same library showing up. For example, a static
1228
+ // immediate dependency might show up as an upstream dynamic dependency and
1229
+ // we currently have no way of knowing that. We know that all dynamic
1230
+ // libraries require dynamic dependencies (see above), so it's satisfactory
1231
+ // to include either all static libraries or all dynamic libraries.
1232
+ //
1233
+ // With this limitation, we expose a compiler default linkage type and an
1234
+ // option to reverse that preference. The current behavior looks like:
1235
+ //
1236
+ // * If a dylib is being created, upstream dependencies must be dylibs
1237
+ // * If nothing else is specified, static linking is preferred
1238
+ // * If the -C prefer-dynamic flag is given, dynamic linking is preferred
1239
+ // * If one form of linking fails, the second is also attempted
1240
+ // * If both forms fail, then we emit an error message
1241
+
1242
+ let dynamic = get_deps ( sess. cstore , cstore:: RequireDynamic ) ;
1243
+ let statik = get_deps ( sess. cstore , cstore:: RequireStatic ) ;
1244
+ match ( dynamic, statik, sess. opts . cg . prefer_dynamic , dylib) {
1245
+ ( _, Some ( deps) , false , false ) => {
1246
+ add_static_crates ( args, sess, tmpdir, deps)
1247
+ }
1248
+
1249
+ ( None , Some ( deps) , true , false ) => {
1250
+ // If you opted in to dynamic linking and we decided to emit a
1251
+ // static output, you should probably be notified of such an event!
1252
+ sess. warn ( "dynamic linking was preferred, but dependencies \
1253
+ could not all be found in an dylib format.") ;
1254
+ sess. warn ( "linking statically instead, using rlibs" ) ;
1255
+ add_static_crates ( args, sess, tmpdir, deps)
1256
+ }
1257
+
1258
+ ( Some ( deps) , _, _, _) => add_dynamic_crates ( args, sess, deps) ,
1259
+
1260
+ ( None , _, _, true ) => {
1261
+ sess. err ( "dylib output requested, but some depenencies could not \
1262
+ be found in the dylib format") ;
1263
+ let deps = sess. cstore . get_used_crates ( cstore:: RequireDynamic ) ;
1264
+ for ( cnum, path) in deps. move_iter ( ) {
1265
+ if path. is_some ( ) { continue }
1266
+ let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1267
+ sess. note ( format ! ( "dylib not found: {}" , name) ) ;
1268
+ }
1269
+ }
1270
+
1271
+ ( None , None , pref, false ) => {
1272
+ let ( pref, name) = if pref {
1273
+ sess. err ( "dynamic linking is preferred, but dependencies were \
1274
+ not found in either dylib or rlib format") ;
1275
+ ( cstore:: RequireDynamic , "dylib" )
1276
+ } else {
1277
+ sess. err ( "dependencies were not all found in either dylib or \
1278
+ rlib format") ;
1279
+ ( cstore:: RequireStatic , "rlib" )
1280
+ } ;
1281
+ sess. note ( format ! ( "dependencies not found in the `{}` format" ,
1282
+ name) ) ;
1283
+ for ( cnum, path) in sess. cstore . get_used_crates ( pref) . move_iter ( ) {
1284
+ if path. is_some ( ) { continue }
1285
+ let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1286
+ sess. note ( name) ;
1287
+ }
1288
+ }
1289
+ }
1290
+
1223
1291
// Converts a library file-stem into a cc -l argument
1224
1292
fn unlib ( config : @session:: Config , stem : & str ) -> ~str {
1225
1293
if stem. starts_with ( "lib" ) &&
@@ -1230,96 +1298,82 @@ fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session,
1230
1298
}
1231
1299
}
1232
1300
1233
- let cstore = sess. cstore ;
1234
- if !dylib && !sess. opts . cg . prefer_dynamic {
1235
- // With an executable, things get a little interesting. As a limitation
1236
- // of the current implementation, we require that everything must be
1237
- // static or everything must be dynamic. The reasons for this are a
1238
- // little subtle, but as with the above two cases, the goal is to
1239
- // prevent duplicate copies of the same library showing up. For example,
1240
- // a static immediate dependency might show up as an upstream dynamic
1241
- // dependency and we currently have no way of knowing that. We know that
1242
- // all dynamic libraries require dynamic dependencies (see above), so
1243
- // it's satisfactory to include either all static libraries or all
1244
- // dynamic libraries.
1245
- let crates = cstore. get_used_crates ( cstore:: RequireStatic ) ;
1301
+ // Attempts to find all dependencies with a certain linkage preference,
1302
+ // returning `None` if not all libraries could be found with that
1303
+ // preference.
1304
+ fn get_deps ( cstore : & cstore:: CStore , preference : cstore:: LinkagePreference )
1305
+ -> Option < ~[ ( ast:: CrateNum , Path ) ] >
1306
+ {
1307
+ let crates = cstore. get_used_crates ( preference) ;
1246
1308
if crates. iter ( ) . all ( |& ( _, ref p) | p. is_some ( ) ) {
1247
- for ( cnum, path) in crates. move_iter ( ) {
1248
- let cratepath = path. unwrap ( ) ;
1249
-
1250
- // When performing LTO on an executable output, all of the
1251
- // bytecode from the upstream libraries has already been
1252
- // included in our object file output. We need to modify all of
1253
- // the upstream archives to remove their corresponding object
1254
- // file to make sure we don't pull the same code in twice.
1255
- //
1256
- // We must continue to link to the upstream archives to be sure
1257
- // to pull in native static dependencies. As the final caveat,
1258
- // on linux it is apparently illegal to link to a blank archive,
1259
- // so if an archive no longer has any object files in it after
1260
- // we remove `lib.o`, then don't link against it at all.
1261
- //
1262
- // If we're not doing LTO, then our job is simply to just link
1263
- // against the archive.
1264
- if sess. lto ( ) {
1265
- let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1266
- time ( sess. time_passes ( ) , format ! ( "altering {}.rlib" , name) ,
1267
- ( ) , |( ) | {
1268
- let dst = tmpdir. join ( cratepath. filename ( ) . unwrap ( ) ) ;
1269
- match fs:: copy ( & cratepath, & dst) {
1270
- Ok ( ..) => { }
1271
- Err ( e) => {
1272
- sess. err ( format ! ( "failed to copy {} to {}: {}" ,
1273
- cratepath. display( ) ,
1274
- dst. display( ) ,
1275
- e) ) ;
1276
- sess. abort_if_errors ( ) ;
1277
- }
1278
- }
1279
- let dst_str = dst. as_str ( ) . unwrap ( ) . to_owned ( ) ;
1280
- let mut archive = Archive :: open ( sess, dst) ;
1281
- archive. remove_file ( format ! ( "{}.o" , name) ) ;
1282
- let files = archive. files ( ) ;
1283
- if files. iter ( ) . any ( |s| s. ends_with ( ".o" ) ) {
1284
- args. push ( dst_str) ;
1309
+ Some ( crates. move_iter ( ) . map ( |( a, b) | ( a, b. unwrap ( ) ) ) . collect ( ) )
1310
+ } else {
1311
+ None
1312
+ }
1313
+ }
1314
+
1315
+ // Adds the static "rlib" versions of all crates to the command line.
1316
+ fn add_static_crates ( args : & mut ~[ ~str ] , sess : Session , tmpdir : & Path ,
1317
+ crates : ~[ ( ast:: CrateNum , Path ) ] ) {
1318
+ for ( cnum, cratepath) in crates. move_iter ( ) {
1319
+ // When performing LTO on an executable output, all of the
1320
+ // bytecode from the upstream libraries has already been
1321
+ // included in our object file output. We need to modify all of
1322
+ // the upstream archives to remove their corresponding object
1323
+ // file to make sure we don't pull the same code in twice.
1324
+ //
1325
+ // We must continue to link to the upstream archives to be sure
1326
+ // to pull in native static dependencies. As the final caveat,
1327
+ // on linux it is apparently illegal to link to a blank archive,
1328
+ // so if an archive no longer has any object files in it after
1329
+ // we remove `lib.o`, then don't link against it at all.
1330
+ //
1331
+ // If we're not doing LTO, then our job is simply to just link
1332
+ // against the archive.
1333
+ if sess. lto ( ) {
1334
+ let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1335
+ time ( sess. time_passes ( ) , format ! ( "altering {}.rlib" , name) ,
1336
+ ( ) , |( ) | {
1337
+ let dst = tmpdir. join ( cratepath. filename ( ) . unwrap ( ) ) ;
1338
+ match fs:: copy ( & cratepath, & dst) {
1339
+ Ok ( ..) => { }
1340
+ Err ( e) => {
1341
+ sess. err ( format ! ( "failed to copy {} to {}: {}" ,
1342
+ cratepath. display( ) ,
1343
+ dst. display( ) ,
1344
+ e) ) ;
1345
+ sess. abort_if_errors ( ) ;
1285
1346
}
1286
- } ) ;
1287
- } else {
1288
- args. push ( cratepath. as_str ( ) . unwrap ( ) . to_owned ( ) ) ;
1289
- }
1347
+ }
1348
+ let dst_str = dst. as_str ( ) . unwrap ( ) . to_owned ( ) ;
1349
+ let mut archive = Archive :: open ( sess, dst) ;
1350
+ archive. remove_file ( format ! ( "{}.o" , name) ) ;
1351
+ let files = archive. files ( ) ;
1352
+ if files. iter ( ) . any ( |s| s. ends_with ( ".o" ) ) {
1353
+ args. push ( dst_str) ;
1354
+ }
1355
+ } ) ;
1356
+ } else {
1357
+ args. push ( cratepath. as_str ( ) . unwrap ( ) . to_owned ( ) ) ;
1290
1358
}
1291
- return ;
1292
1359
}
1293
1360
}
1294
1361
1295
- // If we're performing LTO, then it should have been previously required
1296
- // that all upstream rust dependencies were available in an rlib format.
1297
- assert ! ( !sess. lto( ) ) ;
1298
-
1299
- // This is a fallback of three different cases of linking:
1300
- //
1301
- // * When creating a dynamic library, all inputs are required to be dynamic
1302
- // as well
1303
- // * If an executable is created with a preference on dynamic linking, then
1304
- // this case is the fallback
1305
- // * If an executable is being created, and one of the inputs is missing as
1306
- // a static library, then this is the fallback case.
1307
- let crates = cstore. get_used_crates ( cstore:: RequireDynamic ) ;
1308
- for & ( cnum, ref path) in crates. iter ( ) {
1309
- let cratepath = match * path {
1310
- Some ( ref p) => p. clone ( ) ,
1311
- None => {
1312
- sess. err ( format ! ( "could not find dynamic library for: `{}`" ,
1313
- sess. cstore. get_crate_data( cnum) . name) ) ;
1314
- return
1315
- }
1316
- } ;
1317
- // Just need to tell the linker about where the library lives and what
1318
- // its name is
1319
- let dir = cratepath. dirname_str ( ) . unwrap ( ) ;
1320
- if !dir. is_empty ( ) { args. push ( "-L" + dir) ; }
1321
- let libarg = unlib ( sess. targ_cfg , cratepath. filestem_str ( ) . unwrap ( ) ) ;
1322
- args. push ( "-l" + libarg) ;
1362
+ // Same thing as above, but for dynamic crates instead of static crates.
1363
+ fn add_dynamic_crates ( args : & mut ~[ ~str ] , sess : Session ,
1364
+ crates : ~[ ( ast:: CrateNum , Path ) ] ) {
1365
+ // If we're performing LTO, then it should have been previously required
1366
+ // that all upstream rust dependencies were available in an rlib format.
1367
+ assert ! ( !sess. lto( ) ) ;
1368
+
1369
+ for ( _, cratepath) in crates. move_iter ( ) {
1370
+ // Just need to tell the linker about where the library lives and
1371
+ // what its name is
1372
+ let dir = cratepath. dirname_str ( ) . unwrap ( ) ;
1373
+ if !dir. is_empty ( ) { args. push ( "-L" + dir) ; }
1374
+ let libarg = unlib ( sess. targ_cfg , cratepath. filestem_str ( ) . unwrap ( ) ) ;
1375
+ args. push ( "-l" + libarg) ;
1376
+ }
1323
1377
}
1324
1378
}
1325
1379
0 commit comments