@@ -1220,6 +1220,74 @@ fn add_local_native_libraries(args: &mut ~[~str], sess: Session) {
12201220// the intermediate rlib version)
12211221fn add_upstream_rust_crates ( args : & mut ~[ ~str ] , sess : Session ,
12221222 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+
12231291 // Converts a library file-stem into a cc -l argument
12241292 fn unlib ( config : @session:: Config , stem : & str ) -> ~str {
12251293 if stem. starts_with ( "lib" ) &&
@@ -1230,96 +1298,82 @@ fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session,
12301298 }
12311299 }
12321300
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) ;
12461308 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 ( ) ;
12851346 }
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 ( ) ) ;
12901358 }
1291- return ;
12921359 }
12931360 }
12941361
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+ }
13231377 }
13241378}
13251379
0 commit comments