Skip to content

Commit

Permalink
trans: move the linker support to compute symbols on-demand.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed May 24, 2016
1 parent c9a10bd commit b03bde9
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 45 deletions.
13 changes: 4 additions & 9 deletions src/librustc_trans/back/link.rs
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

use super::archive::{ArchiveBuilder, ArchiveConfig};
use super::linker::{Linker, GnuLinker, MsvcLinker};
use super::linker::Linker;
use super::rpath::RPathConfig;
use super::rpath;
use super::msvc;
Expand Down Expand Up @@ -637,13 +637,9 @@ fn link_natively(sess: &Session,
}

{
let mut linker = if sess.target.target.options.is_like_msvc {
Box::new(MsvcLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
} else {
Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
};
let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
link_args(&mut *linker, sess, crate_type, tmpdir,
objects, out_filename, trans, outputs);
objects, out_filename, outputs);
if !sess.target.target.options.no_compiler_rt {
linker.link_staticlib("compiler-rt");
}
Expand Down Expand Up @@ -712,7 +708,6 @@ fn link_args(cmd: &mut Linker,
tmpdir: &Path,
objects: &[PathBuf],
out_filename: &Path,
trans: &CrateTranslation,
outputs: &OutputFilenames) {

// The default library location, we need this to find the runtime.
Expand All @@ -731,7 +726,7 @@ fn link_args(cmd: &mut Linker,
// If we're building a dynamic library then some platforms need to make sure
// that all symbols are exported correctly from the dynamic library.
if crate_type != config::CrateTypeExecutable {
cmd.export_symbols(sess, trans, tmpdir, crate_type);
cmd.export_symbols(tmpdir, crate_type);
}

// When linking a dynamic library, we put the metadata into a section of the
Expand Down
116 changes: 80 additions & 36 deletions src/librustc_trans/back/linker.rs
Expand Up @@ -15,13 +15,50 @@ use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

use context::SharedCrateContext;
use monomorphize::Instance;

use back::archive;
use middle::dependency_format::Linkage;
use session::Session;
use session::config::CrateType;
use session::config;
use syntax::ast;
use CrateTranslation;

/// For all the linkers we support, and information they might
/// need out of the shared crate context before we get rid of it.
pub struct LinkerInfo {
dylib_exports: Vec<String>,
cdylib_exports: Vec<String>
}

impl<'a, 'tcx> LinkerInfo {
pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
reachable: &[String]) -> LinkerInfo {
LinkerInfo {
dylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeDylib),
cdylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeCdylib)
}
}

pub fn to_linker(&'a self,
cmd: &'a mut Command,
sess: &'a Session) -> Box<Linker+'a> {
if sess.target.target.options.is_like_msvc {
Box::new(MsvcLinker {
cmd: cmd,
sess: sess,
info: self
}) as Box<Linker>
} else {
Box::new(GnuLinker {
cmd: cmd,
sess: sess,
info: self
}) as Box<Linker>
}
}
}

/// Linker abstraction used by back::link to build up the command to invoke a
/// linker.
Expand Down Expand Up @@ -53,16 +90,13 @@ pub trait Linker {
fn hint_dynamic(&mut self);
fn whole_archives(&mut self);
fn no_whole_archives(&mut self);
fn export_symbols(&mut self,
sess: &Session,
trans: &CrateTranslation,
tmpdir: &Path,
crate_type: CrateType);
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
}

pub struct GnuLinker<'a> {
pub cmd: &'a mut Command,
pub sess: &'a Session,
cmd: &'a mut Command,
sess: &'a Session,
info: &'a LinkerInfo
}

impl<'a> GnuLinker<'a> {
Expand Down Expand Up @@ -201,11 +235,7 @@ impl<'a> Linker for GnuLinker<'a> {
self.cmd.arg("-Wl,-Bdynamic");
}

fn export_symbols(&mut self,
sess: &Session,
trans: &CrateTranslation,
tmpdir: &Path,
crate_type: CrateType) {
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
// If we're compiling a dylib, then we let symbol visibility in object
// files to take care of whether they're exported or not.
//
Expand All @@ -225,13 +255,13 @@ impl<'a> Linker for GnuLinker<'a> {
};
let res = (|| -> io::Result<()> {
let mut f = BufWriter::new(File::create(&path)?);
for sym in exported_symbols(sess, trans, crate_type) {
for sym in &self.info.cdylib_exports {
writeln!(f, "{}{}", prefix, sym)?;
}
Ok(())
})();
if let Err(e) = res {
sess.fatal(&format!("failed to write lib.def file: {}", e));
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
}
let mut arg = OsString::new();
if self.sess.target.target.options.is_like_osx {
Expand All @@ -245,8 +275,9 @@ impl<'a> Linker for GnuLinker<'a> {
}

pub struct MsvcLinker<'a> {
pub cmd: &'a mut Command,
pub sess: &'a Session,
cmd: &'a mut Command,
sess: &'a Session,
info: &'a LinkerInfo
}

impl<'a> Linker for MsvcLinker<'a> {
Expand Down Expand Up @@ -366,8 +397,6 @@ impl<'a> Linker for MsvcLinker<'a> {
// in which case they may continue to transitively be used and hence need
// their symbols exported.
fn export_symbols(&mut self,
sess: &Session,
trans: &CrateTranslation,
tmpdir: &Path,
crate_type: CrateType) {
let path = tmpdir.join("lib.def");
Expand All @@ -378,26 +407,42 @@ impl<'a> Linker for MsvcLinker<'a> {
// straight to exports.
writeln!(f, "LIBRARY")?;
writeln!(f, "EXPORTS")?;

for sym in exported_symbols(sess, trans, crate_type) {
writeln!(f, " {}", sym)?;
let symbols = if crate_type == CrateType::CrateTypeCdylib {
&self.info.cdylib_exports
} else {
&self.info.dylib_exports
};
for symbol in symbols {
writeln!(f, " {}", symbol)?;
}

Ok(())
})();
if let Err(e) = res {
sess.fatal(&format!("failed to write lib.def file: {}", e));
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
}
let mut arg = OsString::from("/DEF:");
arg.push(path);
self.cmd.arg(&arg);
}
}

fn exported_symbols(sess: &Session,
trans: &CrateTranslation,
crate_type: CrateType) -> Vec<String> {
let mut symbols = trans.reachable.iter().cloned().collect::<Vec<_>>();
fn exported_symbols(scx: &SharedCrateContext,
reachable: &[String],
crate_type: CrateType)
-> Vec<String> {
if !scx.sess().crate_types.borrow().contains(&crate_type) {
return vec![];
}

// See explanation in GnuLinker::export_symbols, for
// why we don't ever need dylib symbols on non-MSVC.
if crate_type == CrateType::CrateTypeDylib {
if !scx.sess().target.target.options.is_like_msvc {
return vec![];
}
}

let mut symbols = reachable.to_vec();

// If we're producing anything other than a dylib then the `reachable` array
// above is the exhaustive set of symbols we should be exporting.
Expand All @@ -409,20 +454,19 @@ fn exported_symbols(sess: &Session,
return symbols
}

let cstore = &sess.cstore;
let formats = sess.dependency_formats.borrow();
let upstream_symbols = formats[&crate_type].iter();
symbols.extend(upstream_symbols.enumerate().filter_map(|(i, f)| {
let cstore = &scx.sess().cstore;
let formats = scx.sess().dependency_formats.borrow();
let deps = formats[&crate_type].iter();
symbols.extend(deps.enumerate().filter_map(|(i, f)| {
if *f == Linkage::Static {
Some((i + 1) as ast::CrateNum)
} else {
None
}
}).flat_map(|cnum| {
cstore.reachable_ids(cnum)
}).map(|did| {
cstore.item_symbol(did)
}).map(|did| -> String {
Instance::mono(scx, did).symbol_name(scx)
}));

return symbols
symbols
}
3 changes: 3 additions & 0 deletions src/librustc_trans/base.rs
Expand Up @@ -31,6 +31,7 @@ use super::CrateTranslation;
use super::ModuleTranslation;

use back::link;
use back::linker::LinkerInfo;
use lint;
use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
use llvm;
Expand Down Expand Up @@ -2828,13 +2829,15 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");

let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols);
CrateTranslation {
modules: modules,
metadata_module: metadata_module,
link: link_meta,
metadata: metadata,
reachable: reachable_symbols,
no_builtins: no_builtins,
linker_info: linker_info
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc_trans/lib.rs
Expand Up @@ -145,6 +145,7 @@ pub struct CrateTranslation {
pub metadata: Vec<u8>,
pub reachable: Vec<String>,
pub no_builtins: bool,
pub linker_info: back::linker::LinkerInfo
}

__build_diagnostic_array! { librustc_trans, DIAGNOSTICS }

0 comments on commit b03bde9

Please sign in to comment.