@@ -884,10 +884,10 @@ fn link_binary_output(sess: &Session,
884
884
link_staticlib ( sess, & obj_filename, & out_filename) ;
885
885
}
886
886
session:: CrateTypeExecutable => {
887
- link_natively ( sess, false , & obj_filename, & out_filename) ;
887
+ link_natively ( sess, trans , false , & obj_filename, & out_filename) ;
888
888
}
889
889
session:: CrateTypeDylib => {
890
- link_natively ( sess, true , & obj_filename, & out_filename) ;
890
+ link_natively ( sess, trans , true , & obj_filename, & out_filename) ;
891
891
}
892
892
}
893
893
@@ -1037,13 +1037,13 @@ fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) {
1037
1037
//
1038
1038
// This will invoke the system linker/cc to create the resulting file. This
1039
1039
// links to all upstream files as well.
1040
- fn link_natively ( sess : & Session , dylib : bool , obj_filename : & Path ,
1041
- out_filename : & Path ) {
1040
+ fn link_natively ( sess : & Session , trans : & CrateTranslation , dylib : bool ,
1041
+ obj_filename : & Path , out_filename : & Path ) {
1042
1042
let tmpdir = TempDir :: new ( "rustc" ) . expect ( "needs a temp dir" ) ;
1043
1043
// The invocations of cc share some flags across platforms
1044
1044
let cc_prog = get_cc_prog ( sess) ;
1045
1045
let mut cc_args = sess. targ_cfg . target_strs . cc_args . clone ( ) ;
1046
- cc_args. push_all_move ( link_args ( sess, dylib, tmpdir. path ( ) ,
1046
+ cc_args. push_all_move ( link_args ( sess, dylib, tmpdir. path ( ) , trans ,
1047
1047
obj_filename, out_filename) ) ;
1048
1048
if ( sess. opts . debugging_opts & session:: PRINT_LINK_ARGS ) != 0 {
1049
1049
println ! ( "{} link args: '{}'" , cc_prog, cc_args. connect( "' '" ) ) ;
@@ -1092,6 +1092,7 @@ fn link_natively(sess: &Session, dylib: bool, obj_filename: &Path,
1092
1092
fn link_args ( sess : & Session ,
1093
1093
dylib : bool ,
1094
1094
tmpdir : & Path ,
1095
+ trans : & CrateTranslation ,
1095
1096
obj_filename : & Path ,
1096
1097
out_filename : & Path ) -> Vec < ~str > {
1097
1098
@@ -1251,7 +1252,7 @@ fn link_args(sess: &Session,
1251
1252
// this kind of behavior is pretty platform specific and generally not
1252
1253
// recommended anyway, so I don't think we're shooting ourself in the foot
1253
1254
// much with that.
1254
- add_upstream_rust_crates ( & mut args, sess, dylib, tmpdir) ;
1255
+ add_upstream_rust_crates ( & mut args, sess, dylib, tmpdir, trans ) ;
1255
1256
add_local_native_libraries ( & mut args, sess) ;
1256
1257
add_upstream_native_libraries ( & mut args, sess) ;
1257
1258
@@ -1361,73 +1362,44 @@ fn add_local_native_libraries(args: &mut Vec<~str>, sess: &Session) {
1361
1362
// dependencies will be linked when producing the final output (instead of
1362
1363
// the intermediate rlib version)
1363
1364
fn add_upstream_rust_crates ( args : & mut Vec < ~str > , sess : & Session ,
1364
- dylib : bool , tmpdir : & Path ) {
1365
-
1366
- // As a limitation of the current implementation, we require that everything
1367
- // must be static or everything must be dynamic. The reasons for this are a
1368
- // little subtle, but as with staticlibs and rlibs, the goal is to prevent
1369
- // duplicate copies of the same library showing up. For example, a static
1370
- // immediate dependency might show up as an upstream dynamic dependency and
1371
- // we currently have no way of knowing that. We know that all dynamic
1372
- // libraries require dynamic dependencies (see above), so it's satisfactory
1373
- // to include either all static libraries or all dynamic libraries.
1365
+ dylib : bool , tmpdir : & Path ,
1366
+ trans : & CrateTranslation ) {
1367
+ // All of the heavy lifting has previously been accomplished by the
1368
+ // dependency_format module of the compiler. This is just crawling the
1369
+ // output of that module, adding crates as necessary.
1374
1370
//
1375
- // With this limitation, we expose a compiler default linkage type and an
1376
- // option to reverse that preference. The current behavior looks like:
1377
- //
1378
- // * If a dylib is being created, upstream dependencies must be dylibs
1379
- // * If nothing else is specified, static linking is preferred
1380
- // * If the -C prefer-dynamic flag is given, dynamic linking is preferred
1381
- // * If one form of linking fails, the second is also attempted
1382
- // * If both forms fail, then we emit an error message
1383
-
1384
- let dynamic = get_deps ( & sess. cstore , cstore:: RequireDynamic ) ;
1385
- let statik = get_deps ( & sess. cstore , cstore:: RequireStatic ) ;
1386
- match ( dynamic, statik, sess. opts . cg . prefer_dynamic , dylib) {
1387
- ( _, Some ( deps) , false , false ) => {
1388
- add_static_crates ( args, sess, tmpdir, deps)
1389
- }
1390
-
1391
- ( None , Some ( deps) , true , false ) => {
1392
- // If you opted in to dynamic linking and we decided to emit a
1393
- // static output, you should probably be notified of such an event!
1394
- sess. warn ( "dynamic linking was preferred, but dependencies \
1395
- could not all be found in a dylib format.") ;
1396
- sess. warn ( "linking statically instead, using rlibs" ) ;
1397
- add_static_crates ( args, sess, tmpdir, deps)
1398
- }
1371
+ // Linking to a rlib involves just passing it to the linker (the linker
1372
+ // will slurp up the object files inside), and linking to a dynamic library
1373
+ // involves just passing the right -l flag.
1399
1374
1400
- ( Some ( deps) , _, _, _) => add_dynamic_crates ( args, sess, deps) ,
1375
+ let data = if dylib {
1376
+ trans. crate_formats . get ( & session:: CrateTypeDylib )
1377
+ } else {
1378
+ trans. crate_formats . get ( & session:: CrateTypeExecutable )
1379
+ } ;
1401
1380
1402
- ( None , _, _, true ) => {
1403
- sess. err ( "dylib output requested, but some depenencies could not \
1404
- be found in the dylib format") ;
1405
- let deps = sess. cstore . get_used_crates ( cstore:: RequireDynamic ) ;
1406
- for ( cnum, path) in deps. move_iter ( ) {
1407
- if path. is_some ( ) { continue }
1408
- let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1409
- sess. note ( format ! ( "dylib not found: {}" , name) ) ;
1381
+ // Invoke get_used_crates to ensure that we get a topological sorting of
1382
+ // crates.
1383
+ let deps = sess. cstore . get_used_crates ( cstore:: RequireDynamic ) ;
1384
+
1385
+ for & ( cnum, _) in deps. iter ( ) {
1386
+ // We may not pass all crates through to the linker. Some crates may
1387
+ // appear statically in an existing dylib, meaning we'll pick up all the
1388
+ // symbols from the dylib.
1389
+ let kind = match * data. get ( cnum as uint - 1 ) {
1390
+ Some ( t) => t,
1391
+ None => continue
1392
+ } ;
1393
+ let src = sess. cstore . get_used_crate_source ( cnum) . unwrap ( ) ;
1394
+ match kind {
1395
+ cstore:: RequireDynamic => {
1396
+ add_dynamic_crate ( args, sess, src. dylib . unwrap ( ) )
1410
1397
}
1411
- }
1412
-
1413
- ( None , None , pref, false ) => {
1414
- let ( pref, name) = if pref {
1415
- sess. err ( "dynamic linking is preferred, but dependencies were \
1416
- not found in either dylib or rlib format") ;
1417
- ( cstore:: RequireDynamic , "dylib" )
1418
- } else {
1419
- sess. err ( "dependencies were not all found in either dylib or \
1420
- rlib format") ;
1421
- ( cstore:: RequireStatic , "rlib" )
1422
- } ;
1423
- sess. note ( format ! ( "dependencies not found in the `{}` format" ,
1424
- name) ) ;
1425
- for ( cnum, path) in sess. cstore . get_used_crates ( pref) . move_iter ( ) {
1426
- if path. is_some ( ) { continue }
1427
- let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1428
- sess. note ( name) ;
1398
+ cstore:: RequireStatic => {
1399
+ add_static_crate ( args, sess, tmpdir, cnum, src. rlib . unwrap ( ) )
1429
1400
}
1430
1401
}
1402
+
1431
1403
}
1432
1404
1433
1405
// Converts a library file-stem into a cc -l argument
@@ -1439,82 +1411,64 @@ fn add_upstream_rust_crates(args: &mut Vec<~str>, sess: &Session,
1439
1411
}
1440
1412
}
1441
1413
1442
- // Attempts to find all dependencies with a certain linkage preference,
1443
- // returning `None` if not all libraries could be found with that
1444
- // preference.
1445
- fn get_deps ( cstore : & cstore:: CStore , preference : cstore:: LinkagePreference )
1446
- -> Option < Vec < ( ast:: CrateNum , Path ) > >
1447
- {
1448
- let crates = cstore. get_used_crates ( preference) ;
1449
- if crates. iter ( ) . all ( |& ( _, ref p) | p. is_some ( ) ) {
1450
- Some ( crates. move_iter ( ) . map ( |( a, b) | ( a, b. unwrap ( ) ) ) . collect ( ) )
1451
- } else {
1452
- None
1453
- }
1454
- }
1455
-
1456
1414
// Adds the static "rlib" versions of all crates to the command line.
1457
- fn add_static_crates ( args : & mut Vec < ~str > , sess : & Session , tmpdir : & Path ,
1458
- crates : Vec < ( ast:: CrateNum , Path ) > ) {
1459
- for ( cnum, cratepath) in crates. move_iter ( ) {
1460
- // When performing LTO on an executable output, all of the
1461
- // bytecode from the upstream libraries has already been
1462
- // included in our object file output. We need to modify all of
1463
- // the upstream archives to remove their corresponding object
1464
- // file to make sure we don't pull the same code in twice.
1465
- //
1466
- // We must continue to link to the upstream archives to be sure
1467
- // to pull in native static dependencies. As the final caveat,
1468
- // on linux it is apparently illegal to link to a blank archive,
1469
- // so if an archive no longer has any object files in it after
1470
- // we remove `lib.o`, then don't link against it at all.
1471
- //
1472
- // If we're not doing LTO, then our job is simply to just link
1473
- // against the archive.
1474
- if sess. lto ( ) {
1475
- let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1476
- time ( sess. time_passes ( ) , format ! ( "altering {}.rlib" , name) ,
1477
- ( ) , |( ) | {
1478
- let dst = tmpdir. join ( cratepath. filename ( ) . unwrap ( ) ) ;
1479
- match fs:: copy ( & cratepath, & dst) {
1480
- Ok ( ..) => { }
1481
- Err ( e) => {
1482
- sess. err ( format ! ( "failed to copy {} to {}: {}" ,
1483
- cratepath. display( ) ,
1484
- dst. display( ) ,
1485
- e) ) ;
1486
- sess. abort_if_errors ( ) ;
1487
- }
1488
- }
1489
- let dst_str = dst. as_str ( ) . unwrap ( ) . to_owned ( ) ;
1490
- let mut archive = Archive :: open ( sess, dst) ;
1491
- archive. remove_file ( format ! ( "{}.o" , name) ) ;
1492
- let files = archive. files ( ) ;
1493
- if files. iter ( ) . any ( |s| s. ends_with ( ".o" ) ) {
1494
- args. push ( dst_str) ;
1415
+ fn add_static_crate ( args : & mut Vec < ~str > , sess : & Session , tmpdir : & Path ,
1416
+ cnum : ast:: CrateNum , cratepath : Path ) {
1417
+ // When performing LTO on an executable output, all of the
1418
+ // bytecode from the upstream libraries has already been
1419
+ // included in our object file output. We need to modify all of
1420
+ // the upstream archives to remove their corresponding object
1421
+ // file to make sure we don't pull the same code in twice.
1422
+ //
1423
+ // We must continue to link to the upstream archives to be sure
1424
+ // to pull in native static dependencies. As the final caveat,
1425
+ // on linux it is apparently illegal to link to a blank archive,
1426
+ // so if an archive no longer has any object files in it after
1427
+ // we remove `lib.o`, then don't link against it at all.
1428
+ //
1429
+ // If we're not doing LTO, then our job is simply to just link
1430
+ // against the archive.
1431
+ if sess. lto ( ) {
1432
+ let name = sess. cstore . get_crate_data ( cnum) . name . clone ( ) ;
1433
+ time ( sess. time_passes ( ) , format ! ( "altering {}.rlib" , name) ,
1434
+ ( ) , |( ) | {
1435
+ let dst = tmpdir. join ( cratepath. filename ( ) . unwrap ( ) ) ;
1436
+ match fs:: copy ( & cratepath, & dst) {
1437
+ Ok ( ..) => { }
1438
+ Err ( e) => {
1439
+ sess. err ( format ! ( "failed to copy {} to {}: {}" ,
1440
+ cratepath. display( ) ,
1441
+ dst. display( ) ,
1442
+ e) ) ;
1443
+ sess. abort_if_errors ( ) ;
1495
1444
}
1496
- } ) ;
1497
- } else {
1498
- args. push ( cratepath. as_str ( ) . unwrap ( ) . to_owned ( ) ) ;
1499
- }
1445
+ }
1446
+ let dst_str = dst. as_str ( ) . unwrap ( ) . to_owned ( ) ;
1447
+ let mut archive = Archive :: open ( sess, dst) ;
1448
+ archive. remove_file ( format ! ( "{}.o" , name) ) ;
1449
+ let files = archive. files ( ) ;
1450
+ if files. iter ( ) . any ( |s| s. ends_with ( ".o" ) ) {
1451
+ args. push ( dst_str) ;
1452
+ }
1453
+ } ) ;
1454
+ } else {
1455
+ args. push ( cratepath. as_str ( ) . unwrap ( ) . to_owned ( ) ) ;
1500
1456
}
1501
1457
}
1502
1458
1503
1459
// Same thing as above, but for dynamic crates instead of static crates.
1504
- fn add_dynamic_crates ( args : & mut Vec < ~str > , sess : & Session ,
1505
- crates : Vec < ( ast :: CrateNum , Path ) > ) {
1460
+ fn add_dynamic_crate ( args : & mut Vec < ~str > , sess : & Session ,
1461
+ cratepath : Path ) {
1506
1462
// If we're performing LTO, then it should have been previously required
1507
1463
// that all upstream rust dependencies were available in an rlib format.
1508
1464
assert ! ( !sess. lto( ) ) ;
1509
1465
1510
- for ( _, cratepath) in crates. move_iter ( ) {
1511
- // Just need to tell the linker about where the library lives and
1512
- // what its name is
1513
- let dir = cratepath. dirname_str ( ) . unwrap ( ) ;
1514
- if !dir. is_empty ( ) { args. push ( "-L" + dir) ; }
1515
- let libarg = unlib ( & sess. targ_cfg , cratepath. filestem_str ( ) . unwrap ( ) ) ;
1516
- args. push ( "-l" + libarg) ;
1517
- }
1466
+ // Just need to tell the linker about where the library lives and
1467
+ // what its name is
1468
+ let dir = cratepath. dirname_str ( ) . unwrap ( ) ;
1469
+ if !dir. is_empty ( ) { args. push ( "-L" + dir) ; }
1470
+ let libarg = unlib ( & sess. targ_cfg , cratepath. filestem_str ( ) . unwrap ( ) ) ;
1471
+ args. push ( "-l" + libarg) ;
1518
1472
}
1519
1473
}
1520
1474
0 commit comments