|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 | 11 | use std::ffi::OsString;
|
| 12 | +use std::fs::{self, File}; |
| 13 | +use std::io::{self, BufWriter}; |
| 14 | +use std::io::prelude::*; |
12 | 15 | use std::path::{Path, PathBuf};
|
13 | 16 | use std::process::Command;
|
14 |
| -use std::fs; |
15 | 17 |
|
16 | 18 | use back::archive;
|
| 19 | +use metadata::csearch; |
| 20 | +use metadata::cstore; |
17 | 21 | use session::Session;
|
18 |
| -use session::config; |
19 | 22 | use session::config::DebugInfoLevel::{NoDebugInfo, LimitedDebugInfo, FullDebugInfo};
|
| 23 | +use session::config::CrateTypeDylib; |
| 24 | +use session::config; |
| 25 | +use syntax::ast; |
| 26 | +use trans::CrateTranslation; |
20 | 27 |
|
21 | 28 | /// Linker abstraction used by back::link to build up the command to invoke a
|
22 | 29 | /// linker.
|
@@ -48,6 +55,8 @@ pub trait Linker {
|
48 | 55 | fn hint_dynamic(&mut self);
|
49 | 56 | fn whole_archives(&mut self);
|
50 | 57 | fn no_whole_archives(&mut self);
|
| 58 | + fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, |
| 59 | + tmpdir: &Path); |
51 | 60 | }
|
52 | 61 |
|
53 | 62 | pub struct GnuLinker<'a> {
|
@@ -192,6 +201,10 @@ impl<'a> Linker for GnuLinker<'a> {
|
192 | 201 | if !self.takes_hints() { return }
|
193 | 202 | self.cmd.arg("-Wl,-Bdynamic");
|
194 | 203 | }
|
| 204 | + |
| 205 | + fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) { |
| 206 | + // noop, visibility in object files takes care of this |
| 207 | + } |
195 | 208 | }
|
196 | 209 |
|
197 | 210 | pub struct MsvcLinker<'a> {
|
@@ -301,4 +314,61 @@ impl<'a> Linker for MsvcLinker<'a> {
|
301 | 314 | // we do on Unix platforms.
|
302 | 315 | fn hint_static(&mut self) {}
|
303 | 316 | fn hint_dynamic(&mut self) {}
|
| 317 | + |
| 318 | + // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to |
| 319 | + // export symbols from a dynamic library. When building a dynamic library, |
| 320 | + // however, we're going to want some symbols exported, so this function |
| 321 | + // generates a DEF file which lists all the symbols. |
| 322 | + // |
| 323 | + // The linker will read this `*.def` file and export all the symbols from |
| 324 | + // the dynamic library. Note that this is not as simple as just exporting |
| 325 | + // all the symbols in the current crate (as specified by `trans.reachable`) |
| 326 | + // but rather we also need to possibly export the symbols of upstream |
| 327 | + // crates. Upstream rlibs may be linked statically to this dynamic library, |
| 328 | + // in which case they may continue to transitively be used and hence need |
| 329 | + // their symbols exported. |
| 330 | + fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, |
| 331 | + tmpdir: &Path) { |
| 332 | + let path = tmpdir.join("lib.def"); |
| 333 | + let res = (|| -> io::Result<()> { |
| 334 | + let mut f = BufWriter::new(try!(File::create(&path))); |
| 335 | + |
| 336 | + // Start off with the standard module name header and then go |
| 337 | + // straight to exports. |
| 338 | + try!(writeln!(f, "LIBRARY")); |
| 339 | + try!(writeln!(f, "EXPORTS")); |
| 340 | + |
| 341 | + // Write out all our local symbols |
| 342 | + for sym in trans.reachable.iter() { |
| 343 | + try!(writeln!(f, " {}", sym)); |
| 344 | + } |
| 345 | + |
| 346 | + // Take a look at how all upstream crates are linked into this |
| 347 | + // dynamic library. For all statically linked libraries we take all |
| 348 | + // their reachable symbols and emit them as well. |
| 349 | + let cstore = &sess.cstore; |
| 350 | + let symbols = trans.crate_formats[&CrateTypeDylib].iter(); |
| 351 | + let symbols = symbols.enumerate().filter_map(|(i, f)| { |
| 352 | + if let Some(cstore::RequireStatic) = *f { |
| 353 | + Some((i + 1) as ast::CrateNum) |
| 354 | + } else { |
| 355 | + None |
| 356 | + } |
| 357 | + }).flat_map(|cnum| { |
| 358 | + csearch::get_reachable_ids(cstore, cnum) |
| 359 | + }).map(|did| { |
| 360 | + csearch::get_symbol(cstore, did) |
| 361 | + }); |
| 362 | + for symbol in symbols { |
| 363 | + try!(writeln!(f, " {}", symbol)); |
| 364 | + } |
| 365 | + Ok(()) |
| 366 | + })(); |
| 367 | + if let Err(e) = res { |
| 368 | + sess.fatal(&format!("failed to write lib.def file: {}", e)); |
| 369 | + } |
| 370 | + let mut arg = OsString::from("/DEF:"); |
| 371 | + arg.push(path); |
| 372 | + self.cmd.arg(&arg); |
| 373 | + } |
304 | 374 | }
|
0 commit comments