link_staticlib(sess, &obj_filename, &out_filename);
}
session::CrateTypeExecutable => {
- link_natively(sess, false, &obj_filename, &out_filename);
+ link_natively(sess, trans, false, &obj_filename, &out_filename);
}
session::CrateTypeDylib => {
- link_natively(sess, true, &obj_filename, &out_filename);
+ link_natively(sess, trans, true, &obj_filename, &out_filename);
}
}
//
// This will invoke the system linker/cc to create the resulting file. This
// links to all upstream files as well.
-fn link_natively(sess: &Session, dylib: bool, obj_filename: &Path,
- out_filename: &Path) {
+fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
+ obj_filename: &Path, out_filename: &Path) {
let tmpdir = TempDir::new("rustc").expect("needs a temp dir");
// The invocations of cc share some flags across platforms
let cc_prog = get_cc_prog(sess);
let mut cc_args = sess.targ_cfg.target_strs.cc_args.clone();
- cc_args.push_all_move(link_args(sess, dylib, tmpdir.path(),
+ cc_args.push_all_move(link_args(sess, dylib, tmpdir.path(), trans,
obj_filename, out_filename));
if (sess.opts.debugging_opts & session::PRINT_LINK_ARGS) != 0 {
println!("{} link args: '{}'", cc_prog, cc_args.connect("' '"));
fn link_args(sess: &Session,
dylib: bool,
tmpdir: &Path,
+ trans: &CrateTranslation,
obj_filename: &Path,
out_filename: &Path) -> Vec<~str> {
// this kind of behavior is pretty platform specific and generally not
// recommended anyway, so I don't think we're shooting ourself in the foot
// much with that.
- add_upstream_rust_crates(&mut args, sess, dylib, tmpdir);
+ add_upstream_rust_crates(&mut args, sess, dylib, tmpdir, trans);
add_local_native_libraries(&mut args, sess);
add_upstream_native_libraries(&mut args, sess);
// dependencies will be linked when producing the final output (instead of
// the intermediate rlib version)
fn add_upstream_rust_crates(args: &mut Vec<~str>, sess: &Session,
- dylib: bool, tmpdir: &Path) {
-
- // As a limitation of the current implementation, we require that everything
- // must be static or everything must be dynamic. The reasons for this are a
- // little subtle, but as with staticlibs and rlibs, the goal is to prevent
- // duplicate copies of the same library showing up. For example, a static
- // immediate dependency might show up as an upstream dynamic dependency and
- // we currently have no way of knowing that. We know that all dynamic
- // libraries require dynamic dependencies (see above), so it's satisfactory
- // to include either all static libraries or all dynamic libraries.
+ dylib: bool, tmpdir: &Path,
+ trans: &CrateTranslation) {
+ // All of the heavy lifting has previously been accomplished by the
+ // dependency_format module of the compiler. This is just crawling the
+ // output of that module, adding crates as necessary.
//
- // With this limitation, we expose a compiler default linkage type and an
- // option to reverse that preference. The current behavior looks like:
- //
- // * If a dylib is being created, upstream dependencies must be dylibs
- // * If nothing else is specified, static linking is preferred
- // * If the -C prefer-dynamic flag is given, dynamic linking is preferred
- // * If one form of linking fails, the second is also attempted
- // * If both forms fail, then we emit an error message
-
- let dynamic = get_deps(&sess.cstore, cstore::RequireDynamic);
- let statik = get_deps(&sess.cstore, cstore::RequireStatic);
- match (dynamic, statik, sess.opts.cg.prefer_dynamic, dylib) {
- (_, Some(deps), false, false) => {
- add_static_crates(args, sess, tmpdir, deps)
- }
-
- (None, Some(deps), true, false) => {
- // If you opted in to dynamic linking and we decided to emit a
- // static output, you should probably be notified of such an event!
- sess.warn("dynamic linking was preferred, but dependencies \
- could not all be found in a dylib format.");
- sess.warn("linking statically instead, using rlibs");
- add_static_crates(args, sess, tmpdir, deps)
- }
+ // Linking to a rlib involves just passing it to the linker (the linker
+ // will slurp up the object files inside), and linking to a dynamic library
+ // involves just passing the right -l flag.
- (Some(deps), _, _, _) => add_dynamic_crates(args, sess, deps),
+ let data = if dylib {
+ trans.crate_formats.get(&session::CrateTypeDylib)
+ } else {
+ trans.crate_formats.get(&session::CrateTypeExecutable)
+ };
- (None, _, _, true) => {
- sess.err("dylib output requested, but some depenencies could not \
- be found in the dylib format");
- let deps = sess.cstore.get_used_crates(cstore::RequireDynamic);
- for (cnum, path) in deps.move_iter() {
- if path.is_some() { continue }
- let name = sess.cstore.get_crate_data(cnum).name.clone();
- sess.note(format!("dylib not found: {}", name));
+ // Invoke get_used_crates to ensure that we get a topological sorting of
+ // crates.
+ let deps = sess.cstore.get_used_crates(cstore::RequireDynamic);
+
+ for &(cnum, _) in deps.iter() {
+ // We may not pass all crates through to the linker. Some crates may
+ // appear statically in an existing dylib, meaning we'll pick up all the
+ // symbols from the dylib.
+ let kind = match *data.get(cnum as uint - 1) {
+ Some(t) => t,
+ None => continue
+ };
+ let src = sess.cstore.get_used_crate_source(cnum).unwrap();
+ match kind {
+ cstore::RequireDynamic => {
+ add_dynamic_crate(args, sess, src.dylib.unwrap())
}
- }
-
- (None, None, pref, false) => {
- let (pref, name) = if pref {
- sess.err("dynamic linking is preferred, but dependencies were \
- not found in either dylib or rlib format");
- (cstore::RequireDynamic, "dylib")
- } else {
- sess.err("dependencies were not all found in either dylib or \
- rlib format");
- (cstore::RequireStatic, "rlib")
- };
- sess.note(format!("dependencies not found in the `{}` format",
- name));
- for (cnum, path) in sess.cstore.get_used_crates(pref).move_iter() {
- if path.is_some() { continue }
- let name = sess.cstore.get_crate_data(cnum).name.clone();
- sess.note(name);
+ cstore::RequireStatic => {
+ add_static_crate(args, sess, tmpdir, cnum, src.rlib.unwrap())
}
}
+
}
// Converts a library file-stem into a cc -l argument
}
}
- // Attempts to find all dependencies with a certain linkage preference,
- // returning `None` if not all libraries could be found with that
- // preference.
- fn get_deps(cstore: &cstore::CStore, preference: cstore::LinkagePreference)
- -> Option<Vec<(ast::CrateNum, Path)> >
- {
- let crates = cstore.get_used_crates(preference);
- if crates.iter().all(|&(_, ref p)| p.is_some()) {
- Some(crates.move_iter().map(|(a, b)| (a, b.unwrap())).collect())
- } else {
- None
- }
- }
-
// Adds the static "rlib" versions of all crates to the command line.
- fn add_static_crates(args: &mut Vec<~str>, sess: &Session, tmpdir: &Path,
- crates: Vec<(ast::CrateNum, Path)>) {
- for (cnum, cratepath) in crates.move_iter() {
- // When performing LTO on an executable output, all of the
- // bytecode from the upstream libraries has already been
- // included in our object file output. We need to modify all of
- // the upstream archives to remove their corresponding object
- // file to make sure we don't pull the same code in twice.
- //
- // We must continue to link to the upstream archives to be sure
- // to pull in native static dependencies. As the final caveat,
- // on linux it is apparently illegal to link to a blank archive,
- // so if an archive no longer has any object files in it after
- // we remove `lib.o`, then don't link against it at all.
- //
- // If we're not doing LTO, then our job is simply to just link
- // against the archive.
- if sess.lto() {
- let name = sess.cstore.get_crate_data(cnum).name.clone();
- time(sess.time_passes(), format!("altering {}.rlib", name),
- (), |()| {
- let dst = tmpdir.join(cratepath.filename().unwrap());
- match fs::copy(&cratepath, &dst) {
- Ok(..) => {}
- Err(e) => {
- sess.err(format!("failed to copy {} to {}: {}",
- cratepath.display(),
- dst.display(),
- e));
- sess.abort_if_errors();
- }
- }
- let dst_str = dst.as_str().unwrap().to_owned();
- let mut archive = Archive::open(sess, dst);
- archive.remove_file(format!("{}.o", name));
- let files = archive.files();
- if files.iter().any(|s| s.ends_with(".o")) {
- args.push(dst_str);
+ fn add_static_crate(args: &mut Vec<~str>, sess: &Session, tmpdir: &Path,
+ cnum: ast::CrateNum, cratepath: Path) {
+ // When performing LTO on an executable output, all of the
+ // bytecode from the upstream libraries has already been
+ // included in our object file output. We need to modify all of
+ // the upstream archives to remove their corresponding object
+ // file to make sure we don't pull the same code in twice.
+ //
+ // We must continue to link to the upstream archives to be sure
+ // to pull in native static dependencies. As the final caveat,
+ // on linux it is apparently illegal to link to a blank archive,
+ // so if an archive no longer has any object files in it after
+ // we remove `lib.o`, then don't link against it at all.
+ //
+ // If we're not doing LTO, then our job is simply to just link
+ // against the archive.
+ if sess.lto() {
+ let name = sess.cstore.get_crate_data(cnum).name.clone();
+ time(sess.time_passes(), format!("altering {}.rlib", name),
+ (), |()| {
+ let dst = tmpdir.join(cratepath.filename().unwrap());
+ match fs::copy(&cratepath, &dst) {
+ Ok(..) => {}
+ Err(e) => {
+ sess.err(format!("failed to copy {} to {}: {}",
+ cratepath.display(),
+ dst.display(),
+ e));
+ sess.abort_if_errors();
}
- });
- } else {
- args.push(cratepath.as_str().unwrap().to_owned());
- }
+ }
+ let dst_str = dst.as_str().unwrap().to_owned();
+ let mut archive = Archive::open(sess, dst);
+ archive.remove_file(format!("{}.o", name));
+ let files = archive.files();
+ if files.iter().any(|s| s.ends_with(".o")) {
+ args.push(dst_str);
+ }
+ });
+ } else {
+ args.push(cratepath.as_str().unwrap().to_owned());
}
}
// Same thing as above, but for dynamic crates instead of static crates.
- fn add_dynamic_crates(args: &mut Vec<~str>, sess: &Session,
- crates: Vec<(ast::CrateNum, Path)> ) {
+ fn add_dynamic_crate(args: &mut Vec<~str>, sess: &Session,
+ cratepath: Path) {
// If we're performing LTO, then it should have been previously required
// that all upstream rust dependencies were available in an rlib format.
assert!(!sess.lto());
- for (_, cratepath) in crates.move_iter() {
- // Just need to tell the linker about where the library lives and
- // what its name is
- let dir = cratepath.dirname_str().unwrap();
- if !dir.is_empty() { args.push("-L" + dir); }
- let libarg = unlib(&sess.targ_cfg, cratepath.filestem_str().unwrap());
- args.push("-l" + libarg);
- }
+ // Just need to tell the linker about where the library lives and
+ // what its name is
+ let dir = cratepath.dirname_str().unwrap();
+ if !dir.is_empty() { args.push("-L" + dir); }
+ let libarg = unlib(&sess.targ_cfg, cratepath.filestem_str().unwrap());
+ args.push("-l" + libarg);
}
}
use metadata::creader::Loader;
use metadata;
use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
+use middle::dependency_format;
use middle;
use util::common::time;
use util::ppaux;
ty_cx: ty_cx,
exported_items: exported_items,
public_items: public_items,
- reachable: reachable_map
+ reachable: reachable_map,
}
}
pub link: LinkMeta,
pub metadata: Vec<u8>,
pub reachable: Vec<~str>,
+ pub crate_formats: dependency_format::Dependencies,
}
/// Run the translation phase to LLVM, after which the AST and analysis can
pub fn phase_4_translate_to_llvm(krate: ast::Crate,
analysis: CrateAnalysis,
outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
- // Option dance to work around the lack of stack once closures.
let time_passes = analysis.ty_cx.sess.time_passes();
- let mut analysis = Some(analysis);
- time(time_passes, "translation", krate, |krate|
- trans::base::trans_crate(krate, analysis.take_unwrap(), outputs))
+
+ time(time_passes, "resolving dependency formats", (), |_|
+ dependency_format::calculate(&analysis.ty_cx));
+
+ // Option dance to work around the lack of stack once closures.
+ time(time_passes, "translation", (krate, analysis), |(krate, analysis)|
+ trans::base::trans_crate(krate, analysis, outputs))
}
/// Run LLVM itself, producing a bitcode file, assembly file or object file
pub struct Options {
// The crate config requested for the session, which may be combined
// with additional crate configurations during the compile process
- pub crate_types: Vec<CrateType> ,
+ pub crate_types: Vec<CrateType>,
pub gc: bool,
pub optimize: OptLevel,
EntryNone,
}
-#[deriving(Eq, Ord, Clone, TotalOrd, TotalEq)]
+#[deriving(Eq, Ord, Clone, TotalOrd, TotalEq, Hash)]
pub enum CrateType {
CrateTypeExecutable,
CrateTypeDylib,
pub mod cfg;
pub mod dead;
pub mod expr_use_visitor;
+ pub mod dependency_format;
}
pub mod front {
pub static tag_crate_triple: uint = 0x66;
+pub static tag_dylib_dependency_formats: uint = 0x67;
+
#[deriving(Clone, Show)]
pub struct LinkMeta {
pub crateid: CrateId,
let cdata = cstore.get_crate_data(def_id.krate);
decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.node)
}
+
+pub fn get_dylib_dependency_formats(cstore: &cstore::CStore,
+ cnum: ast::CrateNum)
+ -> Vec<(ast::CrateNum, cstore::LinkagePreference)>
+{
+ let cdata = cstore.get_crate_data(cnum);
+ decoder::get_dylib_dependency_formats(&*cdata)
+}
pub span: Span,
}
-#[deriving(Eq)]
+#[deriving(Show, Eq, Clone)]
pub enum LinkagePreference {
RequireDynamic,
RequireStatic,
});
result
}
+
+pub fn get_dylib_dependency_formats(cdata: Cmd)
+ -> Vec<(ast::CrateNum, cstore::LinkagePreference)>
+{
+ let formats = reader::get_doc(reader::Doc(cdata.data()),
+ tag_dylib_dependency_formats);
+ let mut result = Vec::new();
+
+ debug!("found dylib deps: {}", formats.as_str_slice());
+ for spec in formats.as_str_slice().split(',') {
+ if spec.len() == 0 { continue }
+ let cnum = spec.split(':').nth(0).unwrap();
+ let link = spec.split(':').nth(1).unwrap();
+ let cnum = from_str(cnum).unwrap();
+ let cnum = match cdata.cnum_map.find(&cnum) {
+ Some(&n) => n,
+ None => fail!("didn't find a crate in the cnum_map")
+ };
+ result.push((cnum, if link == "d" {
+ cstore::RequireDynamic
+ } else {
+ cstore::RequireStatic
+ }));
+ }
+ return result;
+}
#![allow(non_camel_case_types)]
use back::svh::Svh;
+use driver::session;
use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
ebml_w.end_tag();
}
+fn encode_dylib_dependency_formats(ebml_w: &mut Encoder, ecx: &EncodeContext) {
+ ebml_w.start_tag(tag_dylib_dependency_formats);
+ match ecx.tcx.dependency_formats.borrow().find(&session::CrateTypeDylib) {
+ Some(arr) => {
+ let s = arr.iter().enumerate().filter_map(|(i, slot)| {
+ slot.map(|kind| format!("{}:{}", i + 1, match kind {
+ cstore::RequireDynamic => "d",
+ cstore::RequireStatic => "s",
+ }))
+ }).collect::<Vec<~str>>();
+ ebml_w.writer.write(s.connect(",").as_bytes());
+ }
+ None => {}
+ }
+ ebml_w.end_tag();
+}
+
// NB: Increment this as you change the metadata encoding version.
pub static metadata_encoding_version : &'static [u8] =
&[0x72, //'r' as u8,
encode_crate_id(&mut ebml_w, &ecx.link_meta.crateid);
encode_crate_triple(&mut ebml_w, tcx.sess.targ_cfg.target_strs.target_triple);
encode_hash(&mut ebml_w, &ecx.link_meta.crate_hash);
+ encode_dylib_dependency_formats(&mut ebml_w, &ecx);
let mut i = ebml_w.writer.tell().unwrap();
let crate_attrs = synthesize_crate_attrs(&ecx, krate);
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Resolution of mixing rlibs and dylibs
+//!
+//! When producing a final artifact, such as a dynamic library, the compiler has
+//! a choice between linking an rlib or linking a dylib of all upstream
+//! dependencies. The linking phase must guarantee, however, that a library only
+//! show up once in the object file. For example, it is illegal for library A to
+//! be statically linked to B and C in separate dylibs, and then link B and C
+//! into a crate D (because library A appears twice).
+//!
+//! The job of this module is to calculate what format each upstream crate
+//! should be used when linking each output type requested in this session. This
+//! generally follows this set of rules:
+//!
+//! 1. Each library must appear exactly once in the output.
+//! 2. Each rlib contains only one library (it's just an object file)
+//! 3. Each dylib can contain more than one library (due to static linking),
+//! and can also bring in many dynamic dependencies.
+//!
+//! With these constraints in mind, it's generally a very difficult problem to
+//! find a solution that's not "all rlibs" or "all dylibs". I have suspicions
+//! that NP-ness may come into the picture here...
+//!
+//! The current selection algorithm below looks mostly similar to:
+//!
+//! 1. If static linking is required, then require all upstream dependencies
+//! to be available as rlibs. If not, generate an error.
+//! 2. If static linking is requested (generating an executable), then
+//! attempt to use all upstream dependencies as rlibs. If any are not
+//! found, bail out and continue to step 3.
+//! 3. Static linking has failed, at least one library must be dynamically
+//! linked. Apply a heuristic by greedily maximizing the number of
+//! dynamically linked libraries.
+//! 4. Each upstream dependency available as a dynamic library is
+//! registered. The dependencies all propagate, adding to a map. It is
+//! possible for a dylib to add a static library as a dependency, but it
+//! is illegal for two dylibs to add the same static library as a
+//! dependency. The same dylib can be added twice. Additionally, it is
+//! illegal to add a static dependency when it was previously found as a
+//! dylib (and vice versa)
+//! 5. After all dynamic dependencies have been traversed, re-traverse the
+//! remaining dependencies and add them statically (if they haven't been
+//! added already).
+//!
+//! While not perfect, this algorithm should help support use-cases such as leaf
+//! dependencies being static while the larger tree of inner dependencies are
+//! all dynamic. This isn't currently very well battle tested, so it will likely
+//! fall short in some use cases.
+//!
+//! Currently, there is no way to specify the preference of linkage with a
+//! particular library (other than a global dynamic/static switch).
+//! Additionally, the algorithm is geared towards finding *any* solution rather
+//! than finding a number of solutions (there are normally quite a few).
+
+use collections::HashMap;
+use syntax::ast;
+
+use driver::session;
+use metadata::cstore;
+use metadata::csearch;
+use middle::ty;
+
+/// A list of dependencies for a certain crate type.
+///
+/// The length of this vector is the same as the number of external crates used.
+/// The value is None if the crate does not need to be linked (it was found
+/// statically in another dylib), or Some(kind) if it needs to be linked as
+/// `kind` (either static or dynamic).
+pub type DependencyList = Vec<Option<cstore::LinkagePreference>>;
+
+/// A mapping of all required dependencies for a particular flavor of output.
+///
+/// This is local to the tcx, and is generally relevant to one session.
+pub type Dependencies = HashMap<session::CrateType, DependencyList>;
+
+pub fn calculate(tcx: &ty::ctxt) {
+ let mut fmts = tcx.dependency_formats.borrow_mut();
+ for &ty in tcx.sess.crate_types.borrow().iter() {
+ fmts.insert(ty, calculate_type(&tcx.sess, ty));
+ }
+ tcx.sess.abort_if_errors();
+}
+
+fn calculate_type(sess: &session::Session,
+ ty: session::CrateType) -> DependencyList {
+ match ty {
+ // If the global prefer_dynamic switch is turned off, first attempt
+ // static linkage (this can fail).
+ session::CrateTypeExecutable if !sess.opts.cg.prefer_dynamic => {
+ match attempt_static(sess) {
+ Some(v) => return v,
+ None => {}
+ }
+ }
+
+ // No linkage happens with rlibs, we just needed the metadata (which we
+ // got long ago), so don't bother with anything.
+ session::CrateTypeRlib => return Vec::new(),
+
+ // Staticlibs must have all static dependencies. If any fail to be
+ // found, we generate some nice pretty errors.
+ session::CrateTypeStaticlib => {
+ match attempt_static(sess) {
+ Some(v) => return v,
+ None => {}
+ }
+ sess.cstore.iter_crate_data(|cnum, data| {
+ let src = sess.cstore.get_used_crate_source(cnum).unwrap();
+ if src.rlib.is_some() { return }
+ sess.err(format!("dependency `{}` not found in rlib format",
+ data.name));
+ });
+ return Vec::new();
+ }
+
+ // Everything else falls through below
+ session::CrateTypeExecutable | session::CrateTypeDylib => {},
+ }
+
+ let mut formats = HashMap::new();
+
+ // Sweep all crates for found dylibs. Add all dylibs, as well as their
+ // dependencies, ensuring there are no conflicts. The only valid case for a
+ // dependency to be relied upon twice is for both cases to rely on a dylib.
+ sess.cstore.iter_crate_data(|cnum, data| {
+ let src = sess.cstore.get_used_crate_source(cnum).unwrap();
+ if src.dylib.is_some() {
+ add_library(sess, cnum, cstore::RequireDynamic, &mut formats);
+ debug!("adding dylib: {}", data.name);
+ let deps = csearch::get_dylib_dependency_formats(&sess.cstore, cnum);
+ for &(depnum, style) in deps.iter() {
+ add_library(sess, depnum, style, &mut formats);
+ debug!("adding {}: {}", style,
+ sess.cstore.get_crate_data(depnum).name.clone());
+ }
+ }
+ });
+
+ // Collect what we've got so far in the return vector.
+ let mut ret = range(1, sess.cstore.next_crate_num()).map(|i| {
+ match formats.find(&i).map(|v| *v) {
+ v @ Some(cstore::RequireDynamic) => v,
+ _ => None,
+ }
+ }).collect::<Vec<_>>();
+
+ // Run through the dependency list again, and add any missing libraries as
+ // static libraries.
+ sess.cstore.iter_crate_data(|cnum, data| {
+ let src = sess.cstore.get_used_crate_source(cnum).unwrap();
+ if src.dylib.is_none() && !formats.contains_key(&cnum) {
+ assert!(src.rlib.is_some());
+ add_library(sess, cnum, cstore::RequireStatic, &mut formats);
+ *ret.get_mut(cnum as uint - 1) = Some(cstore::RequireStatic);
+ debug!("adding staticlib: {}", data.name);
+ }
+ });
+
+ // When dylib B links to dylib A, then when using B we must also link to A.
+ // It could be the case, however, that the rlib for A is present (hence we
+ // found metadata), but the dylib for A has since been removed.
+ //
+ // For situations like this, we perform one last pass over the dependencies,
+ // making sure that everything is available in the requested format.
+ for (cnum, kind) in ret.iter().enumerate() {
+ let cnum = cnum as ast::CrateNum;
+ let src = sess.cstore.get_used_crate_source(cnum + 1).unwrap();
+ match *kind {
+ None => continue,
+ Some(cstore::RequireStatic) if src.rlib.is_some() => continue,
+ Some(cstore::RequireDynamic) if src.dylib.is_some() => continue,
+ Some(kind) => {
+ let data = sess.cstore.get_crate_data(cnum + 1);
+ sess.err(format!("crate `{}` required to be available in {}, \
+ but it was not available in this form",
+ data.name,
+ match kind {
+ cstore::RequireStatic => "rlib",
+ cstore::RequireDynamic => "dylib",
+ }));
+ }
+ }
+ }
+
+ return ret;
+}
+
+fn add_library(sess: &session::Session,
+ cnum: ast::CrateNum,
+ link: cstore::LinkagePreference,
+ m: &mut HashMap<ast::CrateNum, cstore::LinkagePreference>) {
+ match m.find(&cnum) {
+ Some(&link2) => {
+ // If the linkages differ, then we'd have two copies of the library
+ // if we continued linking. If the linkages are both static, then we
+ // would also have two copies of the library (static from two
+ // different locations).
+ //
+ // This error is probably a little obscure, but I imagine that it
+ // can be refined over time.
+ if link2 != link || link == cstore::RequireStatic {
+ let data = sess.cstore.get_crate_data(cnum);
+ sess.err(format!("cannot satisfy dependencies so `{}` only \
+ shows up once", data.name));
+ sess.note("having upstream crates all available in one format \
+ will likely make this go away");
+ }
+ }
+ None => { m.insert(cnum, link); }
+ }
+}
+
+fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
+ let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
+ if crates.iter().all(|&(_, ref p)| p.is_some()) {
+ Some(crates.move_iter().map(|_| Some(cstore::RequireStatic)).collect())
+ } else {
+ None
+ }
+}
reachable.push("rust_eh_personality_catch".to_owned()); // referenced from rt/rust_try.ll
let metadata_module = ccx.metadata_llmod;
+ let formats = ccx.tcx.dependency_formats.borrow().clone();
(ccx.tcx, CrateTranslation {
context: llcx,
metadata_module: metadata_module,
metadata: metadata,
reachable: reachable,
+ crate_formats: formats,
})
}
use metadata::csearch;
use mc = middle::mem_categorization;
use middle::const_eval;
+use middle::dependency_format;
use middle::lang_items::{ExchangeHeapLangItem, OpaqueStructLangItem};
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
use middle::freevars;
pub method_map: typeck::MethodMap,
pub vtable_map: typeck::vtable_map,
+
+ pub dependency_formats: RefCell<dependency_format::Dependencies>,
}
pub enum tbox_flag {
extern_const_variants: RefCell::new(DefIdMap::new()),
method_map: RefCell::new(FnvHashMap::new()),
vtable_map: RefCell::new(FnvHashMap::new()),
+ dependency_formats: RefCell::new(HashMap::new()),
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "dylib"]
+
+extern crate a = "issue-12133-rlib";
+extern crate b = "issue-12133-dylib";
+
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:issue-12133-rlib.rs
-// aux-build:issue-12133-dylib.rs
-
-// error-pattern: dynamic linking is preferred, but dependencies were not found
-
-extern crate a = "issue-12133-rlib";
-extern crate b = "issue-12133-dylib";
-
-fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:issue-12133-rlib.rs
-// aux-build:issue-12133-dylib.rs
-// no-prefer-dynamic
-
-// error-pattern: dependencies were not all found in either dylib or rlib format
-
-extern crate a = "issue-12133-rlib";
-extern crate b = "issue-12133-dylib";
-
-fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:issue-12133-rlib.rs
-// aux-build:issue-12133-dylib.rs
-// no-prefer-dynamic
-
-// error-pattern: dylib output requested, but some depenencies could not
-
-#![crate_type = "dylib"]
-
-extern crate a = "issue-12133-rlib";
-extern crate b = "issue-12133-dylib";
--- /dev/null
+-include ../tools.mk
+
+# Testing various mixings of rlibs and dylibs. Makes sure that it's possible to
+# link an rlib to a dylib. The dependency tree among the file looks like:
+#
+# foo
+# / \
+# bar1 bar2
+# / \ /
+# baz baz2
+#
+# This is generally testing the permutations of the foo/bar1/bar2 layer against
+# the baz/baz2 layer
+
+all:
+ # Building just baz
+ $(RUSTC) --crate-type=rlib foo.rs
+ $(RUSTC) --crate-type=dylib bar1.rs
+ $(RUSTC) --crate-type=dylib,rlib baz.rs
+ $(RUSTC) --crate-type=bin baz.rs
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=dylib foo.rs
+ $(RUSTC) --crate-type=rlib bar1.rs
+ $(RUSTC) --crate-type=dylib,rlib baz.rs
+ $(RUSTC) --crate-type=bin baz.rs
+ rm $(TMPDIR)/*
+ # Building baz2
+ $(RUSTC) --crate-type=rlib foo.rs
+ $(RUSTC) --crate-type=dylib bar1.rs
+ $(RUSTC) --crate-type=dylib bar2.rs
+ $(RUSTC) --crate-type=dylib baz2.rs && exit 1 || exit 0
+ $(RUSTC) --crate-type=bin baz2.rs && exit 1 || exit 0
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=rlib foo.rs
+ $(RUSTC) --crate-type=rlib bar1.rs
+ $(RUSTC) --crate-type=dylib bar2.rs
+ $(RUSTC) --crate-type=dylib,rlib baz2.rs
+ $(RUSTC) --crate-type=bin baz2.rs
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=rlib foo.rs
+ $(RUSTC) --crate-type=dylib bar1.rs
+ $(RUSTC) --crate-type=rlib bar2.rs
+ $(RUSTC) --crate-type=dylib,rlib baz2.rs
+ $(RUSTC) --crate-type=bin baz2.rs
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=rlib foo.rs
+ $(RUSTC) --crate-type=rlib bar1.rs
+ $(RUSTC) --crate-type=rlib bar2.rs
+ $(RUSTC) --crate-type=dylib,rlib baz2.rs
+ $(RUSTC) --crate-type=bin baz2.rs
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=dylib foo.rs
+ $(RUSTC) --crate-type=rlib bar1.rs
+ $(RUSTC) --crate-type=rlib bar2.rs
+ $(RUSTC) --crate-type=dylib,rlib baz2.rs
+ $(RUSTC) --crate-type=bin baz2.rs
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=dylib foo.rs
+ $(RUSTC) --crate-type=dylib bar1.rs
+ $(RUSTC) --crate-type=rlib bar2.rs
+ $(RUSTC) --crate-type=dylib,rlib baz2.rs
+ $(RUSTC) --crate-type=bin baz2.rs
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=dylib foo.rs
+ $(RUSTC) --crate-type=rlib bar1.rs
+ $(RUSTC) --crate-type=dylib bar2.rs
+ $(RUSTC) --crate-type=dylib,rlib baz2.rs
+ $(RUSTC) --crate-type=bin baz2.rs
+ rm $(TMPDIR)/*
+ $(RUSTC) --crate-type=dylib foo.rs
+ $(RUSTC) --crate-type=dylib bar1.rs
+ $(RUSTC) --crate-type=dylib bar2.rs
+ $(RUSTC) --crate-type=dylib,rlib baz2.rs
+ $(RUSTC) --crate-type=bin baz2.rs
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate foo;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate foo;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate bar1;
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate bar1;
+extern crate bar2;
+
+fn main() {}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
all:
$(RUSTC) rlib.rs
- $(RUSTC) dylib.rs && exit 1 || exit 0
+ $(RUSTC) dylib.rs
$(RUSTC) rlib.rs --crate-type=dylib
$(RUSTC) dylib.rs
rm $(call DYLIB,rlib-*)
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-12133-rlib.rs
+// aux-build:issue-12133-dylib.rs
+
+extern crate a = "issue-12133-rlib";
+extern crate b = "issue-12133-dylib";
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-12133-rlib.rs
+// aux-build:issue-12133-dylib.rs
+// no-prefer-dynamic
+
+extern crate a = "issue-12133-rlib";
+extern crate b = "issue-12133-dylib";
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-12133-rlib.rs
+// aux-build:issue-12133-dylib.rs
+// aux-build:issue-12133-dylib2.rs
+
+extern crate other = "issue-12133-dylib2";
+
+fn main() {}