Skip to content

Commit 34c6bf9

Browse files
committed
---
yaml --- r: 151354 b: refs/heads/try2 c: 897b96a h: refs/heads/master v: v3
1 parent aaab906 commit 34c6bf9

File tree

26 files changed

+614
-152
lines changed

26 files changed

+614
-152
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 2fc3b3a48fef92f9c38d936eed14453a640df0ec
8+
refs/heads/try2: 897b96a2e28778a5819907a74fc800508eadeffc
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/librustc/back/link.rs

Lines changed: 87 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -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,
10921092
fn 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)
13631364
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.
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

branches/try2/src/librustc/driver/driver.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use metadata::cstore::CStore;
2424
use metadata::creader::Loader;
2525
use metadata;
2626
use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
27+
use middle::dependency_format;
2728
use middle;
2829
use util::common::time;
2930
use util::ppaux;
@@ -382,7 +383,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
382383
ty_cx: ty_cx,
383384
exported_items: exported_items,
384385
public_items: public_items,
385-
reachable: reachable_map
386+
reachable: reachable_map,
386387
}
387388
}
388389

@@ -393,18 +394,22 @@ pub struct CrateTranslation {
393394
pub link: LinkMeta,
394395
pub metadata: Vec<u8>,
395396
pub reachable: Vec<~str>,
397+
pub crate_formats: dependency_format::Dependencies,
396398
}
397399

398400
/// Run the translation phase to LLVM, after which the AST and analysis can
399401
/// be discarded.
400402
pub fn phase_4_translate_to_llvm(krate: ast::Crate,
401403
analysis: CrateAnalysis,
402404
outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
403-
// Option dance to work around the lack of stack once closures.
404405
let time_passes = analysis.ty_cx.sess.time_passes();
405-
let mut analysis = Some(analysis);
406-
time(time_passes, "translation", krate, |krate|
407-
trans::base::trans_crate(krate, analysis.take_unwrap(), outputs))
406+
407+
time(time_passes, "resolving dependency formats", (), |_|
408+
dependency_format::calculate(&analysis.ty_cx));
409+
410+
// Option dance to work around the lack of stack once closures.
411+
time(time_passes, "translation", (krate, analysis), |(krate, analysis)|
412+
trans::base::trans_crate(krate, analysis, outputs))
408413
}
409414

410415
/// Run LLVM itself, producing a bitcode file, assembly file or object file

branches/try2/src/librustc/driver/session.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub enum DebugInfoLevel {
125125
pub struct Options {
126126
// The crate config requested for the session, which may be combined
127127
// with additional crate configurations during the compile process
128-
pub crate_types: Vec<CrateType> ,
128+
pub crate_types: Vec<CrateType>,
129129

130130
pub gc: bool,
131131
pub optimize: OptLevel,
@@ -166,7 +166,7 @@ pub enum EntryFnType {
166166
EntryNone,
167167
}
168168

169-
#[deriving(Eq, Ord, Clone, TotalOrd, TotalEq)]
169+
#[deriving(Eq, Ord, Clone, TotalOrd, TotalEq, Hash)]
170170
pub enum CrateType {
171171
CrateTypeExecutable,
172172
CrateTypeDylib,

branches/try2/src/librustc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ pub mod middle {
9393
pub mod cfg;
9494
pub mod dead;
9595
pub mod expr_use_visitor;
96+
pub mod dependency_format;
9697
}
9798

9899
pub mod front {

branches/try2/src/librustc/metadata/common.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ pub static tag_macro_def: uint = 0x8d;
203203

204204
pub static tag_crate_triple: uint = 0x66;
205205

206+
pub static tag_dylib_dependency_formats: uint = 0x67;
207+
206208
#[deriving(Clone, Show)]
207209
pub struct LinkMeta {
208210
pub crateid: CrateId,

branches/try2/src/librustc/metadata/csearch.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,11 @@ pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore,
284284
let cdata = cstore.get_crate_data(def_id.krate);
285285
decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.node)
286286
}
287+
288+
pub fn get_dylib_dependency_formats(cstore: &cstore::CStore,
289+
cnum: ast::CrateNum)
290+
-> Vec<(ast::CrateNum, cstore::LinkagePreference)>
291+
{
292+
let cdata = cstore.get_crate_data(cnum);
293+
decoder::get_dylib_dependency_formats(&*cdata)
294+
}

branches/try2/src/librustc/metadata/cstore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub struct crate_metadata {
4545
pub span: Span,
4646
}
4747

48-
#[deriving(Eq)]
48+
#[deriving(Show, Eq, Clone)]
4949
pub enum LinkagePreference {
5050
RequireDynamic,
5151
RequireStatic,

0 commit comments

Comments
 (0)