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, filesearch};
20 use middle::trans::context::CrateContext;
21 use middle::trans::common::gensym_name;
25 use std::c_str::ToCStr;
27 use std::hash::Streaming;
29 use std::libc::{c_int, c_uint};
30 use std::os::consts::{macos, freebsd, linux, android, win32};
33 use std::rt::io::Writer;
38 use syntax::ast_map::{path, path_mod, path_name};
40 use syntax::attr::{AttrMetaMethods};
41 use syntax::print::pprust;
42 use syntax::parse::token;
44 #[deriving(Clone, Eq)]
45 pub enum output_type {
49 output_type_llvm_assembly,
54 fn write_string<W:Writer>(writer: &mut W, string: &str) {
55 writer.write(string.as_bytes());
58 pub fn llvm_err(sess: Session, msg: ~str) -> ! {
60 let cstr = llvm::LLVMRustGetLastError();
61 if cstr == ptr::null() {
64 sess.fatal(msg + ": " + str::raw::from_c_str(cstr));
69 pub fn WriteOutputFile(sess: Session,
70 PM: lib::llvm::PassManagerRef, M: ModuleRef,
74 // FIXME: When #2334 is fixed, change
78 EnableSegmentedStacks: bool) {
80 do Triple.to_c_str().with_ref |Triple| {
81 do Feature.to_c_str().with_ref |Feature| {
82 do Output.to_c_str().with_ref |Output| {
83 let result = llvm::LLVMRustWriteOutputFile(
91 EnableSegmentedStacks);
93 llvm_err(sess, ~"Could not write output");
103 use back::link::llvm_err;
104 use driver::session::Session;
106 use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
107 use metadata::cstore;
109 use std::c_str::ToCStr;
112 use std::unstable::intrinsics;
115 ee: ExecutionEngineRef,
120 impl Engine for LLVMJITData {}
122 impl Drop for LLVMJITData {
125 llvm::LLVMDisposeExecutionEngine(self.ee);
126 llvm::LLVMContextDispose(self.llcx);
131 pub fn exec(sess: Session,
136 let manager = llvm::LLVMRustPrepareJIT(intrinsics::morestack_addr());
138 // We need to tell JIT where to resolve all linked
139 // symbols from. The equivalent of -lstd, -lcore, etc.
140 // By default the JIT will resolve symbols from the extra and
141 // core linked into rustc. We don't want that,
142 // incase the user wants to use an older extra library.
144 let cstore = sess.cstore;
145 let r = cstore::get_used_crate_files(cstore);
146 for cratepath in r.iter() {
147 let path = cratepath.to_str();
149 debug!("linking: %s", path);
151 do path.to_c_str().with_ref |buf_t| {
152 if !llvm::LLVMRustLoadCrate(manager, buf_t) {
153 llvm_err(sess, ~"Could not link");
155 debug!("linked: %s", path);
159 // We custom-build a JIT execution engine via some rust wrappers
160 // first. This wrappers takes ownership of the module passed in.
161 let ee = llvm::LLVMRustBuildJIT(manager, m, stacks);
163 llvm::LLVMContextDispose(c);
164 llvm_err(sess, ~"Could not create the JIT");
167 // Next, we need to get a handle on the _rust_main function by
168 // looking up it's corresponding ValueRef and then requesting that
169 // the execution engine compiles the function.
170 let fun = do "_rust_main".to_c_str().with_ref |entry| {
171 llvm::LLVMGetNamedFunction(m, entry)
174 llvm::LLVMDisposeExecutionEngine(ee);
175 llvm::LLVMContextDispose(c);
176 llvm_err(sess, ~"Could not find _rust_main in the JIT");
179 // Finally, once we have the pointer to the code, we can do some
180 // closure magic here to turn it straight into a callable rust
182 let code = llvm::LLVMGetPointerToGlobal(ee, fun);
183 assert!(!code.is_null());
184 let func: extern "Rust" fn() = cast::transmute(code);
187 // Currently there is no method of re-using the executing engine
188 // from LLVM in another call to the JIT. While this kinda defeats
189 // the purpose of having a JIT in the first place, there isn't
190 // actually much code currently which would re-use data between
191 // different invocations of this. Additionally, the compilation
192 // model currently isn't designed to support this scenario.
194 // We can't destroy the engine/context immediately here, however,
195 // because of annihilation. The JIT code contains drop glue for any
196 // types defined in the crate we just ran, and if any of those boxes
197 // are going to be dropped during annihilation, the drop glue must
198 // be run. Hence, we need to transfer ownership of this jit engine
199 // to the caller of this function. To be convenient for now, we
200 // shove it into TLS and have someone else remove it later on.
201 let data = ~LLVMJITData { ee: ee, llcx: c };
202 set_engine(data as ~Engine);
206 // The stage1 compiler won't work, but that doesn't really matter. TLS
207 // changed only very recently to allow storage of owned values.
208 static engine_key: local_data::Key<~Engine> = &local_data::Key;
210 fn set_engine(engine: ~Engine) {
211 local_data::set(engine_key, engine)
214 pub fn consume_engine() -> Option<~Engine> {
215 local_data::pop(engine_key)
222 use back::link::{WriteOutputFile, output_type};
223 use back::link::{output_type_assembly, output_type_bitcode};
224 use back::link::{output_type_exe, output_type_llvm_assembly};
225 use back::link::{output_type_object};
226 use driver::session::Session;
229 use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
230 use lib::llvm::{ContextRef};
235 use std::c_str::ToCStr;
236 use std::libc::{c_int, c_uint};
241 pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
243 output_type_assembly | output_type_object | output_type_exe => true,
248 pub fn run_passes(sess: Session,
251 output_type: output_type,
254 llvm::LLVMInitializePasses();
256 let opts = sess.opts;
257 if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
258 let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
259 let pm = mk_pass_manager();
260 llvm::LLVMAddTargetData(td.lltd, pm.llpm);
262 // Generate a pre-optimization intermediate file if -save-temps
266 output_type_bitcode => {
267 if opts.optimize != session::No {
268 let filename = output.with_filetype("no-opt.bc");
269 do filename.to_c_str().with_ref |buf| {
270 llvm::LLVMWriteBitcodeToFile(llmod, buf);
275 let filename = output.with_filetype("bc");
276 do filename.to_c_str().with_ref |buf| {
277 llvm::LLVMWriteBitcodeToFile(llmod, buf);
283 let mut mpm = passes::PassManager::new(td.lltd);
285 if !sess.no_verify() {
286 mpm.add_pass_from_name("verify");
289 let passes = if sess.opts.custom_passes.len() > 0 {
290 sess.opts.custom_passes.clone()
292 if sess.lint_llvm() {
293 mpm.add_pass_from_name("lint");
295 passes::create_standard_passes(opts.optimize)
299 debug!("Passes: %?", passes);
300 passes::populate_pass_manager(sess, &mut mpm, passes);
302 debug!("Running Module Optimization Pass");
306 // If we are using JIT, go ahead and create and execute the
307 // engine now. JIT execution takes ownership of the module and
308 // context, so don't dispose and return.
309 jit::exec(sess, llcx, llmod, true);
311 if sess.time_llvm_passes() {
312 llvm::LLVMRustPrintPassTimings();
315 } else if is_object_or_assembly_or_exe(output_type) {
316 let LLVMOptNone = 0 as c_int; // -O0
317 let LLVMOptLess = 1 as c_int; // -O1
318 let LLVMOptDefault = 2 as c_int; // -O2, -Os
319 let LLVMOptAggressive = 3 as c_int; // -O3
321 let CodeGenOptLevel = match opts.optimize {
322 session::No => LLVMOptNone,
323 session::Less => LLVMOptLess,
324 session::Default => LLVMOptDefault,
325 session::Aggressive => LLVMOptAggressive
328 let FileType = match output_type {
329 output_type_object | output_type_exe => lib::llvm::ObjectFile,
330 _ => lib::llvm::AssemblyFile
333 // Write optimized bitcode if --save-temps was on.
336 // Always output the bitcode file with --save-temps
338 let filename = output.with_filetype("opt.bc");
339 do filename.to_c_str().with_ref |buf| {
340 llvm::LLVMWriteBitcodeToFile(llmod, buf)
342 // Save the assembly file if -S is used
343 if output_type == output_type_assembly {
348 sess.targ_cfg.target_strs.target_triple,
351 lib::llvm::AssemblyFile as c_uint,
356 // Save the object file for -c or --save-temps alone
357 // This .o is needed when an exe is built
358 if output_type == output_type_object ||
359 output_type == output_type_exe {
364 sess.targ_cfg.target_strs.target_triple,
367 lib::llvm::ObjectFile as c_uint,
372 // If we aren't saving temps then just output the file
373 // type corresponding to the '-c' or '-S' flag used
378 sess.targ_cfg.target_strs.target_triple,
385 // Clean up and return
387 llvm::LLVMDisposeModule(llmod);
388 llvm::LLVMContextDispose(llcx);
389 if sess.time_llvm_passes() {
390 llvm::LLVMRustPrintPassTimings();
395 if output_type == output_type_llvm_assembly {
396 // Given options "-S --emit-llvm": output LLVM assembly
397 do output.to_c_str().with_ref |buf_o| {
398 llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o);
401 // If only a bitcode file is asked for by using the
402 // '--emit-llvm' flag, then output it here
403 do output.to_c_str().with_ref |buf| {
404 llvm::LLVMWriteBitcodeToFile(llmod, buf);
408 llvm::LLVMDisposeModule(llmod);
409 llvm::LLVMContextDispose(llcx);
410 if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
414 pub fn run_ndk(sess: Session, assembly: &Path, object: &Path) {
415 let cc_prog: ~str = match &sess.opts.android_cross_path {
417 fmt!("%s/bin/arm-linux-androideabi-gcc", *path)
420 sess.fatal("need Android NDK path for building \
421 (--android-cross-path)")
427 ~"-o", object.to_str(),
430 let prog = run::process_output(cc_prog, cc_args);
432 if prog.status != 0 {
433 sess.err(fmt!("building with `%s` failed with code %d",
434 cc_prog, prog.status));
435 sess.note(fmt!("%s arguments: %s",
436 cc_prog, cc_args.connect(" ")));
437 sess.note(str::from_bytes(prog.error + prog.output));
438 sess.abort_if_errors();
445 * Name mangling and its relationship to metadata. This is complex. Read
448 * The semantic model of Rust linkage is, broadly, that "there's no global
449 * namespace" between crates. Our aim is to preserve the illusion of this
450 * model despite the fact that it's not *quite* possible to implement on
451 * modern linkers. We initially didn't use system linkers at all, but have
452 * been convinced of their utility.
454 * There are a few issues to handle:
456 * - Linkers operate on a flat namespace, so we have to flatten names.
457 * We do this using the C++ namespace-mangling technique. Foo::bar
460 * - Symbols with the same name but different types need to get different
461 * linkage-names. We do this by hashing a string-encoding of the type into
462 * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
463 * we use SHA1) to "prevent collisions". This is not airtight but 16 hex
464 * digits on uniform probability means you're going to need 2**32 same-name
465 * symbols in the same process before you're even hitting birthday-paradox
466 * collision probability.
468 * - Symbols in different crates but with same names "within" the crate need
469 * to get different linkage-names.
471 * So here is what we do:
473 * - Separate the meta tags into two sets: exported and local. Only work with
474 * the exported ones when considering linkage.
476 * - Consider two exported tags as special (and mandatory): name and vers.
477 * Every crate gets them; if it doesn't name them explicitly we infer them
478 * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
480 * - Define CMETA as all the non-name, non-vers exported meta tags in the
481 * crate (in sorted order).
483 * - Define CMH as hash(CMETA + hashes of dependent crates).
485 * - Compile our crate to lib CNAME-CMH-CVERS.so
487 * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
489 * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
490 * name, non-name metadata, and type sense, and versioned in the way
491 * system linkers understand.
495 pub fn build_link_meta(sess: Session,
498 symbol_hasher: &mut hash::State)
500 struct ProvidedMetas {
503 pkg_id: Option<@str>,
504 cmh_items: ~[@ast::MetaItem]
507 fn provided_link_metas(sess: Session, c: &ast::Crate) ->
511 let mut pkg_id = None;
512 let mut cmh_items = ~[];
513 let linkage_metas = attr::find_linkage_metas(c.attrs);
514 attr::require_unique_names(sess.diagnostic(), linkage_metas);
515 for meta in linkage_metas.iter() {
516 match meta.name_str_pair() {
517 Some((n, value)) if "name" == n => name = Some(value),
518 Some((n, value)) if "vers" == n => vers = Some(value),
519 Some((n, value)) if "package_id" == n => pkg_id = Some(value),
520 _ => cmh_items.push(*meta)
532 // This calculates CMH as defined above
533 fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
534 cmh_items: ~[@ast::MetaItem],
536 pkg_id: Option<@str>) -> @str {
537 fn len_and_str(s: &str) -> ~str {
538 fmt!("%u_%s", s.len(), s)
541 fn len_and_str_lit(l: ast::lit) -> ~str {
542 len_and_str(pprust::lit_to_str(@l))
545 let cmh_items = attr::sort_meta_items(cmh_items);
547 fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
549 ast::MetaNameValue(key, value) => {
550 write_string(symbol_hasher, len_and_str(key));
551 write_string(symbol_hasher, len_and_str_lit(value));
553 ast::MetaWord(name) => {
554 write_string(symbol_hasher, len_and_str(name));
556 ast::MetaList(name, ref mis) => {
557 write_string(symbol_hasher, len_and_str(name));
558 for m_ in mis.iter() {
559 hash(symbol_hasher, m_);
565 symbol_hasher.reset();
566 for m in cmh_items.iter() {
567 hash(symbol_hasher, m);
570 for dh in dep_hashes.iter() {
571 write_string(symbol_hasher, len_and_str(*dh));
574 for p in pkg_id.iter() {
575 write_string(symbol_hasher, len_and_str(*p));
578 return truncated_hash_result(symbol_hasher).to_managed();
581 fn warn_missing(sess: Session, name: &str, default: &str) {
582 if !*sess.building_library { return; }
583 sess.warn(fmt!("missing crate link meta `%s`, using `%s` as default",
587 fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>)
592 // to_managed could go away if there was a version of
593 // filestem that returned an @str
594 let name = session::expect(sess,
596 || fmt!("output file name `%s` doesn't\
597 appear to have a stem",
598 output.to_str())).to_managed();
599 warn_missing(sess, "name", name);
605 fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str {
610 warn_missing(sess, "vers", vers);
621 } = provided_link_metas(sess, c);
622 let name = crate_meta_name(sess, output, opt_name);
623 let vers = crate_meta_vers(sess, opt_vers);
624 let dep_hashes = cstore::get_dep_hashes(sess.cstore);
626 crate_meta_extras_hash(symbol_hasher, cmh_items,
627 dep_hashes, opt_pkg_id);
632 package_id: opt_pkg_id,
633 extras_hash: extras_hash
637 pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
638 symbol_hasher.result_str()
642 // This calculates STH for a symbol, as defined above
643 pub fn symbol_hash(tcx: ty::ctxt,
644 symbol_hasher: &mut hash::State,
648 // NB: do *not* use abbrevs here as we want the symbol names
649 // to be independent of one another in the crate.
651 symbol_hasher.reset();
652 write_string(symbol_hasher, link_meta.name);
653 write_string(symbol_hasher, "-");
654 write_string(symbol_hasher, link_meta.extras_hash);
655 write_string(symbol_hasher, "-");
656 write_string(symbol_hasher, encoder::encoded_ty(tcx, t));
657 let mut hash = truncated_hash_result(symbol_hasher);
658 // Prefix with _ so that it never blends into adjacent digits
659 hash.unshift_char('_');
660 // tjc: allocation is unfortunate; need to change std::hash
664 pub fn get_symbol_hash(ccx: &mut CrateContext, t: ty::t) -> @str {
665 match ccx.type_hashcodes.find(&t) {
668 let hash = symbol_hash(ccx.tcx, &mut ccx.symbol_hasher, t, ccx.link_meta);
669 ccx.type_hashcodes.insert(t, hash);
676 // Name sanitation. LLVM will happily accept identifiers with weird names, but
678 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
679 pub fn sanitize(s: &str) -> ~str {
680 let mut result = ~"";
683 // Escape these with $ sequences
684 '@' => result.push_str("$SP$"),
685 '~' => result.push_str("$UP$"),
686 '*' => result.push_str("$RP$"),
687 '&' => result.push_str("$BP$"),
688 '<' => result.push_str("$LT$"),
689 '>' => result.push_str("$GT$"),
690 '(' => result.push_str("$LP$"),
691 ')' => result.push_str("$RP$"),
692 ',' => result.push_str("$C$"),
694 // '.' doesn't occur in types and functions, so reuse it
696 ':' => result.push_char('.'),
698 // These are legal symbols
702 | '_' => result.push_char(c),
706 do char::escape_unicode(c) |c| { tstr.push_char(c); }
707 result.push_char('$');
708 result.push_str(tstr.slice_from(1));
713 // Underscore-qualify anything that didn't start as an ident.
714 if result.len() > 0u &&
715 result[0] != '_' as u8 &&
716 ! char::is_XID_start(result[0] as char) {
717 return ~"_" + result;
723 pub fn mangle(sess: Session, ss: path) -> ~str {
724 // Follow C++ namespace-mangling style
726 let mut n = ~"_ZN"; // Begin name-sequence.
730 path_name(s) | path_mod(s) => {
731 let sani = sanitize(sess.str_of(s));
732 n.push_str(fmt!("%u%s", sani.len(), sani));
736 n.push_char('E'); // End name-sequence.
740 pub fn exported_name(sess: Session,
743 vers: &str) -> ~str {
746 vec::append_one(path, path_name(sess.ident_of(hash))),
747 path_name(sess.ident_of(vers))))
750 pub fn mangle_exported_name(ccx: &mut CrateContext,
753 let hash = get_symbol_hash(ccx, t);
754 return exported_name(ccx.sess, path,
759 pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
761 name: &str) -> ~str {
762 let s = ppaux::ty_to_short_str(ccx.tcx, t);
763 let hash = get_symbol_hash(ccx, t);
764 return mangle(ccx.sess,
765 ~[path_name(ccx.sess.ident_of(name)),
766 path_name(ccx.sess.ident_of(s)),
767 path_name(ccx.sess.ident_of(hash))]);
770 pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
772 name: &str) -> ~str {
773 let s = ppaux::ty_to_str(ccx.tcx, t);
774 let hash = get_symbol_hash(ccx, t);
775 return mangle(ccx.sess,
776 ~[path_name(ccx.sess.ident_of(s)),
777 path_name(ccx.sess.ident_of(hash)),
778 path_name(gensym_name(name))]);
781 pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
783 flav: &str) -> ~str {
784 path.push(path_name(gensym_name(flav)));
785 mangle(ccx.sess, path)
788 pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
789 mangle(ccx.sess, path)
792 pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str {
793 return fmt!("%s_%u", flav, token::gensym(flav));
797 pub fn output_dll_filename(os: session::os, lm: LinkMeta) -> ~str {
798 let (dll_prefix, dll_suffix) = match os {
799 session::os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
800 session::os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
801 session::os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
802 session::os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
803 session::os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
805 fmt!("%s%s-%s-%s%s", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
808 // If the user wants an exe generated we need to invoke
809 // cc to link the object file with some libs
810 pub fn link_binary(sess: Session,
814 // In the future, FreeBSD will use clang as default compiler.
815 // It would be flexible to use cc (system's default C compiler)
816 // instead of hard-coded gcc.
817 // For win32, there is no cc command,
818 // so we add a condition to make it use gcc.
819 let cc_prog: ~str = match sess.opts.linker {
820 Some(ref linker) => linker.to_str(),
821 None => match sess.targ_cfg.os {
822 session::os_android =>
823 match &sess.opts.android_cross_path {
825 fmt!("%s/bin/arm-linux-androideabi-gcc", *path)
828 sess.fatal("need Android NDK path for linking \
829 (--android-cross-path)")
832 session::os_win32 => ~"gcc",
836 // The invocations of cc share some flags across platforms
839 let output = if *sess.building_library {
840 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
841 debug!("link_meta.name: %s", lm.name);
842 debug!("long_libname: %s", long_libname);
843 debug!("out_filename: %s", out_filename.to_str());
844 debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
846 out_filename.dir_path().push(long_libname)
851 debug!("output: %s", output.to_str());
852 let cc_args = link_args(sess, obj_filename, out_filename, lm);
853 debug!("%s link args: %s", cc_prog, cc_args.connect(" "));
855 let prog = run::process_output(cc_prog, cc_args);
856 if 0 != prog.status {
857 sess.err(fmt!("linking with `%s` failed with code %d",
858 cc_prog, prog.status));
859 sess.note(fmt!("%s arguments: %s",
860 cc_prog, cc_args.connect(" ")));
861 sess.note(str::from_bytes(prog.error + prog.output));
862 sess.abort_if_errors();
865 // Clean up on Darwin
866 if sess.targ_cfg.os == session::os_macos {
867 run::process_status("dsymutil", [output.to_str()]);
870 // Remove the temporary object file if we aren't saving temps
871 if !sess.opts.save_temps {
872 if ! os::remove_file(obj_filename) {
873 sess.warn(fmt!("failed to delete object file `%s`",
874 obj_filename.to_str()));
879 pub fn link_args(sess: Session,
882 lm:LinkMeta) -> ~[~str] {
884 // Converts a library file-stem into a cc -l argument
885 fn unlib(config: @session::config, stem: ~str) -> ~str {
886 if stem.starts_with("lib") &&
887 config.os != session::os_win32 {
888 stem.slice(3, stem.len()).to_owned()
895 let output = if *sess.building_library {
896 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
897 out_filename.dir_path().push(long_libname)
902 // The default library location, we need this to find the runtime.
903 // The location of crates will be determined as needed.
904 let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
906 let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
909 ~"-o", output.to_str(),
910 obj_filename.to_str()]);
912 let lib_cmd = match sess.targ_cfg.os {
913 session::os_macos => ~"-dynamiclib",
919 let cstore = sess.cstore;
920 let r = cstore::get_used_crate_files(cstore);
921 for cratepath in r.iter() {
922 if cratepath.filetype() == Some(~".rlib") {
923 args.push(cratepath.to_str());
926 let dir = cratepath.dirname();
927 if dir != ~"" { args.push(~"-L" + dir); }
928 let libarg = unlib(sess.targ_cfg, cratepath.filestem().unwrap());
929 args.push(~"-l" + libarg);
932 let ula = cstore::get_used_link_args(cstore);
933 for arg in ula.iter() { args.push(arg.to_owned()); }
935 // Add all the link args for external crates.
936 do cstore::iter_crate_data(cstore) |crate_num, _| {
937 let link_args = csearch::get_link_args_for_crate(cstore, crate_num);
938 for link_arg in link_args.consume_iter() {
943 // # Extern library linking
945 // User-supplied library search paths (-L on the cammand line) These are
946 // the same paths used to find Rust crates, so some of them may have been
947 // added already by the previous crate linking code. This only allows them
948 // to be found at compile time so it is still entirely up to outside
949 // forces to make sure that library can be found at runtime.
951 for path in sess.opts.addl_lib_search_paths.iter() {
952 args.push(~"-L" + path.to_str());
955 let rustpath = filesearch::rust_path();
956 for path in rustpath.iter() {
957 args.push(~"-L" + path.to_str());
960 // The names of the extern libraries
961 let used_libs = cstore::get_used_libraries(cstore);
962 for l in used_libs.iter() { args.push(~"-l" + *l); }
964 if *sess.building_library {
967 // On mac we need to tell the linker to let this library
969 if sess.targ_cfg.os == session::os_macos {
970 args.push(~"-Wl,-install_name,@rpath/"
971 + output.filename().unwrap());
975 // On linux librt and libdl are an indirect dependencies via rustrt,
976 // and binutils 2.22+ won't add them automatically
977 if sess.targ_cfg.os == session::os_linux {
978 args.push_all([~"-lrt", ~"-ldl"]);
980 // LLVM implements the `frem` instruction as a call to `fmod`,
981 // which lives in libm. Similar to above, on some linuxes we
982 // have to be explicit about linking to it. See #2510
985 else if sess.targ_cfg.os == session::os_android {
986 args.push_all([~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]);
990 if sess.targ_cfg.os == session::os_freebsd {
991 args.push_all([~"-pthread", ~"-lrt",
992 ~"-L/usr/local/lib", ~"-lexecinfo",
993 ~"-L/usr/local/lib/gcc46",
994 ~"-L/usr/local/lib/gcc44", ~"-lstdc++",
996 ~"-Wl,-rpath,/usr/local/lib/gcc46",
997 ~"-Wl,-rpath,/usr/local/lib/gcc44"]);
1000 // OS X 10.6 introduced 'compact unwind info', which is produced by the
1001 // linker from the dwarf unwind info. Unfortunately, it does not seem to
1002 // understand how to unwind our __morestack frame, so we have to turn it
1003 // off. This has impacted some other projects like GHC.
1004 if sess.targ_cfg.os == session::os_macos {
1005 args.push(~"-Wl,-no_compact_unwind");
1008 // Stack growth requires statically linking a __morestack function
1009 args.push(~"-lmorestack");
1011 // Always want the runtime linked in
1012 args.push(~"-lrustrt");
1014 // FIXME (#2397): At some point we want to rpath our guesses as to where
1015 // extern libraries might live, based on the addl_lib_search_paths
1016 args.push_all(rpath::get_rpath_flags(sess, &output));
1018 // Finally add all the linker arguments provided on the command line
1019 args.push_all(sess.opts.linker_args);