]> git.lizzy.rs Git - rust.git/blob - src/librustc/back/link.rs
Add generation of static libraries to rustc
[rust.git] / src / librustc / back / link.rs
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.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 use back::archive::Archive;
13 use back::rpath;
14 use driver::session::Session;
15 use driver::session;
16 use lib::llvm::llvm;
17 use lib::llvm::ModuleRef;
18 use lib;
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;
23 use middle::ty;
24 use util::ppaux;
25
26 use std::c_str::ToCStr;
27 use std::char;
28 use std::hash::Streaming;
29 use std::hash;
30 use std::os::consts::{macos, freebsd, linux, android, win32};
31 use std::ptr;
32 use std::run;
33 use std::str;
34 use std::io::fs;
35 use syntax::abi;
36 use syntax::ast;
37 use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
38 use syntax::attr;
39 use syntax::attr::{AttrMetaMethods};
40 use syntax::print::pprust;
41
42 #[deriving(Clone, Eq)]
43 pub enum output_type {
44     output_type_none,
45     output_type_bitcode,
46     output_type_assembly,
47     output_type_llvm_assembly,
48     output_type_object,
49     output_type_exe,
50 }
51
52 fn write_string<W:Writer>(writer: &mut W, string: &str) {
53     writer.write(string.as_bytes());
54 }
55
56 pub fn llvm_err(sess: Session, msg: ~str) -> ! {
57     unsafe {
58         let cstr = llvm::LLVMRustGetLastError();
59         if cstr == ptr::null() {
60             sess.fatal(msg);
61         } else {
62             sess.fatal(msg + ": " + str::raw::from_c_str(cstr));
63         }
64     }
65 }
66
67 pub fn WriteOutputFile(
68         sess: Session,
69         Target: lib::llvm::TargetMachineRef,
70         PM: lib::llvm::PassManagerRef,
71         M: ModuleRef,
72         Output: &Path,
73         FileType: lib::llvm::FileType) {
74     unsafe {
75         Output.with_c_str(|Output| {
76             let result = llvm::LLVMRustWriteOutputFile(
77                     Target, PM, M, Output, FileType);
78             if !result {
79                 llvm_err(sess, ~"Could not write output");
80             }
81         })
82     }
83 }
84
85 pub mod jit {
86
87     use back::link::llvm_err;
88     use driver::session::Session;
89     use lib::llvm::llvm;
90     use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
91
92     use std::c_str::ToCStr;
93     use std::cast;
94     use std::local_data;
95     use std::unstable::intrinsics;
96
97     struct LLVMJITData {
98         ee: ExecutionEngineRef,
99         llcx: ContextRef
100     }
101
102     pub trait Engine {}
103     impl Engine for LLVMJITData {}
104
105     impl Drop for LLVMJITData {
106         fn drop(&mut self) {
107             unsafe {
108                 llvm::LLVMDisposeExecutionEngine(self.ee);
109                 llvm::LLVMContextDispose(self.llcx);
110             }
111         }
112     }
113
114     pub fn exec(sess: Session,
115                 c: ContextRef,
116                 m: ModuleRef,
117                 stacks: bool) {
118         unsafe {
119             let manager = llvm::LLVMRustPrepareJIT(intrinsics::morestack_addr());
120
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.
126
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);
130             if ee.is_null() {
131                 llvm::LLVMContextDispose(c);
132                 llvm_err(sess, ~"Could not create the JIT");
133             }
134
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)
140             });
141             if fun.is_null() {
142                 llvm::LLVMDisposeExecutionEngine(ee);
143                 llvm::LLVMContextDispose(c);
144                 llvm_err(sess, ~"Could not find _rust_main in the JIT");
145             }
146
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
149             // closure
150             let code = llvm::LLVMGetPointerToGlobal(ee, fun);
151             assert!(!code.is_null());
152             let func: extern "Rust" fn() = cast::transmute(code);
153             func();
154
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.
161             //
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);
171         }
172     }
173
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)
177
178     fn set_engine(engine: ~Engine) {
179         local_data::set(engine_key, engine)
180     }
181
182     pub fn consume_engine() -> Option<~Engine> {
183         local_data::pop(engine_key)
184     }
185 }
186
187 pub mod write {
188
189     use back::link::jit;
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;
195     use driver::session;
196     use lib::llvm::llvm;
197     use lib::llvm::{ModuleRef, ContextRef};
198     use lib;
199
200     use std::c_str::ToCStr;
201     use std::libc::{c_uint, c_int};
202     use std::path::Path;
203     use std::run;
204     use std::str;
205
206     pub fn run_passes(sess: Session,
207                       llcx: ContextRef,
208                       llmod: ModuleRef,
209                       output_type: output_type,
210                       output: &Path) {
211         unsafe {
212             llvm::LLVMInitializePasses();
213
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();
223
224             llvm::LLVMInitializeARMTargetInfo();
225             llvm::LLVMInitializeARMTarget();
226             llvm::LLVMInitializeARMTargetMC();
227             llvm::LLVMInitializeARMAsmPrinter();
228             llvm::LLVMInitializeARMAsmParser();
229
230             llvm::LLVMInitializeMipsTargetInfo();
231             llvm::LLVMInitializeMipsTarget();
232             llvm::LLVMInitializeMipsTargetMC();
233             llvm::LLVMInitializeMipsAsmPrinter();
234             llvm::LLVMInitializeMipsAsmParser();
235
236             if sess.opts.save_temps {
237                 output.with_extension("no-opt.bc").with_c_str(|buf| {
238                     llvm::LLVMWriteBitcodeToFile(llmod, buf);
239                 })
240             }
241
242             configure_llvm(sess);
243
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,
249             };
250             let use_softfp = sess.opts.debugging_opts & session::use_softfp != 0;
251
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(
256                             T, CPU, Features,
257                             lib::llvm::CodeModelDefault,
258                             lib::llvm::RelocPIC,
259                             OptLevel,
260                             true,
261                             use_softfp
262                         )
263                     })
264                 })
265             });
266
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();
273
274             // If we're verifying or linting, add them to the function pass
275             // manager.
276             let addpass = |pass: &str| {
277                 pass.with_c_str(|s| llvm::LLVMRustAddPass(fpm, s))
278             };
279             if !sess.no_verify() { assert!(addpass("verify")); }
280             if sess.lint_llvm()  { assert!(addpass("lint"));   }
281
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);
286             }
287
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));
292                     }
293                 })
294             }
295
296             // Finally, run the actual optimization passes
297             llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
298             llvm::LLVMRunPassManager(mpm, llmod);
299
300             // Deallocate managers that we're now done with
301             llvm::LLVMDisposePassManager(fpm);
302             llvm::LLVMDisposePassManager(mpm);
303
304             if sess.opts.save_temps {
305                 output.with_extension("bc").with_c_str(|buf| {
306                     llvm::LLVMWriteBitcodeToFile(llmod, buf);
307                 })
308             }
309
310             if sess.opts.jit {
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);
315             } else {
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);
322
323                 match output_type {
324                     output_type_none => {}
325                     output_type_bitcode => {
326                         output.with_c_str(|buf| {
327                             llvm::LLVMWriteBitcodeToFile(llmod, buf);
328                         })
329                     }
330                     output_type_llvm_assembly => {
331                         output.with_c_str(|output| {
332                             llvm::LLVMRustPrintModule(cpm, llmod, output)
333                         })
334                     }
335                     output_type_assembly => {
336                         WriteOutputFile(sess, tm, cpm, llmod, output, lib::llvm::AssemblyFile);
337                     }
338                     output_type_exe | output_type_object => {
339                         WriteOutputFile(sess, tm, cpm, llmod, output, lib::llvm::ObjectFile);
340                     }
341                 }
342
343                 llvm::LLVMDisposePassManager(cpm);
344             }
345
346             llvm::LLVMRustDisposeTargetMachine(tm);
347             // the jit takes ownership of these two items
348             if !sess.opts.jit {
349                 llvm::LLVMDisposeModule(llmod);
350                 llvm::LLVMContextDispose(llcx);
351             }
352             if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
353         }
354     }
355
356     pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) {
357         let cc = super::get_cc_prog(sess);
358
359         // FIXME (#9639): This needs to handle non-utf8 paths
360         let args = [
361             ~"-c",
362             ~"-o", object.as_str().unwrap().to_owned(),
363             assembly.as_str().unwrap().to_owned()];
364
365         debug!("{} {}", cc, args.connect(" "));
366         let prog = run::process_output(cc, args);
367
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();
373         }
374     }
375
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;
384
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));
390             llvm_c_strs.push(s);
391         };
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"); }
399
400         for arg in sess.opts.llvm_args.iter() {
401             add(*arg);
402         }
403
404         llvm_args.as_imm_buf(|p, len| {
405             llvm::LLVMRustSetLLVMOptions(len as c_int, p);
406         })
407     }
408
409     unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
410                                    mpm: lib::llvm::PassManagerRef,
411                                    llmod: ModuleRef,
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
415         // manager.
416         let builder = llvm::LLVMPassManagerBuilderCreate();
417         match opt {
418             lib::llvm::CodeGenLevelNone => {
419                 // Don't add lifetime intrinsics add O0
420                 llvm::LLVMRustAddAlwaysInlinePass(builder, false);
421             }
422             lib::llvm::CodeGenLevelLess => {
423                 llvm::LLVMRustAddAlwaysInlinePass(builder, true);
424             }
425             // numeric values copied from clang
426             lib::llvm::CodeGenLevelDefault => {
427                 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
428                                                                     225);
429             }
430             lib::llvm::CodeGenLevelAggressive => {
431                 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
432                                                                     275);
433             }
434         }
435         llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
436         llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
437
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);
442     }
443 }
444
445
446 /*
447  * Name mangling and its relationship to metadata. This is complex. Read
448  * carefully.
449  *
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.
455  *
456  * There are a few issues to handle:
457  *
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
460  *    symbols and such.
461  *
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.
469  *
470  *  - Symbols in different crates but with same names "within" the crate need
471  *    to get different linkage-names.
472  *
473  * So here is what we do:
474  *
475  *  - Separate the meta tags into two sets: exported and local. Only work with
476  *    the exported ones when considering linkage.
477  *
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.
481  *
482  *  - Define CMETA as all the non-name, non-vers exported meta tags in the
483  *    crate (in sorted order).
484  *
485  *  - Define CMH as hash(CMETA + hashes of dependent crates).
486  *
487  *  - Compile our crate to lib CNAME-CMH-CVERS.so
488  *
489  *  - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
490  *
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.
494  *
495  */
496
497 pub fn build_link_meta(sess: Session,
498                        c: &ast::Crate,
499                        output: &Path,
500                        symbol_hasher: &mut hash::State)
501                        -> LinkMeta {
502     struct ProvidedMetas {
503         name: Option<@str>,
504         vers: Option<@str>,
505         pkg_id: Option<@str>,
506         cmh_items: ~[@ast::MetaItem]
507     }
508
509     fn provided_link_metas(sess: Session, c: &ast::Crate) ->
510        ProvidedMetas {
511         let mut name = None;
512         let mut vers = None;
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)
523             }
524         }
525
526         ProvidedMetas {
527             name: name,
528             vers: vers,
529             pkg_id: pkg_id,
530             cmh_items: cmh_items
531         }
532     }
533
534     // This calculates CMH as defined above
535     fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
536                               cmh_items: ~[@ast::MetaItem],
537                               dep_hashes: ~[@str],
538                               pkg_id: Option<@str>) -> @str {
539         fn len_and_str(s: &str) -> ~str {
540             format!("{}_{}", s.len(), s)
541         }
542
543         fn len_and_str_lit(l: ast::lit) -> ~str {
544             len_and_str(pprust::lit_to_str(@l))
545         }
546
547         let cmh_items = attr::sort_meta_items(cmh_items);
548
549         fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
550             match m.node {
551               ast::MetaNameValue(key, value) => {
552                 write_string(symbol_hasher, len_and_str(key));
553                 write_string(symbol_hasher, len_and_str_lit(value));
554               }
555               ast::MetaWord(name) => {
556                 write_string(symbol_hasher, len_and_str(name));
557               }
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_);
562                 }
563               }
564             }
565         }
566
567         symbol_hasher.reset();
568         for m in cmh_items.iter() {
569             hash(symbol_hasher, m);
570         }
571
572         for dh in dep_hashes.iter() {
573             write_string(symbol_hasher, len_and_str(*dh));
574         }
575
576         for p in pkg_id.iter() {
577             write_string(symbol_hasher, len_and_str(*p));
578         }
579
580         return truncated_hash_result(symbol_hasher).to_managed();
581     }
582
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",
586                        name, default));
587     }
588
589     fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>)
590         -> @str {
591         match opt_name {
592             Some(v) if !v.is_empty() => v,
593             _ => {
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();
602                 if name.is_empty() {
603                     sess.fatal("missing crate link meta `name`, and the \
604                                 inferred name is blank");
605                 }
606                 warn_missing(sess, "name", name);
607                 name
608             }
609         }
610     }
611
612     fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str {
613         match opt_vers {
614             Some(v) if !v.is_empty() => v,
615             _ => {
616                 let vers = @"0.0";
617                 warn_missing(sess, "vers", vers);
618                 vers
619             }
620         }
621     }
622
623     fn crate_meta_pkgid(sess: Session, name: @str, opt_pkg_id: Option<@str>)
624         -> @str {
625         match opt_pkg_id {
626             Some(v) if !v.is_empty() => v,
627             _ => {
628                 let pkg_id = name.clone();
629                 warn_missing(sess, "package_id", pkg_id);
630                 pkg_id
631             }
632         }
633     }
634
635     let ProvidedMetas {
636         name: opt_name,
637         vers: opt_vers,
638         pkg_id: opt_pkg_id,
639         cmh_items: cmh_items
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);
645     let extras_hash =
646         crate_meta_extras_hash(symbol_hasher, cmh_items,
647                                dep_hashes, Some(pkg_id));
648
649     LinkMeta {
650         name: name,
651         vers: vers,
652         package_id: Some(pkg_id),
653         extras_hash: extras_hash
654     }
655 }
656
657 pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
658     symbol_hasher.result_str()
659 }
660
661
662 // This calculates STH for a symbol, as defined above
663 pub fn symbol_hash(tcx: ty::ctxt,
664                    symbol_hasher: &mut hash::State,
665                    t: ty::t,
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.
669
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
680     hash.to_managed()
681 }
682
683 pub fn get_symbol_hash(ccx: &mut CrateContext, t: ty::t) -> @str {
684     match ccx.type_hashcodes.find(&t) {
685       Some(&h) => h,
686       None => {
687         let hash = symbol_hash(ccx.tcx, &mut ccx.symbol_hasher, t, ccx.link_meta);
688         ccx.type_hashcodes.insert(t, hash);
689         hash
690       }
691     }
692 }
693
694
695 // Name sanitation. LLVM will happily accept identifiers with weird names, but
696 // gas doesn't!
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 = ~"";
700     for c in s.chars() {
701         match c {
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$"),
712
713             // '.' doesn't occur in types and functions, so reuse it
714             // for ':'
715             ':' => result.push_char('.'),
716
717             // These are legal symbols
718             'a' .. 'z'
719             | 'A' .. 'Z'
720             | '0' .. '9'
721             | '_' | '.' | '$' => result.push_char(c),
722
723             _ => {
724                 let mut tstr = ~"";
725                 char::escape_unicode(c, |c| tstr.push_char(c));
726                 result.push_char('$');
727                 result.push_str(tstr.slice_from(1));
728             }
729         }
730     }
731
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;
737     }
738
739     return result;
740 }
741
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.
746     //
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.
754     //
755     // To be able to work on all platforms and get *some* reasonable output, we
756     // use C++ name-mangling.
757
758     let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested
759
760     let push = |s: &str| {
761         let sani = sanitize(s);
762         n.push_str(format!("{}{}", sani.len(), sani));
763     };
764
765     // First, connect each component with <len, name> pairs.
766     for s in ss.iter() {
767         match *s {
768             path_name(s) | path_mod(s) | path_pretty_name(s, _) => {
769                 push(sess.str_of(s))
770             }
771         }
772     }
773
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\
780          0123456789";
781     let mut hash = match hash { Some(s) => s.to_owned(), None => ~"" };
782     for s in ss.iter() {
783         match *s {
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);
789             }
790             _ => {}
791         }
792     }
793     if hash.len() > 0 {
794         push(hash);
795     }
796     match vers {
797         Some(s) => push(s),
798         None => {}
799     }
800
801     n.push_char('E'); // End name-sequence.
802     n
803 }
804
805 pub fn exported_name(sess: Session,
806                      path: path,
807                      hash: &str,
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)) {
812         "v" + vers
813     } else {
814         vers.to_owned()
815     };
816
817     mangle(sess, path, Some(hash), Some(vers.as_slice()))
818 }
819
820 pub fn mangle_exported_name(ccx: &mut CrateContext,
821                             path: path,
822                             t: ty::t) -> ~str {
823     let hash = get_symbol_hash(ccx, t);
824     return exported_name(ccx.sess, path,
825                          hash,
826                          ccx.link_meta.vers);
827 }
828
829 pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
830                                          t: ty::t,
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()),
838                   None);
839 }
840
841 pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
842                                             t: ty::t,
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()),
850                   None);
851 }
852
853 pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
854                                             mut path: path,
855                                             flav: &str) -> ~str {
856     let (_, name) = gensym_name(flav);
857     path.push(name);
858     mangle(ccx.sess, path, None, None)
859 }
860
861 pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
862     mangle(ccx.sess, path, None, None)
863 }
864
865 pub fn output_lib_filename(lm: LinkMeta) -> ~str {
866     format!("{}-{}-{}", lm.name, lm.extras_hash, lm.vers)
867 }
868
869 pub fn get_cc_prog(sess: Session) -> ~str {
870     match sess.opts.linker {
871         Some(ref linker) => return linker.to_owned(),
872         None => {}
873     }
874
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),
885             None => {
886                 sess.fatal("need Android NDK path for linking \
887                             (--android-cross-path)")
888             }
889         },
890         abi::OsWin32 => ~"g++",
891         _ => ~"cc",
892     }
893 }
894
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],
899                    obj_filename: &Path,
900                    out_filename: &Path,
901                    lm: LinkMeta) {
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]
906     } else {
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
909         // formats.
910         let mut outputs = sess.opts.outputs.clone();
911         for ty in crate_types.iter() {
912             if "bin" == *ty {
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);
920             }
921         }
922         if outputs.len() == 0 {
923             outputs.push(session::OutputExecutable);
924         }
925         outputs
926     };
927
928     for output in outputs.move_iter() {
929         link_binary_output(sess, output, obj_filename, out_filename, lm);
930     }
931
932     // Remove the temporary object file if we aren't saving temps
933     if !sess.opts.save_temps {
934         fs::unlink(obj_filename);
935     }
936 }
937
938 fn is_writeable(p: &Path) -> bool {
939     use std::io;
940
941     match io::result(|| p.stat()) {
942         Err(..) => true,
943         Ok(m) => m.perm & io::UserWrite == io::UserWrite
944     }
945 }
946
947 fn link_binary_output(sess: Session,
948                       output: session::OutputStyle,
949                       obj_filename: &Path,
950                       out_filename: &Path,
951                       lm: LinkMeta) {
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))
956         }
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),
964             };
965             out_filename.with_filename(format!("{}{}{}", prefix, libname, suffix))
966         }
967         session::OutputStaticlib => {
968             out_filename.with_filename(format!("lib{}.a", libname))
969         }
970         session::OutputExecutable => out_filename.clone(),
971     };
972
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()));
982     }
983     else if !obj_is_writeable {
984         sess.fatal(format!("Object file {} is not writeable -- check its permissions.",
985                            obj_filename.display()));
986     }
987
988     match output {
989         session::OutputRlib => {
990             link_rlib(sess, obj_filename, &out_filename);
991         }
992         session::OutputStaticlib => {
993             link_staticlib(sess, obj_filename, &out_filename);
994         }
995         session::OutputExecutable => {
996             link_natively(sess, false, obj_filename, &out_filename);
997         }
998         session::OutputDylib => {
999             link_natively(sess, true, obj_filename, &out_filename);
1000         }
1001     }
1002 }
1003
1004 // Create an 'rlib'
1005 //
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() {
1014         match kind {
1015             cstore::NativeStatic => {
1016                 a.add_native_library(l.as_slice());
1017             }
1018             cstore::NativeUnknown => {}
1019         }
1020     }
1021     return a;
1022 }
1023
1024 // Create a static archive
1025 //
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.
1029 //
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");
1035
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));
1042                 continue
1043             }
1044         };
1045         a.add_rlib(&p);
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));
1049         }
1050     }
1051 }
1052
1053 // Create a dynamic library or executable
1054 //
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(" "));
1065     }
1066
1067     // May have not found libraries in the right formats.
1068     sess.abort_if_errors();
1069
1070     // Invoke the system linker
1071     debug!("{} {}", cc_prog, cc_args.connect(" "));
1072     let prog = run::process_output(cc_prog, cc_args);
1073
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();
1079     }
1080
1081
1082     // On OSX, debuggers need this utility to get run to do some munging of
1083     // the symbols
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()]);
1088     }
1089 }
1090
1091 fn link_args(sess: Session,
1092              dylib: bool,
1093              obj_filename: &Path,
1094              out_filename: &Path) -> ~[~str] {
1095
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();
1101
1102     let mut args = ~[stage];
1103
1104     // FIXME (#9639): This needs to handle non-utf8 paths
1105     args.push_all([
1106         ~"-o", out_filename.as_str().unwrap().to_owned(),
1107         obj_filename.as_str().unwrap().to_owned()]);
1108
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");
1114
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
1118         // do.
1119         if sess.opts.optimize == session::Default ||
1120            sess.opts.optimize == session::Aggressive {
1121             args.push(~"-Wl,-O1");
1122         }
1123     }
1124
1125     add_upstream_rust_crates(&mut args, sess, dylib);
1126     add_local_native_libraries(&mut args, sess);
1127
1128     // # Telling the linker what we're doing
1129
1130     if dylib {
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());
1138         } else {
1139             args.push(~"-shared")
1140         }
1141     }
1142
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"]);
1147     }
1148
1149     // Stack growth requires statically linking a __morestack function
1150     args.push(~"-lmorestack");
1151
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));
1156
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());
1162     }
1163     return args;
1164 }
1165
1166 // # Rust Crate linking
1167 //
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,
1172                             dylib: bool) {
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()
1178         } else {
1179             stem.to_owned()
1180         }
1181     }
1182
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();
1200
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());
1205
1206                 let libs = csearch::get_native_libraries(sess.cstore, cnum);
1207                 for lib in libs.iter() {
1208                     args.push("-l" + *lib);
1209                 }
1210             }
1211             return;
1212         }
1213     }
1214
1215     // This is a fallback of three differnet cases of linking:
1216     //
1217     // * When creating a dynamic library, all inputs are required to be dynamic
1218     //   as well
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));
1229                 return
1230             }
1231         };
1232         // Just need to tell the linker about where the library lives and what
1233         // its name is
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);
1238     }
1239 }
1240
1241 // # Native library linking
1242 //
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.
1248 //
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());
1256     }
1257
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());
1262     }
1263
1264     for &(ref l, _) in cstore::get_used_libraries(sess.cstore).iter() {
1265         args.push(~"-l" + *l);
1266     }
1267 }