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.
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.
11 use std
::ffi
::OsString
;
12 use std
::path
::{Path, PathBuf}
;
13 use std
::process
::Command
;
15 use rustc_back
::archive
;
19 /// Linker abstraction used by back::link to build up the command to invoke a
22 /// This trait is the total list of requirements needed by `back::link` and
23 /// represents the meaning of each option being passed down. This trait is then
24 /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
25 /// MSVC linker (e.g. `link.exe`) is being used.
27 fn link_dylib(&mut self, lib
: &str);
28 fn link_framework(&mut self, framework
: &str);
29 fn link_staticlib(&mut self, lib
: &str);
30 fn link_rlib(&mut self, lib
: &Path
);
31 fn link_whole_staticlib(&mut self, lib
: &str, search_path
: &[PathBuf
]);
32 fn include_path(&mut self, path
: &Path
);
33 fn framework_path(&mut self, path
: &Path
);
34 fn output_filename(&mut self, path
: &Path
);
35 fn add_object(&mut self, path
: &Path
);
36 fn gc_sections(&mut self, is_dylib
: bool
);
37 fn position_independent_executable(&mut self);
38 fn optimize(&mut self);
39 fn no_default_libraries(&mut self);
40 fn build_dylib(&mut self, out_filename
: &Path
);
41 fn args(&mut self, args
: &[String
]);
42 fn hint_static(&mut self);
43 fn hint_dynamic(&mut self);
44 fn whole_archives(&mut self);
45 fn no_whole_archives(&mut self);
48 pub struct GnuLinker
<'a
> {
49 pub cmd
: &'a
mut Command
,
50 pub sess
: &'a Session
,
53 impl<'a
> GnuLinker
<'a
> {
54 fn takes_hints(&self) -> bool
{
55 !self.sess
.target
.target
.options
.is_like_osx
59 impl<'a
> Linker
for GnuLinker
<'a
> {
60 fn link_dylib(&mut self, lib
: &str) { self.cmd.arg("-l").arg(lib); }
61 fn link_staticlib(&mut self, lib
: &str) { self.cmd.arg("-l").arg(lib); }
62 fn link_rlib(&mut self, lib
: &Path
) { self.cmd.arg(lib); }
63 fn include_path(&mut self, path
: &Path
) { self.cmd.arg("-L").arg(path); }
64 fn framework_path(&mut self, path
: &Path
) { self.cmd.arg("-F").arg(path); }
65 fn output_filename(&mut self, path
: &Path
) { self.cmd.arg("-o").arg(path); }
66 fn add_object(&mut self, path
: &Path
) { self.cmd.arg(path); }
67 fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
68 fn args(&mut self, args
: &[String
]) { self.cmd.args(args); }
70 fn link_framework(&mut self, framework
: &str) {
71 self.cmd
.arg("-framework").arg(framework
);
74 fn link_whole_staticlib(&mut self, lib
: &str, search_path
: &[PathBuf
]) {
75 let target
= &self.sess
.target
.target
;
76 if !target
.options
.is_like_osx
{
77 self.cmd
.arg("-Wl,--whole-archive")
79 .arg("-Wl,--no-whole-archive");
81 // -force_load is the OSX equivalent of --whole-archive, but it
82 // involves passing the full path to the library to link.
83 let mut v
= OsString
::from("-Wl,-force_load,");
84 v
.push(&archive
::find_library(lib
,
85 &target
.options
.staticlib_prefix
,
86 &target
.options
.staticlib_suffix
,
88 &self.sess
.diagnostic().handler
));
93 fn gc_sections(&mut self, is_dylib
: bool
) {
94 // The dead_strip option to the linker specifies that functions and data
95 // unreachable by the entry point will be removed. This is quite useful
96 // with Rust's compilation model of compiling libraries at a time into
97 // one object file. For example, this brings hello world from 1.7MB to
100 // Note that this is done for both executables and dynamic libraries. We
101 // won't get much benefit from dylibs because LLVM will have already
102 // stripped away as much as it could. This has not been seen to impact
103 // link times negatively.
105 // -dead_strip can't be part of the pre_link_args because it's also used
106 // for partial linking when using multiple codegen units (-r). So we
108 if self.sess
.target
.target
.options
.is_like_osx
{
109 self.cmd
.arg("-Wl,-dead_strip");
111 // If we're building a dylib, we don't use --gc-sections because LLVM
112 // has already done the best it can do, and we also don't want to
113 // eliminate the metadata. If we're building an executable, however,
114 // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
116 } else if !is_dylib
{
117 self.cmd
.arg("-Wl,--gc-sections");
121 fn optimize(&mut self) {
122 if !self.sess
.target
.target
.options
.linker_is_gnu { return }
124 // GNU-style linkers support optimization with -O. GNU ld doesn't
125 // need a numeric argument, but other linkers do.
126 if self.sess
.opts
.optimize
== config
::Default
||
127 self.sess
.opts
.optimize
== config
::Aggressive
{
128 self.cmd
.arg("-Wl,-O1");
132 fn no_default_libraries(&mut self) {
133 // Unfortunately right now passing -nodefaultlibs to gcc on windows
134 // doesn't work so hot (in terms of native dependencies). This if
135 // statement should hopefully be removed one day though!
136 if !self.sess
.target
.target
.options
.is_like_windows
{
137 self.cmd
.arg("-nodefaultlibs");
141 fn build_dylib(&mut self, out_filename
: &Path
) {
142 // On mac we need to tell the linker to let this library be rpathed
143 if self.sess
.target
.target
.options
.is_like_osx
{
144 self.cmd
.args(&["-dynamiclib", "-Wl,-dylib"]);
146 if self.sess
.opts
.cg
.rpath
{
147 let mut v
= OsString
::from("-Wl,-install_name,@rpath/");
148 v
.push(out_filename
.file_name().unwrap());
152 self.cmd
.arg("-shared");
156 fn whole_archives(&mut self) {
157 if !self.takes_hints() { return }
158 self.cmd
.arg("-Wl,--whole-archive");
161 fn no_whole_archives(&mut self) {
162 if !self.takes_hints() { return }
163 self.cmd
.arg("-Wl,--no-whole-archive");
166 fn hint_static(&mut self) {
167 if !self.takes_hints() { return }
168 self.cmd
.arg("-Wl,-Bstatic");
171 fn hint_dynamic(&mut self) {
172 if !self.takes_hints() { return }
173 self.cmd
.arg("-Wl,-Bdynamic");
177 pub struct MsvcLinker
<'a
> {
178 pub cmd
: &'a
mut Command
,
179 pub sess
: &'a Session
,
182 impl<'a
> Linker
for MsvcLinker
<'a
> {
183 fn link_rlib(&mut self, lib
: &Path
) { self.cmd.arg(lib); }
184 fn add_object(&mut self, path
: &Path
) { self.cmd.arg(path); }
185 fn args(&mut self, args
: &[String
]) { self.cmd.args(args); }
186 fn build_dylib(&mut self, _out_filename
: &Path
) { self.cmd.arg("/DLL"); }
187 fn gc_sections(&mut self, _is_dylib
: bool
) { self.cmd.arg("/OPT:REF,ICF"); }
189 fn link_dylib(&mut self, lib
: &str) {
190 self.cmd
.arg(&format
!("{}.lib", lib
));
192 fn link_staticlib(&mut self, lib
: &str) {
193 self.cmd
.arg(&format
!("{}.lib", lib
));
196 fn position_independent_executable(&mut self) {
200 fn no_default_libraries(&mut self) {
201 // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
202 // as there's been trouble in the past of linking the C++ standard
203 // library required by LLVM. This likely needs to happen one day, but
204 // in general Windows is also a more controlled environment than
205 // Unix, so it's not necessarily as critical that this be implemented.
207 // Note that there are also some licensing worries about statically
208 // linking some libraries which require a specific agreement, so it may
209 // not ever be possible for us to pass this flag.
212 fn include_path(&mut self, path
: &Path
) {
213 let mut arg
= OsString
::from("/LIBPATH:");
218 fn output_filename(&mut self, path
: &Path
) {
219 let mut arg
= OsString
::from("/OUT:");
224 fn framework_path(&mut self, _path
: &Path
) {
225 panic
!("frameworks are not supported on windows")
227 fn link_framework(&mut self, _framework
: &str) {
228 panic
!("frameworks are not supported on windows")
231 fn link_whole_staticlib(&mut self, lib
: &str, _search_path
: &[PathBuf
]) {
233 self.link_staticlib(lib
);
235 fn optimize(&mut self) {
236 // Needs more investigation of `/OPT` arguments
238 fn whole_archives(&mut self) {
239 // hints not supported?
241 fn no_whole_archives(&mut self) {
242 // hints not supported?
245 // On windows static libraries are of the form `foo.lib` and dynamic
246 // libraries are not linked against directly, but rather through their
247 // import libraries also called `foo.lib`. As a result there's no
248 // possibility for a native library to appear both dynamically and
249 // statically in the same folder so we don't have to worry about hints like
250 // we do on Unix platforms.
251 fn hint_static(&mut self) {}
252 fn hint_dynamic(&mut self) {}