Skip to content

Commit ff3a1ce

Browse files
committed
trans: move the MSVC linker to compute symbols on-demand.
1 parent f7362ca commit ff3a1ce

File tree

4 files changed

+91
-47
lines changed

4 files changed

+91
-47
lines changed

src/librustc_trans/back/link.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use super::archive::{ArchiveBuilder, ArchiveConfig};
12-
use super::linker::{Linker, GnuLinker, MsvcLinker};
12+
use super::linker::Linker;
1313
use super::rpath::RPathConfig;
1414
use super::rpath;
1515
use super::msvc;
@@ -634,13 +634,9 @@ fn link_natively(sess: &Session, dylib: bool,
634634
}
635635

636636
{
637-
let mut linker = if sess.target.target.options.is_like_msvc {
638-
Box::new(MsvcLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
639-
} else {
640-
Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
641-
};
637+
let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
642638
link_args(&mut *linker, sess, dylib, tmpdir,
643-
objects, out_filename, trans, outputs);
639+
objects, out_filename, outputs);
644640
if !sess.target.target.options.no_compiler_rt {
645641
linker.link_staticlib("compiler-rt");
646642
}
@@ -709,7 +705,6 @@ fn link_args(cmd: &mut Linker,
709705
tmpdir: &Path,
710706
objects: &[PathBuf],
711707
out_filename: &Path,
712-
trans: &CrateTranslation,
713708
outputs: &OutputFilenames) {
714709

715710
// The default library location, we need this to find the runtime.
@@ -728,7 +723,7 @@ fn link_args(cmd: &mut Linker,
728723
// If we're building a dynamic library then some platforms need to make sure
729724
// that all symbols are exported correctly from the dynamic library.
730725
if dylib {
731-
cmd.export_symbols(sess, trans, tmpdir);
726+
cmd.export_symbols(tmpdir);
732727
}
733728

734729
// When linking a dynamic library, we put the metadata into a section of the

src/librustc_trans/back/linker.rs

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,91 @@
99
// except according to those terms.
1010

1111
use std::ffi::OsString;
12+
use std::fmt::Write as FmtWrite;
1213
use std::fs::{self, File};
1314
use std::io::{self, BufWriter};
1415
use std::io::prelude::*;
1516
use std::path::{Path, PathBuf};
1617
use std::process::Command;
1718

19+
use context::SharedCrateContext;
20+
use monomorphize::Instance;
21+
1822
use back::archive;
1923
use middle::dependency_format::Linkage;
2024
use session::Session;
2125
use session::config::CrateTypeDylib;
2226
use session::config;
2327
use syntax::ast;
24-
use CrateTranslation;
28+
29+
/// For all the linkers we support, and information they might
30+
/// need out of the shared crate context before we get rid of it.
31+
pub enum LinkerInfo {
32+
Gnu,
33+
Msvc {
34+
dylib_exports: String
35+
}
36+
}
37+
38+
impl<'a, 'tcx> LinkerInfo {
39+
pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
40+
reachable: &[String]) -> LinkerInfo {
41+
if scx.sess().target.target.options.is_like_msvc {
42+
let mut exports = String::new();
43+
if scx.sess().crate_types.borrow().contains(&CrateTypeDylib) {
44+
for sym in reachable {
45+
writeln!(exports, " {}", sym).unwrap();
46+
}
47+
48+
// Take a look at how all upstream crates are linked into this
49+
// dynamic library. For all statically linked libraries we take all
50+
// their reachable symbols and emit them as well.
51+
let cstore = &scx.sess().cstore;
52+
let formats = scx.sess().dependency_formats.borrow();
53+
let symbols = formats[&CrateTypeDylib].iter();
54+
let symbols = symbols.enumerate().filter_map(|(i, f)| {
55+
if *f == Linkage::Static {
56+
Some((i + 1) as ast::CrateNum)
57+
} else {
58+
None
59+
}
60+
}).flat_map(|cnum| {
61+
cstore.reachable_ids(cnum)
62+
}).map(|did| -> String {
63+
Instance::mono(scx.tcx(), did).symbol_name(scx)
64+
});
65+
for symbol in symbols {
66+
writeln!(exports, " {}", symbol).unwrap();
67+
}
68+
}
69+
LinkerInfo::Msvc {
70+
dylib_exports: exports
71+
}
72+
} else {
73+
LinkerInfo::Gnu
74+
}
75+
}
76+
77+
pub fn to_linker(&'a self,
78+
cmd: &'a mut Command,
79+
sess: &'a Session) -> Box<Linker+'a> {
80+
match *self {
81+
LinkerInfo::Gnu => {
82+
Box::new(GnuLinker {
83+
cmd: cmd,
84+
sess: sess
85+
}) as Box<Linker>
86+
}
87+
LinkerInfo::Msvc { ref dylib_exports } => {
88+
Box::new(MsvcLinker {
89+
cmd: cmd,
90+
sess: sess,
91+
dylib_exports: dylib_exports
92+
}) as Box<Linker>
93+
}
94+
}
95+
}
96+
}
2597

2698
/// Linker abstraction used by back::link to build up the command to invoke a
2799
/// linker.
@@ -53,13 +125,12 @@ pub trait Linker {
53125
fn hint_dynamic(&mut self);
54126
fn whole_archives(&mut self);
55127
fn no_whole_archives(&mut self);
56-
fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
57-
tmpdir: &Path);
128+
fn export_symbols(&mut self, tmpdir: &Path);
58129
}
59130

60131
pub struct GnuLinker<'a> {
61-
pub cmd: &'a mut Command,
62-
pub sess: &'a Session,
132+
cmd: &'a mut Command,
133+
sess: &'a Session,
63134
}
64135

65136
impl<'a> GnuLinker<'a> {
@@ -198,14 +269,15 @@ impl<'a> Linker for GnuLinker<'a> {
198269
self.cmd.arg("-Wl,-Bdynamic");
199270
}
200271

201-
fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) {
272+
fn export_symbols(&mut self, _: &Path) {
202273
// noop, visibility in object files takes care of this
203274
}
204275
}
205276

206277
pub struct MsvcLinker<'a> {
207-
pub cmd: &'a mut Command,
208-
pub sess: &'a Session,
278+
cmd: &'a mut Command,
279+
sess: &'a Session,
280+
dylib_exports: &'a str
209281
}
210282

211283
impl<'a> Linker for MsvcLinker<'a> {
@@ -322,8 +394,7 @@ impl<'a> Linker for MsvcLinker<'a> {
322394
// crates. Upstream rlibs may be linked statically to this dynamic library,
323395
// in which case they may continue to transitively be used and hence need
324396
// their symbols exported.
325-
fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
326-
tmpdir: &Path) {
397+
fn export_symbols(&mut self, tmpdir: &Path) {
327398
let path = tmpdir.join("lib.def");
328399
let res = (|| -> io::Result<()> {
329400
let mut f = BufWriter::new(File::create(&path)?);
@@ -332,37 +403,11 @@ impl<'a> Linker for MsvcLinker<'a> {
332403
// straight to exports.
333404
writeln!(f, "LIBRARY")?;
334405
writeln!(f, "EXPORTS")?;
335-
336-
// Write out all our local symbols
337-
for sym in trans.reachable.iter() {
338-
writeln!(f, " {}", sym)?;
339-
}
340-
341-
// Take a look at how all upstream crates are linked into this
342-
// dynamic library. For all statically linked libraries we take all
343-
// their reachable symbols and emit them as well.
344-
let cstore = &sess.cstore;
345-
let formats = sess.dependency_formats.borrow();
346-
let symbols = formats[&CrateTypeDylib].iter();
347-
let symbols = symbols.enumerate().filter_map(|(i, f)| {
348-
if *f == Linkage::Static {
349-
Some((i + 1) as ast::CrateNum)
350-
} else {
351-
None
352-
}
353-
}).flat_map(|cnum| {
354-
cstore.reachable_ids(cnum)
355-
}).map(|did| {
356-
cstore.item_symbol(did)
357-
});
358-
for symbol in symbols {
359-
writeln!(f, " {}", symbol)?;
360-
}
361-
406+
f.write(self.dylib_exports.as_bytes())?;
362407
Ok(())
363408
})();
364409
if let Err(e) = res {
365-
sess.fatal(&format!("failed to write lib.def file: {}", e));
410+
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
366411
}
367412
let mut arg = OsString::from("/DEF:");
368413
arg.push(path);

src/librustc_trans/base.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use super::CrateTranslation;
3131
use super::ModuleTranslation;
3232

3333
use back::link;
34+
use back::linker::LinkerInfo;
3435
use lint;
3536
use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
3637
use llvm;
@@ -2815,13 +2816,15 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
28152816
};
28162817
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
28172818

2819+
let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols);
28182820
CrateTranslation {
28192821
modules: modules,
28202822
metadata_module: metadata_module,
28212823
link: link_meta,
28222824
metadata: metadata,
28232825
reachable: reachable_symbols,
28242826
no_builtins: no_builtins,
2827+
linker_info: linker_info
28252828
}
28262829
}
28272830

src/librustc_trans/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ pub struct CrateTranslation {
144144
pub metadata: Vec<u8>,
145145
pub reachable: Vec<String>,
146146
pub no_builtins: bool,
147+
pub linker_info: back::linker::LinkerInfo
147148
}
148149

149150
__build_diagnostic_array! { librustc_trans, DIAGNOSTICS }

0 commit comments

Comments
 (0)