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;
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(
71 Target: lib::llvm::TargetMachineRef,
72 PM: lib::llvm::PassManagerRef,
75 FileType: lib::llvm::FileType) {
77 do Output.with_c_str |Output| {
78 let result = llvm::LLVMRustWriteOutputFile(
79 Target, PM, M, Output, FileType);
81 llvm_err(sess, ~"Could not write output");
89 use back::link::llvm_err;
90 use driver::session::Session;
92 use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
95 use std::c_str::ToCStr;
98 use std::unstable::intrinsics;
101 ee: ExecutionEngineRef,
106 impl Engine for LLVMJITData {}
108 impl Drop for LLVMJITData {
111 llvm::LLVMDisposeExecutionEngine(self.ee);
112 llvm::LLVMContextDispose(self.llcx);
117 pub fn exec(sess: Session,
122 let manager = llvm::LLVMRustPrepareJIT(intrinsics::morestack_addr());
124 // We need to tell JIT where to resolve all linked
125 // symbols from. The equivalent of -lstd, -lcore, etc.
126 // By default the JIT will resolve symbols from the extra and
127 // core linked into rustc. We don't want that,
128 // incase the user wants to use an older extra library.
130 let cstore = sess.cstore;
131 let r = cstore::get_used_crate_files(cstore);
132 for cratepath in r.iter() {
133 let path = cratepath.to_str();
135 debug!("linking: %s", path);
137 do path.with_c_str |buf_t| {
138 if !llvm::LLVMRustLoadCrate(manager, buf_t) {
139 llvm_err(sess, ~"Could not link");
141 debug!("linked: %s", path);
145 // We custom-build a JIT execution engine via some rust wrappers
146 // first. This wrappers takes ownership of the module passed in.
147 let ee = llvm::LLVMRustBuildJIT(manager, m, stacks);
149 llvm::LLVMContextDispose(c);
150 llvm_err(sess, ~"Could not create the JIT");
153 // Next, we need to get a handle on the _rust_main function by
154 // looking up it's corresponding ValueRef and then requesting that
155 // the execution engine compiles the function.
156 let fun = do "_rust_main".with_c_str |entry| {
157 llvm::LLVMGetNamedFunction(m, entry)
160 llvm::LLVMDisposeExecutionEngine(ee);
161 llvm::LLVMContextDispose(c);
162 llvm_err(sess, ~"Could not find _rust_main in the JIT");
165 // Finally, once we have the pointer to the code, we can do some
166 // closure magic here to turn it straight into a callable rust
168 let code = llvm::LLVMGetPointerToGlobal(ee, fun);
169 assert!(!code.is_null());
170 let func: extern "Rust" fn() = cast::transmute(code);
173 // Currently there is no method of re-using the executing engine
174 // from LLVM in another call to the JIT. While this kinda defeats
175 // the purpose of having a JIT in the first place, there isn't
176 // actually much code currently which would re-use data between
177 // different invocations of this. Additionally, the compilation
178 // model currently isn't designed to support this scenario.
180 // We can't destroy the engine/context immediately here, however,
181 // because of annihilation. The JIT code contains drop glue for any
182 // types defined in the crate we just ran, and if any of those boxes
183 // are going to be dropped during annihilation, the drop glue must
184 // be run. Hence, we need to transfer ownership of this jit engine
185 // to the caller of this function. To be convenient for now, we
186 // shove it into TLS and have someone else remove it later on.
187 let data = ~LLVMJITData { ee: ee, llcx: c };
188 set_engine(data as ~Engine);
192 // The stage1 compiler won't work, but that doesn't really matter. TLS
193 // changed only very recently to allow storage of owned values.
194 static engine_key: local_data::Key<~Engine> = &local_data::Key;
196 fn set_engine(engine: ~Engine) {
197 local_data::set(engine_key, engine)
200 pub fn consume_engine() -> Option<~Engine> {
201 local_data::pop(engine_key)
208 use back::link::{WriteOutputFile, output_type};
209 use back::link::{output_type_assembly, output_type_bitcode};
210 use back::link::{output_type_exe, output_type_llvm_assembly};
211 use back::link::{output_type_object};
212 use driver::session::Session;
215 use lib::llvm::{ModuleRef, ContextRef};
218 use std::c_str::ToCStr;
219 use std::libc::{c_uint, c_int};
224 pub fn run_passes(sess: Session,
227 output_type: output_type,
230 llvm::LLVMInitializePasses();
232 // Only initialize the platforms supported by Rust here, because
233 // using --llvm-root will have multiple platforms that rustllvm
234 // doesn't actually link to and it's pointless to put target info
235 // into the registry that Rust can not generate machine code for.
236 llvm::LLVMInitializeX86TargetInfo();
237 llvm::LLVMInitializeX86Target();
238 llvm::LLVMInitializeX86TargetMC();
239 llvm::LLVMInitializeX86AsmPrinter();
240 llvm::LLVMInitializeX86AsmParser();
242 llvm::LLVMInitializeARMTargetInfo();
243 llvm::LLVMInitializeARMTarget();
244 llvm::LLVMInitializeARMTargetMC();
245 llvm::LLVMInitializeARMAsmPrinter();
246 llvm::LLVMInitializeARMAsmParser();
248 llvm::LLVMInitializeMipsTargetInfo();
249 llvm::LLVMInitializeMipsTarget();
250 llvm::LLVMInitializeMipsTargetMC();
251 llvm::LLVMInitializeMipsAsmPrinter();
252 llvm::LLVMInitializeMipsAsmParser();
254 if sess.opts.save_temps {
255 do output.with_filetype("no-opt.bc").with_c_str |buf| {
256 llvm::LLVMWriteBitcodeToFile(llmod, buf);
260 configure_llvm(sess);
262 let OptLevel = match sess.opts.optimize {
263 session::No => lib::llvm::CodeGenLevelNone,
264 session::Less => lib::llvm::CodeGenLevelLess,
265 session::Default => lib::llvm::CodeGenLevelDefault,
266 session::Aggressive => lib::llvm::CodeGenLevelAggressive,
269 let tm = do sess.targ_cfg.target_strs.target_triple.with_c_str |T| {
270 do sess.opts.target_cpu.with_c_str |CPU| {
271 do sess.opts.target_feature.with_c_str |Features| {
272 llvm::LLVMRustCreateTargetMachine(
274 lib::llvm::CodeModelDefault,
283 // Create the two optimizing pass managers. These mirror what clang
284 // does, and are by populated by LLVM's default PassManagerBuilder.
285 // Each manager has a different set of passes, but they also share
286 // some common passes.
287 let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
288 let mpm = llvm::LLVMCreatePassManager();
290 // If we're verifying or linting, add them to the function pass
292 let addpass = |pass: &str| {
293 do pass.with_c_str |s| { llvm::LLVMRustAddPass(fpm, s) }
295 if !sess.no_verify() { assert!(addpass("verify")); }
296 if sess.lint_llvm() { assert!(addpass("lint")); }
298 if !sess.no_prepopulate_passes() {
299 llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
300 llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
301 populate_llvm_passess(fpm, mpm, llmod, OptLevel);
304 for pass in sess.opts.custom_passes.iter() {
305 do pass.with_c_str |s| {
306 if !llvm::LLVMRustAddPass(mpm, s) {
307 sess.warn(fmt!("Unknown pass %s, ignoring", *pass));
312 // Finally, run the actual optimization passes
313 llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
314 llvm::LLVMRunPassManager(mpm, llmod);
316 // Deallocate managers that we're now done with
317 llvm::LLVMDisposePassManager(fpm);
318 llvm::LLVMDisposePassManager(mpm);
320 if sess.opts.save_temps {
321 do output.with_filetype("bc").with_c_str |buf| {
322 llvm::LLVMWriteBitcodeToFile(llmod, buf);
327 // If we are using JIT, go ahead and create and execute the
328 // engine now. JIT execution takes ownership of the module and
329 // context, so don't dispose
330 jit::exec(sess, llcx, llmod, true);
332 // Create a codegen-specific pass manager to emit the actual
333 // assembly or object files. This may not end up getting used,
334 // but we make it anyway for good measure.
335 let cpm = llvm::LLVMCreatePassManager();
336 llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
337 llvm::LLVMRustAddLibraryInfo(cpm, llmod);
340 output_type_none => {}
341 output_type_bitcode => {
342 do output.with_c_str |buf| {
343 llvm::LLVMWriteBitcodeToFile(llmod, buf);
346 output_type_llvm_assembly => {
347 do output.with_c_str |output| {
348 llvm::LLVMRustPrintModule(cpm, llmod, output)
351 output_type_assembly => {
352 WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
353 lib::llvm::AssemblyFile);
355 output_type_exe | output_type_object => {
356 WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
357 lib::llvm::ObjectFile);
361 llvm::LLVMDisposePassManager(cpm);
364 llvm::LLVMRustDisposeTargetMachine(tm);
365 // the jit takes ownership of these two items
367 llvm::LLVMDisposeModule(llmod);
368 llvm::LLVMContextDispose(llcx);
370 if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
374 pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) {
375 let cc_prog = super::get_cc_prog(sess);
379 ~"-o", object.to_str(),
382 let prog = run::process_output(cc_prog, cc_args);
384 if prog.status != 0 {
385 sess.err(fmt!("building with `%s` failed with code %d",
386 cc_prog, prog.status));
387 sess.note(fmt!("%s arguments: %s",
388 cc_prog, cc_args.connect(" ")));
389 sess.note(str::from_bytes(prog.error + prog.output));
390 sess.abort_if_errors();
394 unsafe fn configure_llvm(sess: Session) {
395 // Copy what clan does by turning on loop vectorization at O2 and
396 // slp vectorization at O3
397 let vectorize_loop = !sess.no_vectorize_loops() &&
398 (sess.opts.optimize == session::Default ||
399 sess.opts.optimize == session::Aggressive);
400 let vectorize_slp = !sess.no_vectorize_slp() &&
401 sess.opts.optimize == session::Aggressive;
403 let mut llvm_c_strs = ~[];
404 let mut llvm_args = ~[];
405 let add = |arg: &str| {
406 let s = arg.to_c_str();
407 llvm_args.push(s.with_ref(|p| p));
410 add("rustc"); // fake program name
411 add("-arm-enable-ehabi");
412 add("-arm-enable-ehabi-descriptors");
413 if vectorize_loop { add("-vectorize-loops"); }
414 if vectorize_slp { add("-vectorize-slp"); }
415 if sess.time_llvm_passes() { add("-time-passes"); }
416 if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
418 for arg in sess.opts.llvm_args.iter() {
422 do llvm_args.as_imm_buf |p, len| {
423 llvm::LLVMRustSetLLVMOptions(len as c_int, p);
427 unsafe fn populate_llvm_passess(fpm: lib::llvm::PassManagerRef,
428 mpm: lib::llvm::PassManagerRef,
430 opt: lib::llvm::CodeGenOptLevel) {
431 // Create the PassManagerBuilder for LLVM. We configure it with
432 // reasonable defaults and prepare it to actually populate the pass
434 let builder = llvm::LLVMPassManagerBuilderCreate();
436 lib::llvm::CodeGenLevelNone => {
437 // Don't add lifetime intrinsics add O0
438 llvm::LLVMRustAddAlwaysInlinePass(builder, false);
440 lib::llvm::CodeGenLevelLess => {
441 llvm::LLVMRustAddAlwaysInlinePass(builder, true);
443 // numeric values copied from clang
444 lib::llvm::CodeGenLevelDefault => {
445 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
448 lib::llvm::CodeGenLevelAggressive => {
449 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
453 llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
454 llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
456 // Use the builder to populate the function/module pass managers.
457 llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
458 llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
459 llvm::LLVMPassManagerBuilderDispose(builder);
465 * Name mangling and its relationship to metadata. This is complex. Read
468 * The semantic model of Rust linkage is, broadly, that "there's no global
469 * namespace" between crates. Our aim is to preserve the illusion of this
470 * model despite the fact that it's not *quite* possible to implement on
471 * modern linkers. We initially didn't use system linkers at all, but have
472 * been convinced of their utility.
474 * There are a few issues to handle:
476 * - Linkers operate on a flat namespace, so we have to flatten names.
477 * We do this using the C++ namespace-mangling technique. Foo::bar
480 * - Symbols with the same name but different types need to get different
481 * linkage-names. We do this by hashing a string-encoding of the type into
482 * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
483 * we use SHA1) to "prevent collisions". This is not airtight but 16 hex
484 * digits on uniform probability means you're going to need 2**32 same-name
485 * symbols in the same process before you're even hitting birthday-paradox
486 * collision probability.
488 * - Symbols in different crates but with same names "within" the crate need
489 * to get different linkage-names.
491 * So here is what we do:
493 * - Separate the meta tags into two sets: exported and local. Only work with
494 * the exported ones when considering linkage.
496 * - Consider two exported tags as special (and mandatory): name and vers.
497 * Every crate gets them; if it doesn't name them explicitly we infer them
498 * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
500 * - Define CMETA as all the non-name, non-vers exported meta tags in the
501 * crate (in sorted order).
503 * - Define CMH as hash(CMETA + hashes of dependent crates).
505 * - Compile our crate to lib CNAME-CMH-CVERS.so
507 * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
509 * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
510 * name, non-name metadata, and type sense, and versioned in the way
511 * system linkers understand.
515 pub fn build_link_meta(sess: Session,
518 symbol_hasher: &mut hash::State)
520 struct ProvidedMetas {
523 pkg_id: Option<@str>,
524 cmh_items: ~[@ast::MetaItem]
527 fn provided_link_metas(sess: Session, c: &ast::Crate) ->
531 let mut pkg_id = None;
532 let mut cmh_items = ~[];
533 let linkage_metas = attr::find_linkage_metas(c.attrs);
534 attr::require_unique_names(sess.diagnostic(), linkage_metas);
535 for meta in linkage_metas.iter() {
536 match meta.name_str_pair() {
537 Some((n, value)) if "name" == n => name = Some(value),
538 Some((n, value)) if "vers" == n => vers = Some(value),
539 Some((n, value)) if "package_id" == n => pkg_id = Some(value),
540 _ => cmh_items.push(*meta)
552 // This calculates CMH as defined above
553 fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
554 cmh_items: ~[@ast::MetaItem],
556 pkg_id: Option<@str>) -> @str {
557 fn len_and_str(s: &str) -> ~str {
558 fmt!("%u_%s", s.len(), s)
561 fn len_and_str_lit(l: ast::lit) -> ~str {
562 len_and_str(pprust::lit_to_str(@l))
565 let cmh_items = attr::sort_meta_items(cmh_items);
567 fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
569 ast::MetaNameValue(key, value) => {
570 write_string(symbol_hasher, len_and_str(key));
571 write_string(symbol_hasher, len_and_str_lit(value));
573 ast::MetaWord(name) => {
574 write_string(symbol_hasher, len_and_str(name));
576 ast::MetaList(name, ref mis) => {
577 write_string(symbol_hasher, len_and_str(name));
578 for m_ in mis.iter() {
579 hash(symbol_hasher, m_);
585 symbol_hasher.reset();
586 for m in cmh_items.iter() {
587 hash(symbol_hasher, m);
590 for dh in dep_hashes.iter() {
591 write_string(symbol_hasher, len_and_str(*dh));
594 for p in pkg_id.iter() {
595 write_string(symbol_hasher, len_and_str(*p));
598 return truncated_hash_result(symbol_hasher).to_managed();
601 fn warn_missing(sess: Session, name: &str, default: &str) {
602 if !*sess.building_library { return; }
603 sess.warn(fmt!("missing crate link meta `%s`, using `%s` as default",
607 fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>)
612 // to_managed could go away if there was a version of
613 // filestem that returned an @str
614 let name = session::expect(sess,
616 || fmt!("output file name `%s` doesn't\
617 appear to have a stem",
618 output.to_str())).to_managed();
619 warn_missing(sess, "name", name);
625 fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str {
630 warn_missing(sess, "vers", vers);
641 } = provided_link_metas(sess, c);
642 let name = crate_meta_name(sess, output, opt_name);
643 let vers = crate_meta_vers(sess, opt_vers);
644 let dep_hashes = cstore::get_dep_hashes(sess.cstore);
646 crate_meta_extras_hash(symbol_hasher, cmh_items,
647 dep_hashes, opt_pkg_id);
652 package_id: opt_pkg_id,
653 extras_hash: extras_hash
657 pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
658 symbol_hasher.result_str()
662 // This calculates STH for a symbol, as defined above
663 pub fn symbol_hash(tcx: ty::ctxt,
664 symbol_hasher: &mut hash::State,
668 // NB: do *not* use abbrevs here as we want the symbol names
669 // to be independent of one another in the crate.
671 symbol_hasher.reset();
672 write_string(symbol_hasher, link_meta.name);
673 write_string(symbol_hasher, "-");
674 write_string(symbol_hasher, link_meta.extras_hash);
675 write_string(symbol_hasher, "-");
676 write_string(symbol_hasher, encoder::encoded_ty(tcx, t));
677 let mut hash = truncated_hash_result(symbol_hasher);
678 // Prefix with _ so that it never blends into adjacent digits
679 hash.unshift_char('_');
680 // tjc: allocation is unfortunate; need to change std::hash
684 pub fn get_symbol_hash(ccx: &mut CrateContext, t: ty::t) -> @str {
685 match ccx.type_hashcodes.find(&t) {
688 let hash = symbol_hash(ccx.tcx, &mut ccx.symbol_hasher, t, ccx.link_meta);
689 ccx.type_hashcodes.insert(t, hash);
696 // Name sanitation. LLVM will happily accept identifiers with weird names, but
698 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
699 pub fn sanitize(s: &str) -> ~str {
700 let mut result = ~"";
703 // Escape these with $ sequences
704 '@' => result.push_str("$SP$"),
705 '~' => result.push_str("$UP$"),
706 '*' => result.push_str("$RP$"),
707 '&' => result.push_str("$BP$"),
708 '<' => result.push_str("$LT$"),
709 '>' => result.push_str("$GT$"),
710 '(' => result.push_str("$LP$"),
711 ')' => result.push_str("$RP$"),
712 ',' => result.push_str("$C$"),
714 // '.' doesn't occur in types and functions, so reuse it
716 ':' => result.push_char('.'),
718 // These are legal symbols
722 | '_' => result.push_char(c),
726 do char::escape_unicode(c) |c| { tstr.push_char(c); }
727 result.push_char('$');
728 result.push_str(tstr.slice_from(1));
733 // Underscore-qualify anything that didn't start as an ident.
734 if result.len() > 0u &&
735 result[0] != '_' as u8 &&
736 ! char::is_XID_start(result[0] as char) {
737 return ~"_" + result;
743 pub fn mangle(sess: Session, ss: path) -> ~str {
744 // Follow C++ namespace-mangling style
746 let mut n = ~"_ZN"; // Begin name-sequence.
750 path_name(s) | path_mod(s) => {
751 let sani = sanitize(sess.str_of(s));
752 n.push_str(fmt!("%u%s", sani.len(), sani));
756 n.push_char('E'); // End name-sequence.
760 pub fn exported_name(sess: Session,
763 vers: &str) -> ~str {
766 vec::append_one(path, path_name(sess.ident_of(hash))),
767 path_name(sess.ident_of(vers))))
770 pub fn mangle_exported_name(ccx: &mut CrateContext,
773 let hash = get_symbol_hash(ccx, t);
774 return exported_name(ccx.sess, path,
779 pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
781 name: &str) -> ~str {
782 let s = ppaux::ty_to_short_str(ccx.tcx, t);
783 let hash = get_symbol_hash(ccx, t);
784 return mangle(ccx.sess,
785 ~[path_name(ccx.sess.ident_of(name)),
786 path_name(ccx.sess.ident_of(s)),
787 path_name(ccx.sess.ident_of(hash))]);
790 pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
792 name: &str) -> ~str {
793 let s = ppaux::ty_to_str(ccx.tcx, t);
794 let hash = get_symbol_hash(ccx, t);
795 return mangle(ccx.sess,
796 ~[path_name(ccx.sess.ident_of(s)),
797 path_name(ccx.sess.ident_of(hash)),
798 path_name(gensym_name(name))]);
801 pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
803 flav: &str) -> ~str {
804 path.push(path_name(gensym_name(flav)));
805 mangle(ccx.sess, path)
808 pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
809 mangle(ccx.sess, path)
812 pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str {
813 return fmt!("%s_%u", flav, token::gensym(flav));
817 pub fn output_dll_filename(os: session::Os, lm: LinkMeta) -> ~str {
818 let (dll_prefix, dll_suffix) = match os {
819 session::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
820 session::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
821 session::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
822 session::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
823 session::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
825 fmt!("%s%s-%s-%s%s", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
828 pub fn get_cc_prog(sess: Session) -> ~str {
829 // In the future, FreeBSD will use clang as default compiler.
830 // It would be flexible to use cc (system's default C compiler)
831 // instead of hard-coded gcc.
832 // For win32, there is no cc command, so we add a condition to make it use g++.
833 // We use g++ rather than gcc because it automatically adds linker options required
834 // for generation of dll modules that correctly register stack unwind tables.
835 match sess.opts.linker {
836 Some(ref linker) => linker.to_str(),
837 None => match sess.targ_cfg.os {
838 session::OsAndroid =>
839 match &sess.opts.android_cross_path {
841 fmt!("%s/bin/arm-linux-androideabi-gcc", *path)
844 sess.fatal("need Android NDK path for linking \
845 (--android-cross-path)")
848 session::OsWin32 => ~"g++",
854 // If the user wants an exe generated we need to invoke
855 // cc to link the object file with some libs
856 pub fn link_binary(sess: Session,
861 let cc_prog = get_cc_prog(sess);
862 // The invocations of cc share some flags across platforms
864 let output = if *sess.building_library {
865 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
866 debug!("link_meta.name: %s", lm.name);
867 debug!("long_libname: %s", long_libname);
868 debug!("out_filename: %s", out_filename.to_str());
869 debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
871 out_filename.dir_path().push(long_libname)
876 debug!("output: %s", output.to_str());
877 let cc_args = link_args(sess, obj_filename, out_filename, lm);
878 debug!("%s link args: %s", cc_prog, cc_args.connect(" "));
879 if (sess.opts.debugging_opts & session::print_link_args) != 0 {
880 io::println(fmt!("%s link args: %s", cc_prog, cc_args.connect(" ")));
884 let prog = run::process_output(cc_prog, cc_args);
885 if 0 != prog.status {
886 sess.err(fmt!("linking with `%s` failed with code %d",
887 cc_prog, prog.status));
888 sess.note(fmt!("%s arguments: %s",
889 cc_prog, cc_args.connect(" ")));
890 sess.note(str::from_bytes(prog.error + prog.output));
891 sess.abort_if_errors();
894 // Clean up on Darwin
895 if sess.targ_cfg.os == session::OsMacos {
896 run::process_status("dsymutil", [output.to_str()]);
899 // Remove the temporary object file if we aren't saving temps
900 if !sess.opts.save_temps {
901 if ! os::remove_file(obj_filename) {
902 sess.warn(fmt!("failed to delete object file `%s`",
903 obj_filename.to_str()));
908 pub fn link_args(sess: Session,
911 lm:LinkMeta) -> ~[~str] {
913 // Converts a library file-stem into a cc -l argument
914 fn unlib(config: @session::config, stem: ~str) -> ~str {
915 if stem.starts_with("lib") &&
916 config.os != session::OsWin32 {
917 stem.slice(3, stem.len()).to_owned()
924 let output = if *sess.building_library {
925 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
926 out_filename.dir_path().push(long_libname)
931 // The default library location, we need this to find the runtime.
932 // The location of crates will be determined as needed.
933 let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
935 let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
938 ~"-o", output.to_str(),
939 obj_filename.to_str()]);
941 let lib_cmd = match sess.targ_cfg.os {
942 session::OsMacos => ~"-dynamiclib",
948 let cstore = sess.cstore;
949 let r = cstore::get_used_crate_files(cstore);
950 for cratepath in r.iter() {
951 if cratepath.filetype() == Some(~".rlib") {
952 args.push(cratepath.to_str());
955 let dir = cratepath.dirname();
956 if dir != ~"" { args.push(~"-L" + dir); }
957 let libarg = unlib(sess.targ_cfg, cratepath.filestem().unwrap());
958 args.push(~"-l" + libarg);
961 let ula = cstore::get_used_link_args(cstore);
962 for arg in ula.iter() { args.push(arg.to_owned()); }
964 // Add all the link args for external crates.
965 do cstore::iter_crate_data(cstore) |crate_num, _| {
966 let link_args = csearch::get_link_args_for_crate(cstore, crate_num);
967 for link_arg in link_args.move_iter() {
972 // # Extern library linking
974 // User-supplied library search paths (-L on the cammand line) These are
975 // the same paths used to find Rust crates, so some of them may have been
976 // added already by the previous crate linking code. This only allows them
977 // to be found at compile time so it is still entirely up to outside
978 // forces to make sure that library can be found at runtime.
980 for path in sess.opts.addl_lib_search_paths.iter() {
981 args.push(~"-L" + path.to_str());
984 let rustpath = filesearch::rust_path();
985 for path in rustpath.iter() {
986 args.push(~"-L" + path.to_str());
989 // The names of the extern libraries
990 let used_libs = cstore::get_used_libraries(cstore);
991 for l in used_libs.iter() { args.push(~"-l" + *l); }
993 if *sess.building_library {
996 // On mac we need to tell the linker to let this library
998 if sess.targ_cfg.os == session::OsMacos {
999 args.push(~"-Wl,-install_name,@rpath/"
1000 + output.filename().unwrap());
1004 // On linux librt and libdl are an indirect dependencies via rustrt,
1005 // and binutils 2.22+ won't add them automatically
1006 if sess.targ_cfg.os == session::OsLinux {
1007 args.push_all([~"-lrt", ~"-ldl"]);
1009 // LLVM implements the `frem` instruction as a call to `fmod`,
1010 // which lives in libm. Similar to above, on some linuxes we
1011 // have to be explicit about linking to it. See #2510
1014 else if sess.targ_cfg.os == session::OsAndroid {
1015 args.push_all([~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]);
1019 if sess.targ_cfg.os == session::OsFreebsd {
1020 args.push_all([~"-pthread", ~"-lrt",
1021 ~"-L/usr/local/lib", ~"-lexecinfo",
1022 ~"-L/usr/local/lib/gcc46",
1023 ~"-L/usr/local/lib/gcc44", ~"-lstdc++",
1025 ~"-Wl,-rpath,/usr/local/lib/gcc46",
1026 ~"-Wl,-rpath,/usr/local/lib/gcc44"]);
1029 // OS X 10.6 introduced 'compact unwind info', which is produced by the
1030 // linker from the dwarf unwind info. Unfortunately, it does not seem to
1031 // understand how to unwind our __morestack frame, so we have to turn it
1032 // off. This has impacted some other projects like GHC.
1033 if sess.targ_cfg.os == session::OsMacos {
1034 args.push(~"-Wl,-no_compact_unwind");
1037 // Stack growth requires statically linking a __morestack function
1038 args.push(~"-lmorestack");
1040 // Always want the runtime linked in
1041 args.push(~"-lrustrt");
1043 // FIXME (#2397): At some point we want to rpath our guesses as to where
1044 // extern libraries might live, based on the addl_lib_search_paths
1045 args.push_all(rpath::get_rpath_flags(sess, &output));
1047 // Finally add all the linker arguments provided on the command line
1048 args.push_all(sess.opts.linker_args);