PageRenderTime 25ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/src/librustc_trans/back/linker.rs

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