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.
12 use back::archive::Archive;
14 use driver::session::Session;
17 use lib::llvm::ModuleRef;
19 use metadata::common::LinkMeta;
20 use metadata::{encoder, cstore, filesearch, csearch};
21 use middle::trans::context::CrateContext;
22 use middle::trans::common::gensym_name;
26 use std::c_str::ToCStr;
28 use std::hash::Streaming;
30 use std::os::consts::{macos, freebsd, linux, android, win32};
37 use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
39 use syntax::attr::{AttrMetaMethods};
40 use syntax::print::pprust;
42 #[deriving(Clone, Eq)]
43 pub enum output_type {
47 output_type_llvm_assembly,
52 fn write_string<W:Writer>(writer: &mut W, string: &str) {
53 writer.write(string.as_bytes());
56 pub fn llvm_err(sess: Session, msg: ~str) -> ! {
58 let cstr = llvm::LLVMRustGetLastError();
59 if cstr == ptr::null() {
62 sess.fatal(msg + ": " + str::raw::from_c_str(cstr));
67 pub fn WriteOutputFile(
69 Target: lib::llvm::TargetMachineRef,
70 PM: lib::llvm::PassManagerRef,
73 FileType: lib::llvm::FileType) {
75 Output.with_c_str(|Output| {
76 let result = llvm::LLVMRustWriteOutputFile(
77 Target, PM, M, Output, FileType);
79 llvm_err(sess, ~"Could not write output");
87 use back::link::llvm_err;
88 use driver::session::Session;
90 use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
92 use std::c_str::ToCStr;
95 use std::unstable::intrinsics;
98 ee: ExecutionEngineRef,
103 impl Engine for LLVMJITData {}
105 impl Drop for LLVMJITData {
108 llvm::LLVMDisposeExecutionEngine(self.ee);
109 llvm::LLVMContextDispose(self.llcx);
114 pub fn exec(sess: Session,
119 let manager = llvm::LLVMRustPrepareJIT(intrinsics::morestack_addr());
121 // We need to tell JIT where to resolve all linked
122 // symbols from. The equivalent of -lstd, -lcore, etc.
123 // By default the JIT will resolve symbols from the extra and
124 // core linked into rustc. We don't want that,
125 // incase the user wants to use an older extra library.
127 // We custom-build a JIT execution engine via some rust wrappers
128 // first. This wrappers takes ownership of the module passed in.
129 let ee = llvm::LLVMRustBuildJIT(manager, m, stacks);
131 llvm::LLVMContextDispose(c);
132 llvm_err(sess, ~"Could not create the JIT");
135 // Next, we need to get a handle on the _rust_main function by
136 // looking up it's corresponding ValueRef and then requesting that
137 // the execution engine compiles the function.
138 let fun = "_rust_main".with_c_str(|entry| {
139 llvm::LLVMGetNamedFunction(m, entry)
142 llvm::LLVMDisposeExecutionEngine(ee);
143 llvm::LLVMContextDispose(c);
144 llvm_err(sess, ~"Could not find _rust_main in the JIT");
147 // Finally, once we have the pointer to the code, we can do some
148 // closure magic here to turn it straight into a callable rust
150 let code = llvm::LLVMGetPointerToGlobal(ee, fun);
151 assert!(!code.is_null());
152 let func: extern "Rust" fn() = cast::transmute(code);
155 // Currently there is no method of re-using the executing engine
156 // from LLVM in another call to the JIT. While this kinda defeats
157 // the purpose of having a JIT in the first place, there isn't
158 // actually much code currently which would re-use data between
159 // different invocations of this. Additionally, the compilation
160 // model currently isn't designed to support this scenario.
162 // We can't destroy the engine/context immediately here, however,
163 // because of annihilation. The JIT code contains drop glue for any
164 // types defined in the crate we just ran, and if any of those boxes
165 // are going to be dropped during annihilation, the drop glue must
166 // be run. Hence, we need to transfer ownership of this jit engine
167 // to the caller of this function. To be convenient for now, we
168 // shove it into TLS and have someone else remove it later on.
169 let data = ~LLVMJITData { ee: ee, llcx: c };
170 set_engine(data as ~Engine);
174 // The stage1 compiler won't work, but that doesn't really matter. TLS
175 // changed only very recently to allow storage of owned values.
176 local_data_key!(engine_key: ~Engine)
178 fn set_engine(engine: ~Engine) {
179 local_data::set(engine_key, engine)
182 pub fn consume_engine() -> Option<~Engine> {
183 local_data::pop(engine_key)
190 use back::link::{WriteOutputFile, output_type};
191 use back::link::{output_type_assembly, output_type_bitcode};
192 use back::link::{output_type_exe, output_type_llvm_assembly};
193 use back::link::{output_type_object};
194 use driver::session::Session;
197 use lib::llvm::{ModuleRef, ContextRef};
200 use std::c_str::ToCStr;
201 use std::libc::{c_uint, c_int};
206 pub fn run_passes(sess: Session,
209 output_type: output_type,
212 llvm::LLVMInitializePasses();
214 // Only initialize the platforms supported by Rust here, because
215 // using --llvm-root will have multiple platforms that rustllvm
216 // doesn't actually link to and it's pointless to put target info
217 // into the registry that Rust can not generate machine code for.
218 llvm::LLVMInitializeX86TargetInfo();
219 llvm::LLVMInitializeX86Target();
220 llvm::LLVMInitializeX86TargetMC();
221 llvm::LLVMInitializeX86AsmPrinter();
222 llvm::LLVMInitializeX86AsmParser();
224 llvm::LLVMInitializeARMTargetInfo();
225 llvm::LLVMInitializeARMTarget();
226 llvm::LLVMInitializeARMTargetMC();
227 llvm::LLVMInitializeARMAsmPrinter();
228 llvm::LLVMInitializeARMAsmParser();
230 llvm::LLVMInitializeMipsTargetInfo();
231 llvm::LLVMInitializeMipsTarget();
232 llvm::LLVMInitializeMipsTargetMC();
233 llvm::LLVMInitializeMipsAsmPrinter();
234 llvm::LLVMInitializeMipsAsmParser();
236 if sess.opts.save_temps {
237 output.with_extension("no-opt.bc").with_c_str(|buf| {
238 llvm::LLVMWriteBitcodeToFile(llmod, buf);
242 configure_llvm(sess);
244 let OptLevel = match sess.opts.optimize {
245 session::No => lib::llvm::CodeGenLevelNone,
246 session::Less => lib::llvm::CodeGenLevelLess,
247 session::Default => lib::llvm::CodeGenLevelDefault,
248 session::Aggressive => lib::llvm::CodeGenLevelAggressive,
250 let use_softfp = sess.opts.debugging_opts & session::use_softfp != 0;
252 let tm = sess.targ_cfg.target_strs.target_triple.with_c_str(|T| {
253 sess.opts.target_cpu.with_c_str(|CPU| {
254 sess.opts.target_feature.with_c_str(|Features| {
255 llvm::LLVMRustCreateTargetMachine(
257 lib::llvm::CodeModelDefault,
267 // Create the two optimizing pass managers. These mirror what clang
268 // does, and are by populated by LLVM's default PassManagerBuilder.
269 // Each manager has a different set of passes, but they also share
270 // some common passes.
271 let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
272 let mpm = llvm::LLVMCreatePassManager();
274 // If we're verifying or linting, add them to the function pass
276 let addpass = |pass: &str| {
277 pass.with_c_str(|s| llvm::LLVMRustAddPass(fpm, s))
279 if !sess.no_verify() { assert!(addpass("verify")); }
280 if sess.lint_llvm() { assert!(addpass("lint")); }
282 if !sess.no_prepopulate_passes() {
283 llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
284 llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
285 populate_llvm_passes(fpm, mpm, llmod, OptLevel);
288 for pass in sess.opts.custom_passes.iter() {
289 pass.with_c_str(|s| {
290 if !llvm::LLVMRustAddPass(mpm, s) {
291 sess.warn(format!("Unknown pass {}, ignoring", *pass));
296 // Finally, run the actual optimization passes
297 llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
298 llvm::LLVMRunPassManager(mpm, llmod);
300 // Deallocate managers that we're now done with
301 llvm::LLVMDisposePassManager(fpm);
302 llvm::LLVMDisposePassManager(mpm);
304 if sess.opts.save_temps {
305 output.with_extension("bc").with_c_str(|buf| {
306 llvm::LLVMWriteBitcodeToFile(llmod, buf);
311 // If we are using JIT, go ahead and create and execute the
312 // engine now. JIT execution takes ownership of the module and
313 // context, so don't dispose
314 jit::exec(sess, llcx, llmod, true);
316 // Create a codegen-specific pass manager to emit the actual
317 // assembly or object files. This may not end up getting used,
318 // but we make it anyway for good measure.
319 let cpm = llvm::LLVMCreatePassManager();
320 llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
321 llvm::LLVMRustAddLibraryInfo(cpm, llmod);
324 output_type_none => {}
325 output_type_bitcode => {
326 output.with_c_str(|buf| {
327 llvm::LLVMWriteBitcodeToFile(llmod, buf);
330 output_type_llvm_assembly => {
331 output.with_c_str(|output| {
332 llvm::LLVMRustPrintModule(cpm, llmod, output)
335 output_type_assembly => {
336 WriteOutputFile(sess, tm, cpm, llmod, output, lib::llvm::AssemblyFile);
338 output_type_exe | output_type_object => {
339 WriteOutputFile(sess, tm, cpm, llmod, output, lib::llvm::ObjectFile);
343 llvm::LLVMDisposePassManager(cpm);
346 llvm::LLVMRustDisposeTargetMachine(tm);
347 // the jit takes ownership of these two items
349 llvm::LLVMDisposeModule(llmod);
350 llvm::LLVMContextDispose(llcx);
352 if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
356 pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) {
357 let cc = super::get_cc_prog(sess);
359 // FIXME (#9639): This needs to handle non-utf8 paths
362 ~"-o", object.as_str().unwrap().to_owned(),
363 assembly.as_str().unwrap().to_owned()];
365 debug!("{} {}", cc, args.connect(" "));
366 let prog = run::process_output(cc, args);
368 if !prog.status.success() {
369 sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
370 sess.note(format!("{} arguments: {}", cc, args.connect(" ")));
371 sess.note(str::from_utf8(prog.error + prog.output));
372 sess.abort_if_errors();
376 unsafe fn configure_llvm(sess: Session) {
377 // Copy what clan does by turning on loop vectorization at O2 and
378 // slp vectorization at O3
379 let vectorize_loop = !sess.no_vectorize_loops() &&
380 (sess.opts.optimize == session::Default ||
381 sess.opts.optimize == session::Aggressive);
382 let vectorize_slp = !sess.no_vectorize_slp() &&
383 sess.opts.optimize == session::Aggressive;
385 let mut llvm_c_strs = ~[];
386 let mut llvm_args = ~[];
387 let add = |arg: &str| {
388 let s = arg.to_c_str();
389 llvm_args.push(s.with_ref(|p| p));
392 add("rustc"); // fake program name
393 add("-arm-enable-ehabi");
394 add("-arm-enable-ehabi-descriptors");
395 if vectorize_loop { add("-vectorize-loops"); }
396 if vectorize_slp { add("-vectorize-slp"); }
397 if sess.time_llvm_passes() { add("-time-passes"); }
398 if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
400 for arg in sess.opts.llvm_args.iter() {
404 llvm_args.as_imm_buf(|p, len| {
405 llvm::LLVMRustSetLLVMOptions(len as c_int, p);
409 unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
410 mpm: lib::llvm::PassManagerRef,
412 opt: lib::llvm::CodeGenOptLevel) {
413 // Create the PassManagerBuilder for LLVM. We configure it with
414 // reasonable defaults and prepare it to actually populate the pass
416 let builder = llvm::LLVMPassManagerBuilderCreate();
418 lib::llvm::CodeGenLevelNone => {
419 // Don't add lifetime intrinsics add O0
420 llvm::LLVMRustAddAlwaysInlinePass(builder, false);
422 lib::llvm::CodeGenLevelLess => {
423 llvm::LLVMRustAddAlwaysInlinePass(builder, true);
425 // numeric values copied from clang
426 lib::llvm::CodeGenLevelDefault => {
427 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
430 lib::llvm::CodeGenLevelAggressive => {
431 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
435 llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
436 llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
438 // Use the builder to populate the function/module pass managers.
439 llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
440 llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
441 llvm::LLVMPassManagerBuilderDispose(builder);
447 * Name mangling and its relationship to metadata. This is complex. Read
450 * The semantic model of Rust linkage is, broadly, that "there's no global
451 * namespace" between crates. Our aim is to preserve the illusion of this
452 * model despite the fact that it's not *quite* possible to implement on
453 * modern linkers. We initially didn't use system linkers at all, but have
454 * been convinced of their utility.
456 * There are a few issues to handle:
458 * - Linkers operate on a flat namespace, so we have to flatten names.
459 * We do this using the C++ namespace-mangling technique. Foo::bar
462 * - Symbols with the same name but different types need to get different
463 * linkage-names. We do this by hashing a string-encoding of the type into
464 * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
465 * we use SHA1) to "prevent collisions". This is not airtight but 16 hex
466 * digits on uniform probability means you're going to need 2**32 same-name
467 * symbols in the same process before you're even hitting birthday-paradox
468 * collision probability.
470 * - Symbols in different crates but with same names "within" the crate need
471 * to get different linkage-names.
473 * So here is what we do:
475 * - Separate the meta tags into two sets: exported and local. Only work with
476 * the exported ones when considering linkage.
478 * - Consider two exported tags as special (and mandatory): name and vers.
479 * Every crate gets them; if it doesn't name them explicitly we infer them
480 * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
482 * - Define CMETA as all the non-name, non-vers exported meta tags in the
483 * crate (in sorted order).
485 * - Define CMH as hash(CMETA + hashes of dependent crates).
487 * - Compile our crate to lib CNAME-CMH-CVERS.so
489 * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
491 * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
492 * name, non-name metadata, and type sense, and versioned in the way
493 * system linkers understand.
497 pub fn build_link_meta(sess: Session,
500 symbol_hasher: &mut hash::State)
502 struct ProvidedMetas {
505 pkg_id: Option<@str>,
506 cmh_items: ~[@ast::MetaItem]
509 fn provided_link_metas(sess: Session, c: &ast::Crate) ->
513 let mut pkg_id = None;
514 let mut cmh_items = ~[];
515 let linkage_metas = attr::find_linkage_metas(c.attrs);
516 attr::require_unique_names(sess.diagnostic(), linkage_metas);
517 for meta in linkage_metas.iter() {
518 match meta.name_str_pair() {
519 Some((n, value)) if "name" == n => name = Some(value),
520 Some((n, value)) if "vers" == n => vers = Some(value),
521 Some((n, value)) if "package_id" == n => pkg_id = Some(value),
522 _ => cmh_items.push(*meta)
534 // This calculates CMH as defined above
535 fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
536 cmh_items: ~[@ast::MetaItem],
538 pkg_id: Option<@str>) -> @str {
539 fn len_and_str(s: &str) -> ~str {
540 format!("{}_{}", s.len(), s)
543 fn len_and_str_lit(l: ast::lit) -> ~str {
544 len_and_str(pprust::lit_to_str(@l))
547 let cmh_items = attr::sort_meta_items(cmh_items);
549 fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
551 ast::MetaNameValue(key, value) => {
552 write_string(symbol_hasher, len_and_str(key));
553 write_string(symbol_hasher, len_and_str_lit(value));
555 ast::MetaWord(name) => {
556 write_string(symbol_hasher, len_and_str(name));
558 ast::MetaList(name, ref mis) => {
559 write_string(symbol_hasher, len_and_str(name));
560 for m_ in mis.iter() {
561 hash(symbol_hasher, m_);
567 symbol_hasher.reset();
568 for m in cmh_items.iter() {
569 hash(symbol_hasher, m);
572 for dh in dep_hashes.iter() {
573 write_string(symbol_hasher, len_and_str(*dh));
576 for p in pkg_id.iter() {
577 write_string(symbol_hasher, len_and_str(*p));
580 return truncated_hash_result(symbol_hasher).to_managed();
583 fn warn_missing(sess: Session, name: &str, default: &str) {
584 if !*sess.building_library { return; }
585 sess.warn(format!("missing crate link meta `{}`, using `{}` as default",
589 fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>)
592 Some(v) if !v.is_empty() => v,
594 // to_managed could go away if there was a version of
595 // filestem that returned an @str
596 // FIXME (#9639): Non-utf8 filenames will give a misleading error
597 let name = session::expect(sess,
598 output.filestem_str(),
599 || format!("output file name `{}` doesn't\
600 appear to have a stem",
601 output.display())).to_managed();
603 sess.fatal("missing crate link meta `name`, and the \
604 inferred name is blank");
606 warn_missing(sess, "name", name);
612 fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str {
614 Some(v) if !v.is_empty() => v,
617 warn_missing(sess, "vers", vers);
623 fn crate_meta_pkgid(sess: Session, name: @str, opt_pkg_id: Option<@str>)
626 Some(v) if !v.is_empty() => v,
628 let pkg_id = name.clone();
629 warn_missing(sess, "package_id", pkg_id);
640 } = provided_link_metas(sess, c);
641 let name = crate_meta_name(sess, output, opt_name);
642 let vers = crate_meta_vers(sess, opt_vers);
643 let pkg_id = crate_meta_pkgid(sess, name, opt_pkg_id);
644 let dep_hashes = cstore::get_dep_hashes(sess.cstore);
646 crate_meta_extras_hash(symbol_hasher, cmh_items,
647 dep_hashes, Some(pkg_id));
652 package_id: Some(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,
666 link_meta: LinkMeta) -> @str {
667 // NB: do *not* use abbrevs here as we want the symbol names
668 // to be independent of one another in the crate.
670 symbol_hasher.reset();
671 write_string(symbol_hasher, link_meta.name);
672 write_string(symbol_hasher, "-");
673 write_string(symbol_hasher, link_meta.extras_hash);
674 write_string(symbol_hasher, "-");
675 write_string(symbol_hasher, encoder::encoded_ty(tcx, t));
676 let mut hash = truncated_hash_result(symbol_hasher);
677 // Prefix with 'h' so that it never blends into adjacent digits
678 hash.unshift_char('h');
679 // tjc: allocation is unfortunate; need to change std::hash
683 pub fn get_symbol_hash(ccx: &mut CrateContext, t: ty::t) -> @str {
684 match ccx.type_hashcodes.find(&t) {
687 let hash = symbol_hash(ccx.tcx, &mut ccx.symbol_hasher, t, ccx.link_meta);
688 ccx.type_hashcodes.insert(t, hash);
695 // Name sanitation. LLVM will happily accept identifiers with weird names, but
697 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
698 pub fn sanitize(s: &str) -> ~str {
699 let mut result = ~"";
702 // Escape these with $ sequences
703 '@' => result.push_str("$SP$"),
704 '~' => result.push_str("$UP$"),
705 '*' => result.push_str("$RP$"),
706 '&' => result.push_str("$BP$"),
707 '<' => result.push_str("$LT$"),
708 '>' => result.push_str("$GT$"),
709 '(' => result.push_str("$LP$"),
710 ')' => result.push_str("$RP$"),
711 ',' => result.push_str("$C$"),
713 // '.' doesn't occur in types and functions, so reuse it
715 ':' => result.push_char('.'),
717 // These are legal symbols
721 | '_' | '.' | '$' => result.push_char(c),
725 char::escape_unicode(c, |c| tstr.push_char(c));
726 result.push_char('$');
727 result.push_str(tstr.slice_from(1));
732 // Underscore-qualify anything that didn't start as an ident.
733 if result.len() > 0u &&
734 result[0] != '_' as u8 &&
735 ! char::is_XID_start(result[0] as char) {
736 return ~"_" + result;
742 pub fn mangle(sess: Session, ss: path,
743 hash: Option<&str>, vers: Option<&str>) -> ~str {
744 // Follow C++ namespace-mangling style, see
745 // http://en.wikipedia.org/wiki/Name_mangling for more info.
747 // It turns out that on OSX you can actually have arbitrary symbols in
748 // function names (at least when given to LLVM), but this is not possible
749 // when using unix's linker. Perhaps one day when we just a linker from LLVM
750 // we won't need to do this name mangling. The problem with name mangling is
751 // that it seriously limits the available characters. For example we can't
752 // have things like @T or ~[T] in symbol names when one would theoretically
753 // want them for things like impls of traits on that type.
755 // To be able to work on all platforms and get *some* reasonable output, we
756 // use C++ name-mangling.
758 let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested
760 let push = |s: &str| {
761 let sani = sanitize(s);
762 n.push_str(format!("{}{}", sani.len(), sani));
765 // First, connect each component with <len, name> pairs.
768 path_name(s) | path_mod(s) | path_pretty_name(s, _) => {
774 // next, if any identifiers are "pretty" and need extra information tacked
775 // on, then use the hash to generate two unique characters. For now
776 // hopefully 2 characters is enough to avoid collisions.
777 static EXTRA_CHARS: &'static str =
778 "abcdefghijklmnopqrstuvwxyz\
779 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
781 let mut hash = match hash { Some(s) => s.to_owned(), None => ~"" };
784 path_pretty_name(_, extra) => {
785 let hi = (extra >> 32) as u32 as uint;
786 let lo = extra as u32 as uint;
787 hash.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char);
788 hash.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char);
801 n.push_char('E'); // End name-sequence.
805 pub fn exported_name(sess: Session,
808 vers: &str) -> ~str {
809 // The version will get mangled to have a leading '_', but it makes more
810 // sense to lead with a 'v' b/c this is a version...
811 let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) {
817 mangle(sess, path, Some(hash), Some(vers.as_slice()))
820 pub fn mangle_exported_name(ccx: &mut CrateContext,
823 let hash = get_symbol_hash(ccx, t);
824 return exported_name(ccx.sess, path,
829 pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
831 name: &str) -> ~str {
832 let s = ppaux::ty_to_short_str(ccx.tcx, t);
833 let hash = get_symbol_hash(ccx, t);
834 return mangle(ccx.sess,
835 ~[path_name(ccx.sess.ident_of(name)),
836 path_name(ccx.sess.ident_of(s))],
837 Some(hash.as_slice()),
841 pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
843 name: &str) -> ~str {
844 let s = ppaux::ty_to_str(ccx.tcx, t);
845 let hash = get_symbol_hash(ccx, t);
846 let (_, name) = gensym_name(name);
847 return mangle(ccx.sess,
848 ~[path_name(ccx.sess.ident_of(s)), name],
849 Some(hash.as_slice()),
853 pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
855 flav: &str) -> ~str {
856 let (_, name) = gensym_name(flav);
858 mangle(ccx.sess, path, None, None)
861 pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
862 mangle(ccx.sess, path, None, None)
865 pub fn output_lib_filename(lm: LinkMeta) -> ~str {
866 format!("{}-{}-{}", lm.name, lm.extras_hash, lm.vers)
869 pub fn get_cc_prog(sess: Session) -> ~str {
870 match sess.opts.linker {
871 Some(ref linker) => return linker.to_owned(),
875 // In the future, FreeBSD will use clang as default compiler.
876 // It would be flexible to use cc (system's default C compiler)
877 // instead of hard-coded gcc.
878 // For win32, there is no cc command, so we add a condition to make it use
879 // g++. We use g++ rather than gcc because it automatically adds linker
880 // options required for generation of dll modules that correctly register
881 // stack unwind tables.
882 match sess.targ_cfg.os {
883 abi::OsAndroid => match sess.opts.android_cross_path {
884 Some(ref path) => format!("{}/bin/arm-linux-androideabi-gcc", *path),
886 sess.fatal("need Android NDK path for linking \
887 (--android-cross-path)")
890 abi::OsWin32 => ~"g++",
895 /// Perform the linkage portion of the compilation phase. This will generate all
896 /// of the requested outputs for this compilation session.
897 pub fn link_binary(sess: Session,
898 crate_types: &[~str],
902 let outputs = if sess.opts.test {
903 // If we're generating a test executable, then ignore all other output
904 // styles at all other locations
905 ~[session::OutputExecutable]
907 // Always generate whatever was specified on the command line, but also
908 // look at what was in the crate file itself for generating output
910 let mut outputs = sess.opts.outputs.clone();
911 for ty in crate_types.iter() {
913 outputs.push(session::OutputExecutable);
914 } else if "dylib" == *ty || "lib" == *ty {
915 outputs.push(session::OutputDylib);
916 } else if "rlib" == *ty {
917 outputs.push(session::OutputRlib);
918 } else if "staticlib" == *ty {
919 outputs.push(session::OutputStaticlib);
922 if outputs.len() == 0 {
923 outputs.push(session::OutputExecutable);
928 for output in outputs.move_iter() {
929 link_binary_output(sess, output, obj_filename, out_filename, lm);
932 // Remove the temporary object file if we aren't saving temps
933 if !sess.opts.save_temps {
934 fs::unlink(obj_filename);
938 fn is_writeable(p: &Path) -> bool {
941 match io::result(|| p.stat()) {
943 Ok(m) => m.perm & io::UserWrite == io::UserWrite
947 fn link_binary_output(sess: Session,
948 output: session::OutputStyle,
952 let libname = output_lib_filename(lm);
953 let out_filename = match output {
954 session::OutputRlib => {
955 out_filename.with_filename(format!("lib{}.rlib", libname))
957 session::OutputDylib => {
958 let (prefix, suffix) = match sess.targ_cfg.os {
959 abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
960 abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
961 abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
962 abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
963 abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
965 out_filename.with_filename(format!("{}{}{}", prefix, libname, suffix))
967 session::OutputStaticlib => {
968 out_filename.with_filename(format!("lib{}.a", libname))
970 session::OutputExecutable => out_filename.clone(),
973 // Make sure the output and obj_filename are both writeable.
974 // Mac, FreeBSD, and Windows system linkers check this already --
975 // however, the Linux linker will happily overwrite a read-only file.
976 // We should be consistent.
977 let obj_is_writeable = is_writeable(obj_filename);
978 let out_is_writeable = is_writeable(&out_filename);
979 if !out_is_writeable {
980 sess.fatal(format!("Output file {} is not writeable -- check its permissions.",
981 out_filename.display()));
983 else if !obj_is_writeable {
984 sess.fatal(format!("Object file {} is not writeable -- check its permissions.",
985 obj_filename.display()));
989 session::OutputRlib => {
990 link_rlib(sess, obj_filename, &out_filename);
992 session::OutputStaticlib => {
993 link_staticlib(sess, obj_filename, &out_filename);
995 session::OutputExecutable => {
996 link_natively(sess, false, obj_filename, &out_filename);
998 session::OutputDylib => {
999 link_natively(sess, true, obj_filename, &out_filename);
1006 // An rlib in its current incarnation is essentially a renamed .a file. The
1007 // rlib primarily contains the object file of the crate, but it also contains
1008 // all of the object files from native libraries. This is done by unzipping
1009 // native libraries and inserting all of the contents into this archive.
1010 fn link_rlib(sess: Session, obj_filename: &Path,
1011 out_filename: &Path) -> Archive {
1012 let mut a = Archive::create(sess, out_filename, obj_filename);
1013 for &(ref l, kind) in cstore::get_used_libraries(sess.cstore).iter() {
1015 cstore::NativeStatic => {
1016 a.add_native_library(l.as_slice());
1018 cstore::NativeUnknown => {}
1024 // Create a static archive
1026 // This is essentially the same thing as an rlib, but it also involves adding
1027 // all of the upstream crates' objects into the the archive. This will slurp in
1028 // all of the native libraries of upstream dependencies as well.
1030 // Additionally, there's no way for us to link dynamic libraries, so we warn
1031 // about all dynamic library dependencies that they're not linked in.
1032 fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
1033 let mut a = link_rlib(sess, obj_filename, out_filename);
1034 a.add_native_library("morestack");
1036 let crates = cstore::get_used_crates(sess.cstore, cstore::RequireStatic);
1037 for &(cnum, ref path) in crates.iter() {
1038 let p = match *path {
1039 Some(ref p) => p.clone(), None => {
1040 sess.err(format!("could not find rlib for: `{}`",
1041 cstore::get_crate_data(sess.cstore, cnum).name));
1046 let native_libs = csearch::get_native_libraries(sess.cstore, cnum);
1047 for lib in native_libs.iter() {
1048 sess.warn(format!("unlinked native library: {}", *lib));
1053 // Create a dynamic library or executable
1055 // This will invoke the system linker/cc to create the resulting file. This
1056 // links to all upstream files as well.
1057 fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
1058 out_filename: &Path) {
1059 // The invocations of cc share some flags across platforms
1060 let cc_prog = get_cc_prog(sess);
1061 let mut cc_args = sess.targ_cfg.target_strs.cc_args.clone();
1062 cc_args.push_all_move(link_args(sess, dylib, obj_filename, out_filename));
1063 if (sess.opts.debugging_opts & session::print_link_args) != 0 {
1064 println!("{} link args: {}", cc_prog, cc_args.connect(" "));
1067 // May have not found libraries in the right formats.
1068 sess.abort_if_errors();
1070 // Invoke the system linker
1071 debug!("{} {}", cc_prog, cc_args.connect(" "));
1072 let prog = run::process_output(cc_prog, cc_args);
1074 if !prog.status.success() {
1075 sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
1076 sess.note(format!("{} arguments: {}", cc_prog, cc_args.connect(" ")));
1077 sess.note(str::from_utf8(prog.error + prog.output));
1078 sess.abort_if_errors();
1082 // On OSX, debuggers need this utility to get run to do some munging of
1084 if sess.targ_cfg.os == abi::OsMacos && sess.opts.debuginfo {
1085 // FIXME (#9639): This needs to handle non-utf8 paths
1086 run::process_status("dsymutil",
1087 [out_filename.as_str().unwrap().to_owned()]);
1091 fn link_args(sess: Session,
1093 obj_filename: &Path,
1094 out_filename: &Path) -> ~[~str] {
1096 // The default library location, we need this to find the runtime.
1097 // The location of crates will be determined as needed.
1098 // FIXME (#9639): This needs to handle non-utf8 paths
1099 let lib_path = sess.filesearch.get_target_lib_path();
1100 let stage: ~str = ~"-L" + lib_path.as_str().unwrap();
1102 let mut args = ~[stage];
1104 // FIXME (#9639): This needs to handle non-utf8 paths
1106 ~"-o", out_filename.as_str().unwrap().to_owned(),
1107 obj_filename.as_str().unwrap().to_owned()]);
1109 if sess.targ_cfg.os == abi::OsLinux {
1110 // GNU-style linkers will use this to omit linking to libraries which
1111 // don't actually fulfill any relocations, but only for libraries which
1112 // follow this flag. Thus, use it before specifing libraries to link to.
1113 args.push(~"-Wl,--as-needed");
1115 // GNU-style linkers supports optimization with -O. --gc-sections
1116 // removes metadata and potentially other useful things, so don't
1117 // include it. GNU ld doesn't need a numeric argument, but other linkers
1119 if sess.opts.optimize == session::Default ||
1120 sess.opts.optimize == session::Aggressive {
1121 args.push(~"-Wl,-O1");
1125 add_upstream_rust_crates(&mut args, sess, dylib);
1126 add_local_native_libraries(&mut args, sess);
1128 // # Telling the linker what we're doing
1131 // On mac we need to tell the linker to let this library be rpathed
1132 if sess.targ_cfg.os == abi::OsMacos {
1133 args.push(~"-dynamiclib");
1134 args.push(~"-Wl,-dylib");
1135 // FIXME (#9639): This needs to handle non-utf8 paths
1136 args.push(~"-Wl,-install_name,@rpath/" +
1137 out_filename.filename_str().unwrap());
1139 args.push(~"-shared")
1143 if sess.targ_cfg.os == abi::OsFreebsd {
1144 args.push_all([~"-L/usr/local/lib",
1145 ~"-L/usr/local/lib/gcc46",
1146 ~"-L/usr/local/lib/gcc44"]);
1149 // Stack growth requires statically linking a __morestack function
1150 args.push(~"-lmorestack");
1152 // FIXME (#2397): At some point we want to rpath our guesses as to
1153 // where extern libraries might live, based on the
1154 // addl_lib_search_paths
1155 args.push_all(rpath::get_rpath_flags(sess, out_filename));
1157 // Finally add all the linker arguments provided on the command line along
1158 // with any #[link_args] attributes found inside the crate
1159 args.push_all(sess.opts.linker_args);
1160 for arg in cstore::get_used_link_args(sess.cstore).iter() {
1161 args.push(arg.clone());
1166 // # Rust Crate linking
1168 // Rust crates are not considered at all when creating an rlib output. All
1169 // dependencies will be linked when producing the final output (instead of
1170 // the intermediate rlib version)
1171 fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session,
1173 // Converts a library file-stem into a cc -l argument
1174 fn unlib(config: @session::config, stem: &str) -> ~str {
1175 if stem.starts_with("lib") &&
1176 config.os != abi::OsWin32 {
1177 stem.slice(3, stem.len()).to_owned()
1183 let cstore = sess.cstore;
1184 if !dylib && !sess.prefer_dynamic() {
1185 // With an executable, things get a little interesting. As a limitation
1186 // of the current implementation, we require that everything must be
1187 // static, or everything must be dynamic. The reasons for this are a
1188 // little subtle, but as with the above two cases, the goal is to
1189 // prevent duplicate copies of the same library showing up. For example,
1190 // a static immediate dependency might show up as an upstream dynamic
1191 // dependency and we currently have no way of knowing that. We know that
1192 // all dynamic libaries require dynamic dependencies (see above), so
1193 // it's satisfactory to include either all static libraries or all
1194 // dynamic libraries.
1195 let crates = cstore::get_used_crates(cstore,
1196 cstore::RequireStatic);
1197 if crates.iter().all(|&(_, ref p)| p.is_some()) {
1198 for &(cnum, ref path) in crates.iter() {
1199 let cratepath = path.clone().unwrap();
1201 // If we're linking to the static version of the crate, then
1202 // we're mostly good to go. The caveat here is that we need to
1203 // pull in the static crate's native dependencies.
1204 args.push(cratepath.as_str().unwrap().to_owned());
1206 let libs = csearch::get_native_libraries(sess.cstore, cnum);
1207 for lib in libs.iter() {
1208 args.push("-l" + *lib);
1215 // This is a fallback of three differnet cases of linking:
1217 // * When creating a dynamic library, all inputs are required to be dynamic
1219 // * If an executable is created with a preference on dynamic linking, then
1220 // this case is the fallback
1221 // * If an executable is being created, and one of the inputs is missing as
1222 // a static library, then this is the fallback case.
1223 let crates = cstore::get_used_crates(cstore, cstore::RequireDynamic);
1224 for &(cnum, ref path) in crates.iter() {
1225 let cratepath = match *path {
1226 Some(ref p) => p.clone(), None => {
1227 sess.err(format!("could not find dynamic library for: `{}`",
1228 cstore::get_crate_data(sess.cstore, cnum).name));
1232 // Just need to tell the linker about where the library lives and what
1234 let dir = cratepath.dirname_str().unwrap();
1235 if !dir.is_empty() { args.push("-L" + dir); }
1236 let libarg = unlib(sess.targ_cfg, cratepath.filestem_str().unwrap());
1237 args.push("-l" + libarg);
1241 // # Native library linking
1243 // User-supplied library search paths (-L on the cammand line) These are
1244 // the same paths used to find Rust crates, so some of them may have been
1245 // added already by the previous crate linking code. This only allows them
1246 // to be found at compile time so it is still entirely up to outside
1247 // forces to make sure that library can be found at runtime.
1249 // Also note that the native libraries linked here are only the ones located
1250 // in the current crate. Upstream crates with native library dependencies
1251 // may have their native library pulled in above.
1252 fn add_local_native_libraries(args: &mut ~[~str], sess: Session) {
1253 for path in sess.opts.addl_lib_search_paths.iter() {
1254 // FIXME (#9639): This needs to handle non-utf8 paths
1255 args.push("-L" + path.as_str().unwrap().to_owned());
1258 let rustpath = filesearch::rust_path();
1259 for path in rustpath.iter() {
1260 // FIXME (#9639): This needs to handle non-utf8 paths
1261 args.push("-L" + path.as_str().unwrap().to_owned());
1264 for &(ref l, _) in cstore::get_used_libraries(sess.cstore).iter() {
1265 args.push(~"-l" + *l);