]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/back/linker.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_trans / back / linker.rs
CommitLineData
62682a34
SL
1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use std::ffi::OsString;
e9174d1e
SL
12use std::fs::{self, File};
13use std::io::{self, BufWriter};
14use std::io::prelude::*;
62682a34
SL
15use std::path::{Path, PathBuf};
16use std::process::Command;
17
c1a9b12d 18use back::archive;
92a42be0 19use middle::cstore::CrateStore;
e9174d1e 20use middle::dependency_format::Linkage;
62682a34 21use session::Session;
e9174d1e
SL
22use session::config::CrateTypeDylib;
23use session::config;
24use syntax::ast;
54a0048b 25use CrateTranslation;
62682a34
SL
26
27/// Linker abstraction used by back::link to build up the command to invoke a
28/// linker.
29///
30/// This trait is the total list of requirements needed by `back::link` and
31/// represents the meaning of each option being passed down. This trait is then
32/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
33/// MSVC linker (e.g. `link.exe`) is being used.
34pub trait Linker {
35 fn link_dylib(&mut self, lib: &str);
c1a9b12d 36 fn link_rust_dylib(&mut self, lib: &str, path: &Path);
62682a34
SL
37 fn link_framework(&mut self, framework: &str);
38 fn link_staticlib(&mut self, lib: &str);
39 fn link_rlib(&mut self, lib: &Path);
c1a9b12d 40 fn link_whole_rlib(&mut self, lib: &Path);
62682a34
SL
41 fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
42 fn include_path(&mut self, path: &Path);
43 fn framework_path(&mut self, path: &Path);
44 fn output_filename(&mut self, path: &Path);
45 fn add_object(&mut self, path: &Path);
46 fn gc_sections(&mut self, is_dylib: bool);
47 fn position_independent_executable(&mut self);
48 fn optimize(&mut self);
c1a9b12d 49 fn debuginfo(&mut self);
62682a34
SL
50 fn no_default_libraries(&mut self);
51 fn build_dylib(&mut self, out_filename: &Path);
52 fn args(&mut self, args: &[String]);
53 fn hint_static(&mut self);
54 fn hint_dynamic(&mut self);
55 fn whole_archives(&mut self);
56 fn no_whole_archives(&mut self);
e9174d1e
SL
57 fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
58 tmpdir: &Path);
62682a34
SL
59}
60
61pub struct GnuLinker<'a> {
62 pub cmd: &'a mut Command,
63 pub sess: &'a Session,
64}
65
66impl<'a> GnuLinker<'a> {
67 fn takes_hints(&self) -> bool {
68 !self.sess.target.target.options.is_like_osx
69 }
70}
71
72impl<'a> Linker for GnuLinker<'a> {
73 fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
74 fn link_staticlib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
75 fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
76 fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
77 fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
78 fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
79 fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
80 fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
81 fn args(&mut self, args: &[String]) { self.cmd.args(args); }
82
c1a9b12d
SL
83 fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
84 self.cmd.arg("-l").arg(lib);
85 }
86
62682a34
SL
87 fn link_framework(&mut self, framework: &str) {
88 self.cmd.arg("-framework").arg(framework);
89 }
90
91 fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
92 let target = &self.sess.target.target;
93 if !target.options.is_like_osx {
94 self.cmd.arg("-Wl,--whole-archive")
95 .arg("-l").arg(lib)
96 .arg("-Wl,--no-whole-archive");
97 } else {
98 // -force_load is the OSX equivalent of --whole-archive, but it
99 // involves passing the full path to the library to link.
100 let mut v = OsString::from("-Wl,-force_load,");
c1a9b12d
SL
101 v.push(&archive::find_library(lib, search_path, &self.sess));
102 self.cmd.arg(&v);
103 }
104 }
105
106 fn link_whole_rlib(&mut self, lib: &Path) {
107 if self.sess.target.target.options.is_like_osx {
108 let mut v = OsString::from("-Wl,-force_load,");
109 v.push(lib);
62682a34 110 self.cmd.arg(&v);
c1a9b12d
SL
111 } else {
112 self.cmd.arg("-Wl,--whole-archive").arg(lib)
113 .arg("-Wl,--no-whole-archive");
62682a34
SL
114 }
115 }
116
117 fn gc_sections(&mut self, is_dylib: bool) {
118 // The dead_strip option to the linker specifies that functions and data
119 // unreachable by the entry point will be removed. This is quite useful
120 // with Rust's compilation model of compiling libraries at a time into
121 // one object file. For example, this brings hello world from 1.7MB to
122 // 458K.
123 //
124 // Note that this is done for both executables and dynamic libraries. We
125 // won't get much benefit from dylibs because LLVM will have already
126 // stripped away as much as it could. This has not been seen to impact
127 // link times negatively.
128 //
129 // -dead_strip can't be part of the pre_link_args because it's also used
130 // for partial linking when using multiple codegen units (-r). So we
131 // insert it here.
132 if self.sess.target.target.options.is_like_osx {
133 self.cmd.arg("-Wl,-dead_strip");
7453a54e
SL
134 } else if self.sess.target.target.options.is_like_solaris {
135 self.cmd.arg("-Wl,-z");
136 self.cmd.arg("-Wl,ignore");
62682a34
SL
137
138 // If we're building a dylib, we don't use --gc-sections because LLVM
139 // has already done the best it can do, and we also don't want to
140 // eliminate the metadata. If we're building an executable, however,
141 // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
142 // reduction.
143 } else if !is_dylib {
144 self.cmd.arg("-Wl,--gc-sections");
145 }
146 }
147
148 fn optimize(&mut self) {
149 if !self.sess.target.target.options.linker_is_gnu { return }
150
151 // GNU-style linkers support optimization with -O. GNU ld doesn't
152 // need a numeric argument, but other linkers do.
9cc50fc6
SL
153 if self.sess.opts.optimize == config::OptLevel::Default ||
154 self.sess.opts.optimize == config::OptLevel::Aggressive {
62682a34
SL
155 self.cmd.arg("-Wl,-O1");
156 }
157 }
158
c1a9b12d
SL
159 fn debuginfo(&mut self) {
160 // Don't do anything special here for GNU-style linkers.
161 }
162
62682a34 163 fn no_default_libraries(&mut self) {
b039eaaf 164 self.cmd.arg("-nodefaultlibs");
62682a34
SL
165 }
166
167 fn build_dylib(&mut self, out_filename: &Path) {
168 // On mac we need to tell the linker to let this library be rpathed
169 if self.sess.target.target.options.is_like_osx {
170 self.cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
171
172 if self.sess.opts.cg.rpath {
173 let mut v = OsString::from("-Wl,-install_name,@rpath/");
174 v.push(out_filename.file_name().unwrap());
175 self.cmd.arg(&v);
176 }
177 } else {
178 self.cmd.arg("-shared");
179 }
180 }
181
182 fn whole_archives(&mut self) {
183 if !self.takes_hints() { return }
184 self.cmd.arg("-Wl,--whole-archive");
185 }
186
187 fn no_whole_archives(&mut self) {
188 if !self.takes_hints() { return }
189 self.cmd.arg("-Wl,--no-whole-archive");
190 }
191
192 fn hint_static(&mut self) {
193 if !self.takes_hints() { return }
194 self.cmd.arg("-Wl,-Bstatic");
195 }
196
197 fn hint_dynamic(&mut self) {
198 if !self.takes_hints() { return }
199 self.cmd.arg("-Wl,-Bdynamic");
200 }
e9174d1e
SL
201
202 fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) {
203 // noop, visibility in object files takes care of this
204 }
62682a34
SL
205}
206
207pub struct MsvcLinker<'a> {
208 pub cmd: &'a mut Command,
209 pub sess: &'a Session,
210}
211
212impl<'a> Linker for MsvcLinker<'a> {
213 fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
214 fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
215 fn args(&mut self, args: &[String]) { self.cmd.args(args); }
7453a54e
SL
216
217 fn build_dylib(&mut self, out_filename: &Path) {
218 self.cmd.arg("/DLL");
219 let mut arg: OsString = "/IMPLIB:".into();
220 arg.push(out_filename.with_extension("dll.lib"));
221 self.cmd.arg(arg);
222 }
223
62682a34
SL
224 fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); }
225
226 fn link_dylib(&mut self, lib: &str) {
227 self.cmd.arg(&format!("{}.lib", lib));
228 }
c1a9b12d
SL
229
230 fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
231 // When producing a dll, the MSVC linker may not actually emit a
232 // `foo.lib` file if the dll doesn't actually export any symbols, so we
233 // check to see if the file is there and just omit linking to it if it's
234 // not present.
7453a54e 235 let name = format!("{}.dll.lib", lib);
c1a9b12d
SL
236 if fs::metadata(&path.join(&name)).is_ok() {
237 self.cmd.arg(name);
238 }
239 }
240
62682a34
SL
241 fn link_staticlib(&mut self, lib: &str) {
242 self.cmd.arg(&format!("{}.lib", lib));
243 }
244
245 fn position_independent_executable(&mut self) {
246 // noop
247 }
248
249 fn no_default_libraries(&mut self) {
250 // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
251 // as there's been trouble in the past of linking the C++ standard
252 // library required by LLVM. This likely needs to happen one day, but
253 // in general Windows is also a more controlled environment than
254 // Unix, so it's not necessarily as critical that this be implemented.
255 //
256 // Note that there are also some licensing worries about statically
257 // linking some libraries which require a specific agreement, so it may
258 // not ever be possible for us to pass this flag.
259 }
260
261 fn include_path(&mut self, path: &Path) {
262 let mut arg = OsString::from("/LIBPATH:");
263 arg.push(path);
264 self.cmd.arg(&arg);
265 }
266
267 fn output_filename(&mut self, path: &Path) {
268 let mut arg = OsString::from("/OUT:");
269 arg.push(path);
270 self.cmd.arg(&arg);
271 }
272
273 fn framework_path(&mut self, _path: &Path) {
54a0048b 274 bug!("frameworks are not supported on windows")
62682a34
SL
275 }
276 fn link_framework(&mut self, _framework: &str) {
54a0048b 277 bug!("frameworks are not supported on windows")
62682a34
SL
278 }
279
280 fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
281 // not supported?
282 self.link_staticlib(lib);
283 }
c1a9b12d
SL
284 fn link_whole_rlib(&mut self, path: &Path) {
285 // not supported?
286 self.link_rlib(path);
287 }
62682a34
SL
288 fn optimize(&mut self) {
289 // Needs more investigation of `/OPT` arguments
290 }
c1a9b12d
SL
291
292 fn debuginfo(&mut self) {
b039eaaf
SL
293 // This will cause the Microsoft linker to generate a PDB file
294 // from the CodeView line tables in the object files.
295 self.cmd.arg("/DEBUG");
c1a9b12d
SL
296 }
297
62682a34
SL
298 fn whole_archives(&mut self) {
299 // hints not supported?
300 }
301 fn no_whole_archives(&mut self) {
302 // hints not supported?
303 }
304
305 // On windows static libraries are of the form `foo.lib` and dynamic
306 // libraries are not linked against directly, but rather through their
307 // import libraries also called `foo.lib`. As a result there's no
308 // possibility for a native library to appear both dynamically and
309 // statically in the same folder so we don't have to worry about hints like
310 // we do on Unix platforms.
311 fn hint_static(&mut self) {}
312 fn hint_dynamic(&mut self) {}
e9174d1e
SL
313
314 // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
315 // export symbols from a dynamic library. When building a dynamic library,
316 // however, we're going to want some symbols exported, so this function
317 // generates a DEF file which lists all the symbols.
318 //
319 // The linker will read this `*.def` file and export all the symbols from
320 // the dynamic library. Note that this is not as simple as just exporting
321 // all the symbols in the current crate (as specified by `trans.reachable`)
322 // but rather we also need to possibly export the symbols of upstream
323 // crates. Upstream rlibs may be linked statically to this dynamic library,
324 // in which case they may continue to transitively be used and hence need
325 // their symbols exported.
326 fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
327 tmpdir: &Path) {
328 let path = tmpdir.join("lib.def");
329 let res = (|| -> io::Result<()> {
54a0048b 330 let mut f = BufWriter::new(File::create(&path)?);
e9174d1e
SL
331
332 // Start off with the standard module name header and then go
333 // straight to exports.
54a0048b
SL
334 writeln!(f, "LIBRARY")?;
335 writeln!(f, "EXPORTS")?;
e9174d1e
SL
336
337 // Write out all our local symbols
338 for sym in trans.reachable.iter() {
54a0048b 339 writeln!(f, " {}", sym)?;
e9174d1e
SL
340 }
341
342 // Take a look at how all upstream crates are linked into this
343 // dynamic library. For all statically linked libraries we take all
344 // their reachable symbols and emit them as well.
345 let cstore = &sess.cstore;
346 let formats = sess.dependency_formats.borrow();
347 let symbols = formats[&CrateTypeDylib].iter();
348 let symbols = symbols.enumerate().filter_map(|(i, f)| {
349 if *f == Linkage::Static {
350 Some((i + 1) as ast::CrateNum)
351 } else {
352 None
353 }
354 }).flat_map(|cnum| {
92a42be0 355 cstore.reachable_ids(cnum)
e9174d1e 356 }).map(|did| {
92a42be0 357 cstore.item_symbol(did)
e9174d1e
SL
358 });
359 for symbol in symbols {
54a0048b 360 writeln!(f, " {}", symbol)?;
e9174d1e 361 }
54a0048b 362
e9174d1e
SL
363 Ok(())
364 })();
365 if let Err(e) = res {
366 sess.fatal(&format!("failed to write lib.def file: {}", e));
367 }
368 let mut arg = OsString::from("/DEF:");
369 arg.push(path);
370 self.cmd.arg(&arg);
371 }
62682a34 372}