@@ -884,10 +884,10 @@ fn link_binary_output(sess: &Session,
884884 link_staticlib ( sess, & obj_filename, & out_filename) ;
885885 }
886886 session:: CrateTypeExecutable => {
887- link_natively ( sess, false , & obj_filename, & out_filename) ;
887+ link_natively ( sess, trans , false , & obj_filename, & out_filename) ;
888888 }
889889 session:: CrateTypeDylib => {
890- link_natively ( sess, true , & obj_filename, & out_filename) ;
890+ link_natively ( sess, trans , true , & obj_filename, & out_filename) ;
891891 }
892892 }
893893
@@ -1037,13 +1037,13 @@ fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) {
10371037//
10381038// This will invoke the system linker/cc to create the resulting file. This
10391039// 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 ) {
10421042 let tmpdir = TempDir :: new ( "rustc" ) . expect ( "needs a temp dir" ) ;
10431043 // The invocations of cc share some flags across platforms
10441044 let cc_prog = get_cc_prog ( sess) ;
10451045 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 ,
10471047 obj_filename, out_filename) ) ;
10481048 if ( sess. opts . debugging_opts & session:: PRINT_LINK_ARGS ) != 0 {
10491049 println ! ( "{} link args: '{}'" , cc_prog, cc_args. connect( "' '" ) ) ;
@@ -1092,6 +1092,7 @@ fn link_natively(sess: &Session, dylib: bool, obj_filename: &Path,
10921092fn link_args ( sess : & Session ,
10931093 dylib : bool ,
10941094 tmpdir : & Path ,
1095+ trans : & CrateTranslation ,
10951096 obj_filename : & Path ,
10961097 out_filename : & Path ) -> Vec < ~str > {
10971098
@@ -1251,7 +1252,7 @@ fn link_args(sess: &Session,
12511252 // this kind of behavior is pretty platform specific and generally not
12521253 // recommended anyway, so I don't think we're shooting ourself in the foot
12531254 // much with that.
1254- add_upstream_rust_crates ( & mut args, sess, dylib, tmpdir) ;
1255+ add_upstream_rust_crates ( & mut args, sess, dylib, tmpdir, trans ) ;
12551256 add_local_native_libraries ( & mut args, sess) ;
12561257 add_upstream_native_libraries ( & mut args, sess) ;
12571258
@@ -1361,73 +1362,44 @@ fn add_local_native_libraries(args: &mut Vec<~str>, sess: &Session) {
13611362// dependencies will be linked when producing the final output (instead of
13621363// the intermediate rlib version)
13631364fn 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.
13741370 //
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.
13991374
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+ } ;
14011380
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 ( ) )
14101397 }
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 ( ) )
14291400 }
14301401 }
1402+
14311403 }
14321404
14331405 // 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,
14391411 }
14401412 }
14411413
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-
14561414 // 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 ( ) ;
14951444 }
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 ( ) ) ;
15001456 }
15011457 }
15021458
15031459 // 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 ) {
15061462 // If we're performing LTO, then it should have been previously required
15071463 // that all upstream rust dependencies were available in an rlib format.
15081464 assert ! ( !sess. lto( ) ) ;
15091465
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) ;
15181472 }
15191473}
15201474
0 commit comments