trans: move the linker support to compute symbols on-demand.
This commit is contained in:
parent
c9a10bd26b
commit
b03bde9c2a
@ -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;
|
||||
@ -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");
|
||||
}
|
||||
@ -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.
|
||||
@ -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
|
||||
|
@ -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.
|
||||
@ -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> {
|
||||
@ -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.
|
||||
//
|
||||
@ -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 {
|
||||
@ -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> {
|
||||
@ -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");
|
||||
@ -378,15 +407,18 @@ 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);
|
||||
@ -394,10 +426,23 @@ impl<'a> Linker for MsvcLinker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@ -409,10 +454,10 @@ 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 {
|
||||
@ -420,9 +465,8 @@ fn exported_symbols(sess: &Session,
|
||||
}
|
||||
}).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
|
||||
}
|
||||
|
@ -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;
|
||||
@ -2828,6 +2829,7 @@ 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,
|
||||
@ -2835,6 +2837,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
metadata: metadata,
|
||||
reachable: reachable_symbols,
|
||||
no_builtins: no_builtins,
|
||||
linker_info: linker_info
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
|
Loading…
x
Reference in New Issue
Block a user