1 // Copyright 2012-2013 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.
13 use driver::session::Session;
16 use lib::llvm::ModuleRef;
18 use metadata::common::LinkMeta;
19 use metadata::{encoder, csearch, cstore};
20 use middle::trans::context::CrateContext;
21 use middle::trans::common::gensym_name;
26 use std::hash::Streaming;
28 use std::libc::{c_int, c_uint};
29 use std::os::consts::{macos, freebsd, linux, android, win32};
32 use std::rt::io::Writer;
37 use syntax::ast_map::{path, path_mod, path_name};
39 use syntax::attr::{AttrMetaMethods};
40 use syntax::print::pprust;
41 use syntax::parse::token;
43 #[deriving(Clone, Eq)]
44 pub enum output_type {
48 output_type_llvm_assembly,
53 fn write_string<W:Writer>(writer: &mut W, string: &str) {
54 writer.write(string.as_bytes());
57 pub fn llvm_err(sess: Session, msg: ~str) -> ! {
59 let cstr = llvm::LLVMRustGetLastError();
60 if cstr == ptr::null() {
63 sess.fatal(msg + ": " + str::raw::from_c_str(cstr));
68 pub fn WriteOutputFile(sess: Session,
69 PM: lib::llvm::PassManagerRef, M: ModuleRef,
73 // FIXME: When #2334 is fixed, change
77 EnableSegmentedStacks: bool) {
79 do str::as_c_str(Triple) |Triple| {
80 do str::as_c_str(Feature) |Feature| {
81 do str::as_c_str(Output) |Output| {
82 let result = llvm::LLVMRustWriteOutputFile(
90 EnableSegmentedStacks);
92 llvm_err(sess, ~"Could not write output");
102 use back::link::llvm_err;
103 use driver::session::Session;
105 use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
106 use metadata::cstore;
110 use std::unstable::intrinsics;
113 ee: ExecutionEngineRef,
118 impl Engine for LLVMJITData {}
120 impl Drop for LLVMJITData {
123 llvm::LLVMDisposeExecutionEngine(self.ee);
124 llvm::LLVMContextDispose(self.llcx);
129 pub fn exec(sess: Session,
134 let manager = llvm::LLVMRustPrepareJIT(intrinsics::morestack_addr());
136 // We need to tell JIT where to resolve all linked
137 // symbols from. The equivalent of -lstd, -lcore, etc.
138 // By default the JIT will resolve symbols from the extra and
139 // core linked into rustc. We don't want that,
140 // incase the user wants to use an older extra library.
142 let cstore = sess.cstore;
143 let r = cstore::get_used_crate_files(cstore);
144 for r.iter().advance |cratepath| {
145 let path = cratepath.to_str();
147 debug!("linking: %s", path);
149 do path.as_c_str |buf_t| {
150 if !llvm::LLVMRustLoadCrate(manager, buf_t) {
151 llvm_err(sess, ~"Could not link");
153 debug!("linked: %s", path);
157 // We custom-build a JIT execution engine via some rust wrappers
158 // first. This wrappers takes ownership of the module passed in.
159 let ee = llvm::LLVMRustBuildJIT(manager, m, stacks);
161 llvm::LLVMContextDispose(c);
162 llvm_err(sess, ~"Could not create the JIT");
165 // Next, we need to get a handle on the _rust_main function by
166 // looking up it's corresponding ValueRef and then requesting that
167 // the execution engine compiles the function.
168 let fun = do "_rust_main".as_c_str |entry| {
169 llvm::LLVMGetNamedFunction(m, entry)
172 llvm::LLVMDisposeExecutionEngine(ee);
173 llvm::LLVMContextDispose(c);
174 llvm_err(sess, ~"Could not find _rust_main in the JIT");
177 // Finally, once we have the pointer to the code, we can do some
178 // closure magic here to turn it straight into a callable rust
180 let code = llvm::LLVMGetPointerToGlobal(ee, fun);
181 assert!(!code.is_null());
182 let func: extern "Rust" fn() = cast::transmute(code);
185 // Currently there is no method of re-using the executing engine
186 // from LLVM in another call to the JIT. While this kinda defeats
187 // the purpose of having a JIT in the first place, there isn't
188 // actually much code currently which would re-use data between
189 // different invocations of this. Additionally, the compilation
190 // model currently isn't designed to support this scenario.
192 // We can't destroy the engine/context immediately here, however,
193 // because of annihilation. The JIT code contains drop glue for any
194 // types defined in the crate we just ran, and if any of those boxes
195 // are going to be dropped during annihilation, the drop glue must
196 // be run. Hence, we need to transfer ownership of this jit engine
197 // to the caller of this function. To be convenient for now, we
198 // shove it into TLS and have someone else remove it later on.
199 let data = ~LLVMJITData { ee: ee, llcx: c };
200 set_engine(data as ~Engine);
204 // The stage1 compiler won't work, but that doesn't really matter. TLS
205 // changed only very recently to allow storage of owned values.
206 static engine_key: local_data::Key<~Engine> = &local_data::Key;
208 fn set_engine(engine: ~Engine) {
209 local_data::set(engine_key, engine)
212 pub fn consume_engine() -> Option<~Engine> {
213 local_data::pop(engine_key)
220 use back::link::{WriteOutputFile, output_type};
221 use back::link::{output_type_assembly, output_type_bitcode};
222 use back::link::{output_type_exe, output_type_llvm_assembly};
223 use back::link::{output_type_object};
224 use driver::session::Session;
227 use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
228 use lib::llvm::{ContextRef};
233 use std::libc::{c_int, c_uint};
238 pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
240 output_type_assembly | output_type_object | output_type_exe => true,
245 pub fn run_passes(sess: Session,
248 output_type: output_type,
251 llvm::LLVMInitializePasses();
253 let opts = sess.opts;
254 if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
255 let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
256 let pm = mk_pass_manager();
257 llvm::LLVMAddTargetData(td.lltd, pm.llpm);
259 // Generate a pre-optimization intermediate file if -save-temps
263 output_type_bitcode => {
264 if opts.optimize != session::No {
265 let filename = output.with_filetype("no-opt.bc");
266 str::as_c_str(filename.to_str(), |buf| {
267 llvm::LLVMWriteBitcodeToFile(llmod, buf)
272 let filename = output.with_filetype("bc");
273 str::as_c_str(filename.to_str(), |buf| {
274 llvm::LLVMWriteBitcodeToFile(llmod, buf)
280 let mut mpm = passes::PassManager::new(td.lltd);
282 if !sess.no_verify() {
283 mpm.add_pass_from_name("verify");
286 let passes = if sess.opts.custom_passes.len() > 0 {
287 sess.opts.custom_passes.clone()
289 if sess.lint_llvm() {
290 mpm.add_pass_from_name("lint");
292 passes::create_standard_passes(opts.optimize)
296 debug!("Passes: %?", passes);
297 passes::populate_pass_manager(sess, &mut mpm, passes);
299 debug!("Running Module Optimization Pass");
303 // If we are using JIT, go ahead and create and execute the
304 // engine now. JIT execution takes ownership of the module and
305 // context, so don't dispose and return.
306 jit::exec(sess, llcx, llmod, true);
308 if sess.time_llvm_passes() {
309 llvm::LLVMRustPrintPassTimings();
312 } else if is_object_or_assembly_or_exe(output_type) {
313 let LLVMOptNone = 0 as c_int; // -O0
314 let LLVMOptLess = 1 as c_int; // -O1
315 let LLVMOptDefault = 2 as c_int; // -O2, -Os
316 let LLVMOptAggressive = 3 as c_int; // -O3
318 let CodeGenOptLevel = match opts.optimize {
319 session::No => LLVMOptNone,
320 session::Less => LLVMOptLess,
321 session::Default => LLVMOptDefault,
322 session::Aggressive => LLVMOptAggressive
325 let FileType = match output_type {
326 output_type_object | output_type_exe => lib::llvm::ObjectFile,
327 _ => lib::llvm::AssemblyFile
330 // Write optimized bitcode if --save-temps was on.
333 // Always output the bitcode file with --save-temps
335 let filename = output.with_filetype("opt.bc");
336 str::as_c_str(filename.to_str(), |buf| {
337 llvm::LLVMWriteBitcodeToFile(llmod, buf)
339 // Save the assembly file if -S is used
340 if output_type == output_type_assembly {
345 sess.targ_cfg.target_strs.target_triple,
348 lib::llvm::AssemblyFile as c_uint,
353 // Save the object file for -c or --save-temps alone
354 // This .o is needed when an exe is built
355 if output_type == output_type_object ||
356 output_type == output_type_exe {
361 sess.targ_cfg.target_strs.target_triple,
364 lib::llvm::ObjectFile as c_uint,
369 // If we aren't saving temps then just output the file
370 // type corresponding to the '-c' or '-S' flag used
375 sess.targ_cfg.target_strs.target_triple,
382 // Clean up and return
384 llvm::LLVMDisposeModule(llmod);
385 llvm::LLVMContextDispose(llcx);
386 if sess.time_llvm_passes() {
387 llvm::LLVMRustPrintPassTimings();
392 if output_type == output_type_llvm_assembly {
393 // Given options "-S --emit-llvm": output LLVM assembly
394 str::as_c_str(output.to_str(), |buf_o| {
395 llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o)});
397 // If only a bitcode file is asked for by using the
398 // '--emit-llvm' flag, then output it here
399 str::as_c_str(output.to_str(),
400 |buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) );
403 llvm::LLVMDisposeModule(llmod);
404 llvm::LLVMContextDispose(llcx);
405 if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
409 pub fn run_ndk(sess: Session, assembly: &Path, object: &Path) {
410 let cc_prog: ~str = match &sess.opts.android_cross_path {
412 fmt!("%s/bin/arm-linux-androideabi-gcc", *path)
415 sess.fatal("need Android NDK path for building \
416 (--android-cross-path)")
422 ~"-o", object.to_str(),
425 let prog = run::process_output(cc_prog, cc_args);
427 if prog.status != 0 {
428 sess.err(fmt!("building with `%s` failed with code %d",
429 cc_prog, prog.status));
430 sess.note(fmt!("%s arguments: %s",
431 cc_prog, cc_args.connect(" ")));
432 sess.note(str::from_bytes(prog.error + prog.output));
433 sess.abort_if_errors();
440 * Name mangling and its relationship to metadata. This is complex. Read
443 * The semantic model of Rust linkage is, broadly, that "there's no global
444 * namespace" between crates. Our aim is to preserve the illusion of this
445 * model despite the fact that it's not *quite* possible to implement on
446 * modern linkers. We initially didn't use system linkers at all, but have
447 * been convinced of their utility.
449 * There are a few issues to handle:
451 * - Linkers operate on a flat namespace, so we have to flatten names.
452 * We do this using the C++ namespace-mangling technique. Foo::bar
455 * - Symbols with the same name but different types need to get different
456 * linkage-names. We do this by hashing a string-encoding of the type into
457 * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
458 * we use SHA1) to "prevent collisions". This is not airtight but 16 hex
459 * digits on uniform probability means you're going to need 2**32 same-name
460 * symbols in the same process before you're even hitting birthday-paradox
461 * collision probability.
463 * - Symbols in different crates but with same names "within" the crate need
464 * to get different linkage-names.
466 * So here is what we do:
468 * - Separate the meta tags into two sets: exported and local. Only work with
469 * the exported ones when considering linkage.
471 * - Consider two exported tags as special (and mandatory): name and vers.
472 * Every crate gets them; if it doesn't name them explicitly we infer them
473 * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
475 * - Define CMETA as all the non-name, non-vers exported meta tags in the
476 * crate (in sorted order).
478 * - Define CMH as hash(CMETA + hashes of dependent crates).
480 * - Compile our crate to lib CNAME-CMH-CVERS.so
482 * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
484 * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
485 * name, non-name metadata, and type sense, and versioned in the way
486 * system linkers understand.
490 pub fn build_link_meta(sess: Session,
493 symbol_hasher: &mut hash::State)
495 struct ProvidedMetas {
498 cmh_items: ~[@ast::MetaItem]
501 fn provided_link_metas(sess: Session, c: &ast::Crate) ->
505 let mut cmh_items = ~[];
506 let linkage_metas = attr::find_linkage_metas(c.attrs);
507 attr::require_unique_names(sess.diagnostic(), linkage_metas);
508 for linkage_metas.iter().advance |meta| {
509 match meta.name_str_pair() {
510 Some((n, value)) if "name" == n => name = Some(value),
511 Some((n, value)) if "vers" == n => vers = Some(value),
512 _ => cmh_items.push(*meta)
523 // This calculates CMH as defined above
524 fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
525 cmh_items: ~[@ast::MetaItem],
526 dep_hashes: ~[@str]) -> @str {
527 fn len_and_str(s: &str) -> ~str {
528 fmt!("%u_%s", s.len(), s)
531 fn len_and_str_lit(l: ast::lit) -> ~str {
532 len_and_str(pprust::lit_to_str(@l))
535 let cmh_items = attr::sort_meta_items(cmh_items);
537 fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
539 ast::MetaNameValue(key, value) => {
540 write_string(symbol_hasher, len_and_str(key));
541 write_string(symbol_hasher, len_and_str_lit(value));
543 ast::MetaWord(name) => {
544 write_string(symbol_hasher, len_and_str(name));
546 ast::MetaList(name, ref mis) => {
547 write_string(symbol_hasher, len_and_str(name));
548 for mis.iter().advance |m_| {
549 hash(symbol_hasher, m_);
555 symbol_hasher.reset();
556 for cmh_items.iter().advance |m| {
557 hash(symbol_hasher, m);
560 for dep_hashes.iter().advance |dh| {
561 write_string(symbol_hasher, len_and_str(*dh));
564 // tjc: allocation is unfortunate; need to change std::hash
565 return truncated_hash_result(symbol_hasher).to_managed();
568 fn warn_missing(sess: Session, name: &str, default: &str) {
569 if !*sess.building_library { return; }
570 sess.warn(fmt!("missing crate link meta `%s`, using `%s` as default",
574 fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>)
579 // to_managed could go away if there was a version of
580 // filestem that returned an @str
581 let name = session::expect(sess,
583 || fmt!("output file name `%s` doesn't\
584 appear to have a stem",
585 output.to_str())).to_managed();
586 warn_missing(sess, "name", name);
592 fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str {
597 warn_missing(sess, "vers", vers);
607 } = provided_link_metas(sess, c);
608 let name = crate_meta_name(sess, output, opt_name);
609 let vers = crate_meta_vers(sess, opt_vers);
610 let dep_hashes = cstore::get_dep_hashes(sess.cstore);
612 crate_meta_extras_hash(symbol_hasher, cmh_items,
618 extras_hash: extras_hash
622 pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
623 symbol_hasher.result_str()
627 // This calculates STH for a symbol, as defined above
628 pub fn symbol_hash(tcx: ty::ctxt,
629 symbol_hasher: &mut hash::State,
633 // NB: do *not* use abbrevs here as we want the symbol names
634 // to be independent of one another in the crate.
636 symbol_hasher.reset();
637 write_string(symbol_hasher, link_meta.name);
638 write_string(symbol_hasher, "-");
639 write_string(symbol_hasher, link_meta.extras_hash);
640 write_string(symbol_hasher, "-");
641 write_string(symbol_hasher, encoder::encoded_ty(tcx, t));
642 let mut hash = truncated_hash_result(symbol_hasher);
643 // Prefix with _ so that it never blends into adjacent digits
644 hash.unshift_char('_');
645 // tjc: allocation is unfortunate; need to change std::hash
649 pub fn get_symbol_hash(ccx: &mut CrateContext, t: ty::t) -> @str {
650 match ccx.type_hashcodes.find(&t) {
653 let hash = symbol_hash(ccx.tcx, &mut ccx.symbol_hasher, t, ccx.link_meta);
654 ccx.type_hashcodes.insert(t, hash);
661 // Name sanitation. LLVM will happily accept identifiers with weird names, but
663 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
664 pub fn sanitize(s: &str) -> ~str {
665 let mut result = ~"";
666 for s.iter().advance |c| {
668 // Escape these with $ sequences
669 '@' => result.push_str("$SP$"),
670 '~' => result.push_str("$UP$"),
671 '*' => result.push_str("$RP$"),
672 '&' => result.push_str("$BP$"),
673 '<' => result.push_str("$LT$"),
674 '>' => result.push_str("$GT$"),
675 '(' => result.push_str("$LP$"),
676 ')' => result.push_str("$RP$"),
677 ',' => result.push_str("$C$"),
679 // '.' doesn't occur in types and functions, so reuse it
681 ':' => result.push_char('.'),
683 // These are legal symbols
687 | '_' => result.push_char(c),
691 do char::escape_unicode(c) |c| { tstr.push_char(c); }
692 result.push_char('$');
693 result.push_str(tstr.slice_from(1));
698 // Underscore-qualify anything that didn't start as an ident.
699 if result.len() > 0u &&
700 result[0] != '_' as u8 &&
701 ! char::is_XID_start(result[0] as char) {
702 return ~"_" + result;
708 pub fn mangle(sess: Session, ss: path) -> ~str {
709 // Follow C++ namespace-mangling style
711 let mut n = ~"_ZN"; // Begin name-sequence.
713 for ss.iter().advance |s| {
715 path_name(s) | path_mod(s) => {
716 let sani = sanitize(sess.str_of(s));
717 n.push_str(fmt!("%u%s", sani.len(), sani));
721 n.push_char('E'); // End name-sequence.
725 pub fn exported_name(sess: Session,
728 vers: &str) -> ~str {
731 vec::append_one(path, path_name(sess.ident_of(hash))),
732 path_name(sess.ident_of(vers))))
735 pub fn mangle_exported_name(ccx: &mut CrateContext,
738 let hash = get_symbol_hash(ccx, t);
739 return exported_name(ccx.sess, path,
744 pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
746 name: &str) -> ~str {
747 let s = ppaux::ty_to_short_str(ccx.tcx, t);
748 let hash = get_symbol_hash(ccx, t);
749 return mangle(ccx.sess,
750 ~[path_name(ccx.sess.ident_of(name)),
751 path_name(ccx.sess.ident_of(s)),
752 path_name(ccx.sess.ident_of(hash))]);
755 pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
757 name: &str) -> ~str {
758 let s = ppaux::ty_to_str(ccx.tcx, t);
759 let hash = get_symbol_hash(ccx, t);
760 return mangle(ccx.sess,
761 ~[path_name(ccx.sess.ident_of(s)),
762 path_name(ccx.sess.ident_of(hash)),
763 path_name(gensym_name(name))]);
766 pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
768 flav: &str) -> ~str {
769 path.push(path_name(gensym_name(flav)));
770 mangle(ccx.sess, path)
773 pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
774 mangle(ccx.sess, path)
777 pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str {
778 return fmt!("%s_%u", flav, token::gensym(flav));
782 pub fn output_dll_filename(os: session::os, lm: LinkMeta) -> ~str {
783 let (dll_prefix, dll_suffix) = match os {
784 session::os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
785 session::os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
786 session::os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
787 session::os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
788 session::os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
790 fmt!("%s%s-%s-%s%s", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
793 // If the user wants an exe generated we need to invoke
794 // cc to link the object file with some libs
795 pub fn link_binary(sess: Session,
799 // In the future, FreeBSD will use clang as default compiler.
800 // It would be flexible to use cc (system's default C compiler)
801 // instead of hard-coded gcc.
802 // For win32, there is no cc command,
803 // so we add a condition to make it use gcc.
804 let cc_prog: ~str = match sess.opts.linker {
805 Some(ref linker) => linker.to_str(),
806 None => match sess.targ_cfg.os {
807 session::os_android =>
808 match &sess.opts.android_cross_path {
810 fmt!("%s/bin/arm-linux-androideabi-gcc", *path)
813 sess.fatal("need Android NDK path for linking \
814 (--android-cross-path)")
817 session::os_win32 => ~"gcc",
821 // The invocations of cc share some flags across platforms
824 let output = if *sess.building_library {
825 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
826 debug!("link_meta.name: %s", lm.name);
827 debug!("long_libname: %s", long_libname);
828 debug!("out_filename: %s", out_filename.to_str());
829 debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
831 out_filename.dir_path().push(long_libname)
836 debug!("output: %s", output.to_str());
837 let cc_args = link_args(sess, obj_filename, out_filename, lm);
838 debug!("%s link args: %s", cc_prog, cc_args.connect(" "));
840 let prog = run::process_output(cc_prog, cc_args);
841 if 0 != prog.status {
842 sess.err(fmt!("linking with `%s` failed with code %d",
843 cc_prog, prog.status));
844 sess.note(fmt!("%s arguments: %s",
845 cc_prog, cc_args.connect(" ")));
846 sess.note(str::from_bytes(prog.error + prog.output));
847 sess.abort_if_errors();
850 // Clean up on Darwin
851 if sess.targ_cfg.os == session::os_macos {
852 run::process_status("dsymutil", [output.to_str()]);
855 // Remove the temporary object file if we aren't saving temps
856 if !sess.opts.save_temps {
857 if ! os::remove_file(obj_filename) {
858 sess.warn(fmt!("failed to delete object file `%s`",
859 obj_filename.to_str()));
864 pub fn link_args(sess: Session,
867 lm:LinkMeta) -> ~[~str] {
869 // Converts a library file-stem into a cc -l argument
870 fn unlib(config: @session::config, stem: ~str) -> ~str {
871 if stem.starts_with("lib") &&
872 config.os != session::os_win32 {
873 stem.slice(3, stem.len()).to_owned()
880 let output = if *sess.building_library {
881 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
882 out_filename.dir_path().push(long_libname)
887 // The default library location, we need this to find the runtime.
888 // The location of crates will be determined as needed.
889 let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
891 let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
894 ~"-o", output.to_str(),
895 obj_filename.to_str()]);
897 let lib_cmd = match sess.targ_cfg.os {
898 session::os_macos => ~"-dynamiclib",
904 let cstore = sess.cstore;
905 let r = cstore::get_used_crate_files(cstore);
906 for r.iter().advance |cratepath| {
907 if cratepath.filetype() == Some(~".rlib") {
908 args.push(cratepath.to_str());
911 let dir = cratepath.dirname();
912 if dir != ~"" { args.push(~"-L" + dir); }
913 let libarg = unlib(sess.targ_cfg, cratepath.filestem().get());
914 args.push(~"-l" + libarg);
917 let ula = cstore::get_used_link_args(cstore);
918 for ula.iter().advance |arg| { args.push(arg.to_owned()); }
920 // Add all the link args for external crates.
921 do cstore::iter_crate_data(cstore) |crate_num, _| {
922 let link_args = csearch::get_link_args_for_crate(cstore, crate_num);
923 for link_args.consume_iter().advance |link_arg| {
928 // # Extern library linking
930 // User-supplied library search paths (-L on the cammand line) These are
931 // the same paths used to find Rust crates, so some of them may have been
932 // added already by the previous crate linking code. This only allows them
933 // to be found at compile time so it is still entirely up to outside
934 // forces to make sure that library can be found at runtime.
936 for sess.opts.addl_lib_search_paths.iter().advance |path| {
937 args.push(~"-L" + path.to_str());
940 // The names of the extern libraries
941 let used_libs = cstore::get_used_libraries(cstore);
942 for used_libs.iter().advance |l| { args.push(~"-l" + *l); }
944 if *sess.building_library {
947 // On mac we need to tell the linker to let this library
949 if sess.targ_cfg.os == session::os_macos {
950 args.push(~"-Wl,-install_name,@rpath/"
951 + output.filename().get());
955 // On linux librt and libdl are an indirect dependencies via rustrt,
956 // and binutils 2.22+ won't add them automatically
957 if sess.targ_cfg.os == session::os_linux {
958 args.push_all([~"-lrt", ~"-ldl"]);
960 // LLVM implements the `frem` instruction as a call to `fmod`,
961 // which lives in libm. Similar to above, on some linuxes we
962 // have to be explicit about linking to it. See #2510
965 else if sess.targ_cfg.os == session::os_android {
966 args.push_all([~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]);
970 if sess.targ_cfg.os == session::os_freebsd {
971 args.push_all([~"-pthread", ~"-lrt",
972 ~"-L/usr/local/lib", ~"-lexecinfo",
973 ~"-L/usr/local/lib/gcc46",
974 ~"-L/usr/local/lib/gcc44", ~"-lstdc++",
976 ~"-Wl,-rpath,/usr/local/lib/gcc46",
977 ~"-Wl,-rpath,/usr/local/lib/gcc44"]);
980 // OS X 10.6 introduced 'compact unwind info', which is produced by the
981 // linker from the dwarf unwind info. Unfortunately, it does not seem to
982 // understand how to unwind our __morestack frame, so we have to turn it
983 // off. This has impacted some other projects like GHC.
984 if sess.targ_cfg.os == session::os_macos {
985 args.push(~"-Wl,-no_compact_unwind");
988 // Stack growth requires statically linking a __morestack function
989 args.push(~"-lmorestack");
991 // Always want the runtime linked in
992 args.push(~"-lrustrt");
994 // FIXME (#2397): At some point we want to rpath our guesses as to where
995 // extern libraries might live, based on the addl_lib_search_paths
996 args.push_all(rpath::get_rpath_flags(sess, &output));
998 // Finally add all the linker arguments provided on the command line
999 args.push_all(sess.opts.linker_args);