]> git.lizzy.rs Git - rust.git/blob - src/librustc/back/link.rs
f9910462db5a2f460415693ae46ae11067c1e49b
[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::rpath;
13 use driver::session::Session;
14 use driver::session;
15 use lib::llvm::llvm;
16 use lib::llvm::ModuleRef;
17 use lib;
18 use metadata::common::LinkMeta;
19 use metadata::{encoder, csearch, cstore};
20 use middle::trans::context::CrateContext;
21 use middle::trans::common::gensym_name;
22 use middle::ty;
23 use util::ppaux;
24
25 use std::char;
26 use std::hash::Streaming;
27 use std::hash;
28 use std::libc::{c_int, c_uint};
29 use std::os::consts::{macos, freebsd, linux, android, win32};
30 use std::os;
31 use std::ptr;
32 use std::rt::io::Writer;
33 use std::run;
34 use std::str;
35 use std::vec;
36 use syntax::ast;
37 use syntax::ast_map::{path, path_mod, path_name};
38 use syntax::attr;
39 use syntax::attr::{AttrMetaMethods};
40 use syntax::print::pprust;
41 use syntax::parse::token;
42
43 #[deriving(Clone, Eq)]
44 pub enum output_type {
45     output_type_none,
46     output_type_bitcode,
47     output_type_assembly,
48     output_type_llvm_assembly,
49     output_type_object,
50     output_type_exe,
51 }
52
53 fn write_string<W:Writer>(writer: &mut W, string: &str) {
54     writer.write(string.as_bytes());
55 }
56
57 pub fn llvm_err(sess: Session, msg: ~str) -> ! {
58     unsafe {
59         let cstr = llvm::LLVMRustGetLastError();
60         if cstr == ptr::null() {
61             sess.fatal(msg);
62         } else {
63             sess.fatal(msg + ": " + str::raw::from_c_str(cstr));
64         }
65     }
66 }
67
68 pub fn WriteOutputFile(sess: Session,
69         PM: lib::llvm::PassManagerRef, M: ModuleRef,
70         Triple: &str,
71         Feature: &str,
72         Output: &str,
73         // FIXME: When #2334 is fixed, change
74         // c_uint to FileType
75         FileType: c_uint,
76         OptLevel: c_int,
77         EnableSegmentedStacks: bool) {
78     unsafe {
79         do str::as_c_str(Triple) |Triple| {
80             do str::as_c_str(Feature) |Feature| {
81                 do str::as_c_str(Output) |Output| {
82                     let result = llvm::LLVMRustWriteOutputFile(
83                             PM,
84                             M,
85                             Triple,
86                             Feature,
87                             Output,
88                             FileType,
89                             OptLevel,
90                             EnableSegmentedStacks);
91                     if (!result) {
92                         llvm_err(sess, ~"Could not write output");
93                     }
94                 }
95             }
96         }
97     }
98 }
99
100 pub mod jit {
101
102     use back::link::llvm_err;
103     use driver::session::Session;
104     use lib::llvm::llvm;
105     use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef};
106     use metadata::cstore;
107
108     use std::cast;
109     use std::local_data;
110     use std::unstable::intrinsics;
111
112     struct LLVMJITData {
113         ee: ExecutionEngineRef,
114         llcx: ContextRef
115     }
116
117     pub trait Engine {}
118     impl Engine for LLVMJITData {}
119
120     impl Drop for LLVMJITData {
121         fn drop(&self) {
122             unsafe {
123                 llvm::LLVMDisposeExecutionEngine(self.ee);
124                 llvm::LLVMContextDispose(self.llcx);
125             }
126         }
127     }
128
129     pub fn exec(sess: Session,
130                 c: ContextRef,
131                 m: ModuleRef,
132                 stacks: bool) {
133         unsafe {
134             let manager = llvm::LLVMRustPrepareJIT(intrinsics::morestack_addr());
135
136             // We need to tell JIT where to resolve all linked
137             // symbols from. The equivalent of -lstd, -lcore, etc.
138             // By default the JIT will resolve symbols from the extra and
139             // core linked into rustc. We don't want that,
140             // incase the user wants to use an older extra library.
141
142             let cstore = sess.cstore;
143             let r = cstore::get_used_crate_files(cstore);
144             for r.iter().advance |cratepath| {
145                 let path = cratepath.to_str();
146
147                 debug!("linking: %s", path);
148
149                 do path.as_c_str |buf_t| {
150                     if !llvm::LLVMRustLoadCrate(manager, buf_t) {
151                         llvm_err(sess, ~"Could not link");
152                     }
153                     debug!("linked: %s", path);
154                 }
155             }
156
157             // We custom-build a JIT execution engine via some rust wrappers
158             // first. This wrappers takes ownership of the module passed in.
159             let ee = llvm::LLVMRustBuildJIT(manager, m, stacks);
160             if ee.is_null() {
161                 llvm::LLVMContextDispose(c);
162                 llvm_err(sess, ~"Could not create the JIT");
163             }
164
165             // Next, we need to get a handle on the _rust_main function by
166             // looking up it's corresponding ValueRef and then requesting that
167             // the execution engine compiles the function.
168             let fun = do "_rust_main".as_c_str |entry| {
169                 llvm::LLVMGetNamedFunction(m, entry)
170             };
171             if fun.is_null() {
172                 llvm::LLVMDisposeExecutionEngine(ee);
173                 llvm::LLVMContextDispose(c);
174                 llvm_err(sess, ~"Could not find _rust_main in the JIT");
175             }
176
177             // Finally, once we have the pointer to the code, we can do some
178             // closure magic here to turn it straight into a callable rust
179             // closure
180             let code = llvm::LLVMGetPointerToGlobal(ee, fun);
181             assert!(!code.is_null());
182             let func: extern "Rust" fn() = cast::transmute(code);
183             func();
184
185             // Currently there is no method of re-using the executing engine
186             // from LLVM in another call to the JIT. While this kinda defeats
187             // the purpose of having a JIT in the first place, there isn't
188             // actually much code currently which would re-use data between
189             // different invocations of this. Additionally, the compilation
190             // model currently isn't designed to support this scenario.
191             //
192             // We can't destroy the engine/context immediately here, however,
193             // because of annihilation. The JIT code contains drop glue for any
194             // types defined in the crate we just ran, and if any of those boxes
195             // are going to be dropped during annihilation, the drop glue must
196             // be run. Hence, we need to transfer ownership of this jit engine
197             // to the caller of this function. To be convenient for now, we
198             // shove it into TLS and have someone else remove it later on.
199             let data = ~LLVMJITData { ee: ee, llcx: c };
200             set_engine(data as ~Engine);
201         }
202     }
203
204     // The stage1 compiler won't work, but that doesn't really matter. TLS
205     // changed only very recently to allow storage of owned values.
206     static engine_key: local_data::Key<~Engine> = &local_data::Key;
207
208     fn set_engine(engine: ~Engine) {
209         local_data::set(engine_key, engine)
210     }
211
212     pub fn consume_engine() -> Option<~Engine> {
213         local_data::pop(engine_key)
214     }
215 }
216
217 pub mod write {
218
219     use back::link::jit;
220     use back::link::{WriteOutputFile, output_type};
221     use back::link::{output_type_assembly, output_type_bitcode};
222     use back::link::{output_type_exe, output_type_llvm_assembly};
223     use back::link::{output_type_object};
224     use driver::session::Session;
225     use driver::session;
226     use lib::llvm::llvm;
227     use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
228     use lib::llvm::{ContextRef};
229     use lib;
230
231     use back::passes;
232
233     use std::libc::{c_int, c_uint};
234     use std::path::Path;
235     use std::run;
236     use std::str;
237
238     pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
239         match ot {
240             output_type_assembly | output_type_object | output_type_exe => true,
241             _ => false
242         }
243     }
244
245     pub fn run_passes(sess: Session,
246                       llcx: ContextRef,
247                       llmod: ModuleRef,
248                       output_type: output_type,
249                       output: &Path) {
250         unsafe {
251             llvm::LLVMInitializePasses();
252
253             let opts = sess.opts;
254             if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
255             let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
256             let pm = mk_pass_manager();
257             llvm::LLVMAddTargetData(td.lltd, pm.llpm);
258
259             // Generate a pre-optimization intermediate file if -save-temps
260             // was specified.
261             if opts.save_temps {
262                 match output_type {
263                   output_type_bitcode => {
264                     if opts.optimize != session::No {
265                         let filename = output.with_filetype("no-opt.bc");
266                         str::as_c_str(filename.to_str(), |buf| {
267                             llvm::LLVMWriteBitcodeToFile(llmod, buf)
268                         });
269                     }
270                   }
271                   _ => {
272                     let filename = output.with_filetype("bc");
273                     str::as_c_str(filename.to_str(), |buf| {
274                         llvm::LLVMWriteBitcodeToFile(llmod, buf)
275                     });
276                   }
277                 }
278             }
279
280             let mut mpm = passes::PassManager::new(td.lltd);
281
282             if !sess.no_verify() {
283                 mpm.add_pass_from_name("verify");
284             }
285
286             let passes = if sess.opts.custom_passes.len() > 0 {
287                 sess.opts.custom_passes.clone()
288             } else {
289                 if sess.lint_llvm() {
290                     mpm.add_pass_from_name("lint");
291                 }
292                 passes::create_standard_passes(opts.optimize)
293             };
294
295
296             debug!("Passes: %?", passes);
297             passes::populate_pass_manager(sess, &mut mpm, passes);
298
299             debug!("Running Module Optimization Pass");
300             mpm.run(llmod);
301
302             if opts.jit {
303                 // If we are using JIT, go ahead and create and execute the
304                 // engine now.  JIT execution takes ownership of the module and
305                 // context, so don't dispose and return.
306                 jit::exec(sess, llcx, llmod, true);
307
308                 if sess.time_llvm_passes() {
309                     llvm::LLVMRustPrintPassTimings();
310                 }
311                 return;
312             } else if is_object_or_assembly_or_exe(output_type) {
313                 let LLVMOptNone       = 0 as c_int; // -O0
314                 let LLVMOptLess       = 1 as c_int; // -O1
315                 let LLVMOptDefault    = 2 as c_int; // -O2, -Os
316                 let LLVMOptAggressive = 3 as c_int; // -O3
317
318                 let CodeGenOptLevel = match opts.optimize {
319                   session::No => LLVMOptNone,
320                   session::Less => LLVMOptLess,
321                   session::Default => LLVMOptDefault,
322                   session::Aggressive => LLVMOptAggressive
323                 };
324
325                 let FileType = match output_type {
326                     output_type_object | output_type_exe => lib::llvm::ObjectFile,
327                     _ => lib::llvm::AssemblyFile
328                 };
329
330                 // Write optimized bitcode if --save-temps was on.
331
332                 if opts.save_temps {
333                     // Always output the bitcode file with --save-temps
334
335                     let filename = output.with_filetype("opt.bc");
336                     str::as_c_str(filename.to_str(), |buf| {
337                         llvm::LLVMWriteBitcodeToFile(llmod, buf)
338                     });
339                     // Save the assembly file if -S is used
340                     if output_type == output_type_assembly {
341                         WriteOutputFile(
342                             sess,
343                             pm.llpm,
344                             llmod,
345                             sess.targ_cfg.target_strs.target_triple,
346                             opts.target_feature,
347                             output.to_str(),
348                             lib::llvm::AssemblyFile as c_uint,
349                             CodeGenOptLevel,
350                             true);
351                     }
352
353                     // Save the object file for -c or --save-temps alone
354                     // This .o is needed when an exe is built
355                     if output_type == output_type_object ||
356                            output_type == output_type_exe {
357                         WriteOutputFile(
358                             sess,
359                             pm.llpm,
360                             llmod,
361                             sess.targ_cfg.target_strs.target_triple,
362                             opts.target_feature,
363                             output.to_str(),
364                             lib::llvm::ObjectFile as c_uint,
365                             CodeGenOptLevel,
366                             true);
367                     }
368                 } else {
369                     // If we aren't saving temps then just output the file
370                     // type corresponding to the '-c' or '-S' flag used
371                     WriteOutputFile(
372                         sess,
373                         pm.llpm,
374                         llmod,
375                         sess.targ_cfg.target_strs.target_triple,
376                         opts.target_feature,
377                         output.to_str(),
378                         FileType as c_uint,
379                         CodeGenOptLevel,
380                         true);
381                 }
382                 // Clean up and return
383
384                 llvm::LLVMDisposeModule(llmod);
385                 llvm::LLVMContextDispose(llcx);
386                 if sess.time_llvm_passes() {
387                     llvm::LLVMRustPrintPassTimings();
388                 }
389                 return;
390             }
391
392             if output_type == output_type_llvm_assembly {
393                 // Given options "-S --emit-llvm": output LLVM assembly
394                 str::as_c_str(output.to_str(), |buf_o| {
395                     llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o)});
396             } else {
397                 // If only a bitcode file is asked for by using the
398                 // '--emit-llvm' flag, then output it here
399                 str::as_c_str(output.to_str(),
400                             |buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) );
401             }
402
403             llvm::LLVMDisposeModule(llmod);
404             llvm::LLVMContextDispose(llcx);
405             if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
406         }
407     }
408
409     pub fn run_ndk(sess: Session, assembly: &Path, object: &Path) {
410         let cc_prog: ~str = match &sess.opts.android_cross_path {
411             &Some(ref path) => {
412                 fmt!("%s/bin/arm-linux-androideabi-gcc", *path)
413             }
414             &None => {
415                 sess.fatal("need Android NDK path for building \
416                             (--android-cross-path)")
417             }
418         };
419
420         let cc_args = ~[
421             ~"-c",
422             ~"-o", object.to_str(),
423             assembly.to_str()];
424
425         let prog = run::process_output(cc_prog, cc_args);
426
427         if prog.status != 0 {
428             sess.err(fmt!("building with `%s` failed with code %d",
429                         cc_prog, prog.status));
430             sess.note(fmt!("%s arguments: %s",
431                         cc_prog, cc_args.connect(" ")));
432             sess.note(str::from_bytes(prog.error + prog.output));
433             sess.abort_if_errors();
434         }
435     }
436 }
437
438
439 /*
440  * Name mangling and its relationship to metadata. This is complex. Read
441  * carefully.
442  *
443  * The semantic model of Rust linkage is, broadly, that "there's no global
444  * namespace" between crates. Our aim is to preserve the illusion of this
445  * model despite the fact that it's not *quite* possible to implement on
446  * modern linkers. We initially didn't use system linkers at all, but have
447  * been convinced of their utility.
448  *
449  * There are a few issues to handle:
450  *
451  *  - Linkers operate on a flat namespace, so we have to flatten names.
452  *    We do this using the C++ namespace-mangling technique. Foo::bar
453  *    symbols and such.
454  *
455  *  - Symbols with the same name but different types need to get different
456  *    linkage-names. We do this by hashing a string-encoding of the type into
457  *    a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
458  *    we use SHA1) to "prevent collisions". This is not airtight but 16 hex
459  *    digits on uniform probability means you're going to need 2**32 same-name
460  *    symbols in the same process before you're even hitting birthday-paradox
461  *    collision probability.
462  *
463  *  - Symbols in different crates but with same names "within" the crate need
464  *    to get different linkage-names.
465  *
466  * So here is what we do:
467  *
468  *  - Separate the meta tags into two sets: exported and local. Only work with
469  *    the exported ones when considering linkage.
470  *
471  *  - Consider two exported tags as special (and mandatory): name and vers.
472  *    Every crate gets them; if it doesn't name them explicitly we infer them
473  *    as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
474  *
475  *  - Define CMETA as all the non-name, non-vers exported meta tags in the
476  *    crate (in sorted order).
477  *
478  *  - Define CMH as hash(CMETA + hashes of dependent crates).
479  *
480  *  - Compile our crate to lib CNAME-CMH-CVERS.so
481  *
482  *  - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
483  *
484  *  - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
485  *    name, non-name metadata, and type sense, and versioned in the way
486  *    system linkers understand.
487  *
488  */
489
490 pub fn build_link_meta(sess: Session,
491                        c: &ast::Crate,
492                        output: &Path,
493                        symbol_hasher: &mut hash::State)
494                        -> LinkMeta {
495     struct ProvidedMetas {
496         name: Option<@str>,
497         vers: Option<@str>,
498         cmh_items: ~[@ast::MetaItem]
499     }
500
501     fn provided_link_metas(sess: Session, c: &ast::Crate) ->
502        ProvidedMetas {
503         let mut name = None;
504         let mut vers = None;
505         let mut cmh_items = ~[];
506         let linkage_metas = attr::find_linkage_metas(c.attrs);
507         attr::require_unique_names(sess.diagnostic(), linkage_metas);
508         for linkage_metas.iter().advance |meta| {
509             match meta.name_str_pair() {
510                 Some((n, value)) if "name" == n => name = Some(value),
511                 Some((n, value)) if "vers" == n => vers = Some(value),
512                 _ => cmh_items.push(*meta)
513             }
514         }
515
516         ProvidedMetas {
517             name: name,
518             vers: vers,
519             cmh_items: cmh_items
520         }
521     }
522
523     // This calculates CMH as defined above
524     fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
525                               cmh_items: ~[@ast::MetaItem],
526                               dep_hashes: ~[@str]) -> @str {
527         fn len_and_str(s: &str) -> ~str {
528             fmt!("%u_%s", s.len(), s)
529         }
530
531         fn len_and_str_lit(l: ast::lit) -> ~str {
532             len_and_str(pprust::lit_to_str(@l))
533         }
534
535         let cmh_items = attr::sort_meta_items(cmh_items);
536
537         fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
538             match m.node {
539               ast::MetaNameValue(key, value) => {
540                 write_string(symbol_hasher, len_and_str(key));
541                 write_string(symbol_hasher, len_and_str_lit(value));
542               }
543               ast::MetaWord(name) => {
544                 write_string(symbol_hasher, len_and_str(name));
545               }
546               ast::MetaList(name, ref mis) => {
547                 write_string(symbol_hasher, len_and_str(name));
548                 for mis.iter().advance |m_| {
549                     hash(symbol_hasher, m_);
550                 }
551               }
552             }
553         }
554
555         symbol_hasher.reset();
556         for cmh_items.iter().advance |m| {
557             hash(symbol_hasher, m);
558         }
559
560         for dep_hashes.iter().advance |dh| {
561             write_string(symbol_hasher, len_and_str(*dh));
562         }
563
564     // tjc: allocation is unfortunate; need to change std::hash
565         return truncated_hash_result(symbol_hasher).to_managed();
566     }
567
568     fn warn_missing(sess: Session, name: &str, default: &str) {
569         if !*sess.building_library { return; }
570         sess.warn(fmt!("missing crate link meta `%s`, using `%s` as default",
571                        name, default));
572     }
573
574     fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>)
575         -> @str {
576         match opt_name {
577             Some(v) => v,
578             None => {
579                 // to_managed could go away if there was a version of
580                 // filestem that returned an @str
581                 let name = session::expect(sess,
582                                            output.filestem(),
583                                            || fmt!("output file name `%s` doesn't\
584                                                     appear to have a stem",
585                                                    output.to_str())).to_managed();
586                 warn_missing(sess, "name", name);
587                 name
588             }
589         }
590     }
591
592     fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str {
593         match opt_vers {
594             Some(v) => v,
595             None => {
596                 let vers = @"0.0";
597                 warn_missing(sess, "vers", vers);
598                 vers
599             }
600         }
601     }
602
603     let ProvidedMetas {
604         name: opt_name,
605         vers: opt_vers,
606         cmh_items: cmh_items
607     } = provided_link_metas(sess, c);
608     let name = crate_meta_name(sess, output, opt_name);
609     let vers = crate_meta_vers(sess, opt_vers);
610     let dep_hashes = cstore::get_dep_hashes(sess.cstore);
611     let extras_hash =
612         crate_meta_extras_hash(symbol_hasher, cmh_items,
613                                dep_hashes);
614
615     LinkMeta {
616         name: name,
617         vers: vers,
618         extras_hash: extras_hash
619     }
620 }
621
622 pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
623     symbol_hasher.result_str()
624 }
625
626
627 // This calculates STH for a symbol, as defined above
628 pub fn symbol_hash(tcx: ty::ctxt,
629                    symbol_hasher: &mut hash::State,
630                    t: ty::t,
631                    link_meta: LinkMeta)
632                    -> @str {
633     // NB: do *not* use abbrevs here as we want the symbol names
634     // to be independent of one another in the crate.
635
636     symbol_hasher.reset();
637     write_string(symbol_hasher, link_meta.name);
638     write_string(symbol_hasher, "-");
639     write_string(symbol_hasher, link_meta.extras_hash);
640     write_string(symbol_hasher, "-");
641     write_string(symbol_hasher, encoder::encoded_ty(tcx, t));
642     let mut hash = truncated_hash_result(symbol_hasher);
643     // Prefix with _ so that it never blends into adjacent digits
644     hash.unshift_char('_');
645     // tjc: allocation is unfortunate; need to change std::hash
646     hash.to_managed()
647 }
648
649 pub fn get_symbol_hash(ccx: &mut CrateContext, t: ty::t) -> @str {
650     match ccx.type_hashcodes.find(&t) {
651       Some(&h) => h,
652       None => {
653         let hash = symbol_hash(ccx.tcx, &mut ccx.symbol_hasher, t, ccx.link_meta);
654         ccx.type_hashcodes.insert(t, hash);
655         hash
656       }
657     }
658 }
659
660
661 // Name sanitation. LLVM will happily accept identifiers with weird names, but
662 // gas doesn't!
663 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
664 pub fn sanitize(s: &str) -> ~str {
665     let mut result = ~"";
666     for s.iter().advance |c| {
667         match c {
668             // Escape these with $ sequences
669             '@' => result.push_str("$SP$"),
670             '~' => result.push_str("$UP$"),
671             '*' => result.push_str("$RP$"),
672             '&' => result.push_str("$BP$"),
673             '<' => result.push_str("$LT$"),
674             '>' => result.push_str("$GT$"),
675             '(' => result.push_str("$LP$"),
676             ')' => result.push_str("$RP$"),
677             ',' => result.push_str("$C$"),
678
679             // '.' doesn't occur in types and functions, so reuse it
680             // for ':'
681             ':' => result.push_char('.'),
682
683             // These are legal symbols
684             'a' .. 'z'
685             | 'A' .. 'Z'
686             | '0' .. '9'
687             | '_' => result.push_char(c),
688
689             _ => {
690                 let mut tstr = ~"";
691                 do char::escape_unicode(c) |c| { tstr.push_char(c); }
692                 result.push_char('$');
693                 result.push_str(tstr.slice_from(1));
694             }
695         }
696     }
697
698     // Underscore-qualify anything that didn't start as an ident.
699     if result.len() > 0u &&
700         result[0] != '_' as u8 &&
701         ! char::is_XID_start(result[0] as char) {
702         return ~"_" + result;
703     }
704
705     return result;
706 }
707
708 pub fn mangle(sess: Session, ss: path) -> ~str {
709     // Follow C++ namespace-mangling style
710
711     let mut n = ~"_ZN"; // Begin name-sequence.
712
713     for ss.iter().advance |s| {
714         match *s {
715             path_name(s) | path_mod(s) => {
716                 let sani = sanitize(sess.str_of(s));
717                 n.push_str(fmt!("%u%s", sani.len(), sani));
718             }
719         }
720     }
721     n.push_char('E'); // End name-sequence.
722     n
723 }
724
725 pub fn exported_name(sess: Session,
726                      path: path,
727                      hash: &str,
728                      vers: &str) -> ~str {
729     mangle(sess,
730            vec::append_one(
731                vec::append_one(path, path_name(sess.ident_of(hash))),
732                path_name(sess.ident_of(vers))))
733 }
734
735 pub fn mangle_exported_name(ccx: &mut CrateContext,
736                             path: path,
737                             t: ty::t) -> ~str {
738     let hash = get_symbol_hash(ccx, t);
739     return exported_name(ccx.sess, path,
740                          hash,
741                          ccx.link_meta.vers);
742 }
743
744 pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
745                                          t: ty::t,
746                                          name: &str) -> ~str {
747     let s = ppaux::ty_to_short_str(ccx.tcx, t);
748     let hash = get_symbol_hash(ccx, t);
749     return mangle(ccx.sess,
750         ~[path_name(ccx.sess.ident_of(name)),
751           path_name(ccx.sess.ident_of(s)),
752           path_name(ccx.sess.ident_of(hash))]);
753 }
754
755 pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
756                                          t: ty::t,
757                                          name: &str) -> ~str {
758     let s = ppaux::ty_to_str(ccx.tcx, t);
759     let hash = get_symbol_hash(ccx, t);
760     return mangle(ccx.sess,
761         ~[path_name(ccx.sess.ident_of(s)),
762           path_name(ccx.sess.ident_of(hash)),
763           path_name(gensym_name(name))]);
764 }
765
766 pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
767                                             mut path: path,
768                                             flav: &str) -> ~str {
769     path.push(path_name(gensym_name(flav)));
770     mangle(ccx.sess, path)
771 }
772
773 pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
774     mangle(ccx.sess, path)
775 }
776
777 pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str {
778     return fmt!("%s_%u", flav, token::gensym(flav));
779 }
780
781
782 pub fn output_dll_filename(os: session::os, lm: LinkMeta) -> ~str {
783     let (dll_prefix, dll_suffix) = match os {
784         session::os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
785         session::os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
786         session::os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
787         session::os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
788         session::os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
789     };
790     fmt!("%s%s-%s-%s%s", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
791 }
792
793 // If the user wants an exe generated we need to invoke
794 // cc to link the object file with some libs
795 pub fn link_binary(sess: Session,
796                    obj_filename: &Path,
797                    out_filename: &Path,
798                    lm: LinkMeta) {
799     // In the future, FreeBSD will use clang as default compiler.
800     // It would be flexible to use cc (system's default C compiler)
801     // instead of hard-coded gcc.
802     // For win32, there is no cc command,
803     // so we add a condition to make it use gcc.
804     let cc_prog: ~str = match sess.opts.linker {
805         Some(ref linker) => linker.to_str(),
806         None => match sess.targ_cfg.os {
807             session::os_android =>
808                 match &sess.opts.android_cross_path {
809                     &Some(ref path) => {
810                         fmt!("%s/bin/arm-linux-androideabi-gcc", *path)
811                     }
812                     &None => {
813                         sess.fatal("need Android NDK path for linking \
814                                     (--android-cross-path)")
815                     }
816                 },
817             session::os_win32 => ~"gcc",
818             _ => ~"cc"
819         }
820     };
821     // The invocations of cc share some flags across platforms
822
823
824     let output = if *sess.building_library {
825         let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
826         debug!("link_meta.name:  %s", lm.name);
827         debug!("long_libname: %s", long_libname);
828         debug!("out_filename: %s", out_filename.to_str());
829         debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
830
831         out_filename.dir_path().push(long_libname)
832     } else {
833         out_filename.clone()
834     };
835
836     debug!("output: %s", output.to_str());
837     let cc_args = link_args(sess, obj_filename, out_filename, lm);
838     debug!("%s link args: %s", cc_prog, cc_args.connect(" "));
839     // We run 'cc' here
840     let prog = run::process_output(cc_prog, cc_args);
841     if 0 != prog.status {
842         sess.err(fmt!("linking with `%s` failed with code %d",
843                       cc_prog, prog.status));
844         sess.note(fmt!("%s arguments: %s",
845                        cc_prog, cc_args.connect(" ")));
846         sess.note(str::from_bytes(prog.error + prog.output));
847         sess.abort_if_errors();
848     }
849
850     // Clean up on Darwin
851     if sess.targ_cfg.os == session::os_macos {
852         run::process_status("dsymutil", [output.to_str()]);
853     }
854
855     // Remove the temporary object file if we aren't saving temps
856     if !sess.opts.save_temps {
857         if ! os::remove_file(obj_filename) {
858             sess.warn(fmt!("failed to delete object file `%s`",
859                            obj_filename.to_str()));
860         }
861     }
862 }
863
864 pub fn link_args(sess: Session,
865                  obj_filename: &Path,
866                  out_filename: &Path,
867                  lm:LinkMeta) -> ~[~str] {
868
869     // Converts a library file-stem into a cc -l argument
870     fn unlib(config: @session::config, stem: ~str) -> ~str {
871         if stem.starts_with("lib") &&
872             config.os != session::os_win32 {
873             stem.slice(3, stem.len()).to_owned()
874         } else {
875             stem
876         }
877     }
878
879
880     let output = if *sess.building_library {
881         let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
882         out_filename.dir_path().push(long_libname)
883     } else {
884         out_filename.clone()
885     };
886
887     // The default library location, we need this to find the runtime.
888     // The location of crates will be determined as needed.
889     let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
890
891     let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
892
893     args.push_all([
894         ~"-o", output.to_str(),
895         obj_filename.to_str()]);
896
897     let lib_cmd = match sess.targ_cfg.os {
898         session::os_macos => ~"-dynamiclib",
899         _ => ~"-shared"
900     };
901
902     // # Crate linking
903
904     let cstore = sess.cstore;
905     let r = cstore::get_used_crate_files(cstore);
906     for r.iter().advance |cratepath| {
907         if cratepath.filetype() == Some(~".rlib") {
908             args.push(cratepath.to_str());
909             loop;
910         }
911         let dir = cratepath.dirname();
912         if dir != ~"" { args.push(~"-L" + dir); }
913         let libarg = unlib(sess.targ_cfg, cratepath.filestem().get());
914         args.push(~"-l" + libarg);
915     }
916
917     let ula = cstore::get_used_link_args(cstore);
918     for ula.iter().advance |arg| { args.push(arg.to_owned()); }
919
920     // Add all the link args for external crates.
921     do cstore::iter_crate_data(cstore) |crate_num, _| {
922         let link_args = csearch::get_link_args_for_crate(cstore, crate_num);
923         for link_args.consume_iter().advance |link_arg| {
924             args.push(link_arg);
925         }
926     }
927
928     // # Extern library linking
929
930     // User-supplied library search paths (-L on the cammand line) These are
931     // the same paths used to find Rust crates, so some of them may have been
932     // added already by the previous crate linking code. This only allows them
933     // to be found at compile time so it is still entirely up to outside
934     // forces to make sure that library can be found at runtime.
935
936     for sess.opts.addl_lib_search_paths.iter().advance |path| {
937         args.push(~"-L" + path.to_str());
938     }
939
940     // The names of the extern libraries
941     let used_libs = cstore::get_used_libraries(cstore);
942     for used_libs.iter().advance |l| { args.push(~"-l" + *l); }
943
944     if *sess.building_library {
945         args.push(lib_cmd);
946
947         // On mac we need to tell the linker to let this library
948         // be rpathed
949         if sess.targ_cfg.os == session::os_macos {
950             args.push(~"-Wl,-install_name,@rpath/"
951                       + output.filename().get());
952         }
953     }
954
955     // On linux librt and libdl are an indirect dependencies via rustrt,
956     // and binutils 2.22+ won't add them automatically
957     if sess.targ_cfg.os == session::os_linux {
958         args.push_all([~"-lrt", ~"-ldl"]);
959
960         // LLVM implements the `frem` instruction as a call to `fmod`,
961         // which lives in libm. Similar to above, on some linuxes we
962         // have to be explicit about linking to it. See #2510
963         args.push(~"-lm");
964     }
965     else if sess.targ_cfg.os == session::os_android {
966         args.push_all([~"-ldl", ~"-llog",  ~"-lsupc++", ~"-lgnustl_shared"]);
967         args.push(~"-lm");
968     }
969
970     if sess.targ_cfg.os == session::os_freebsd {
971         args.push_all([~"-pthread", ~"-lrt",
972                        ~"-L/usr/local/lib", ~"-lexecinfo",
973                        ~"-L/usr/local/lib/gcc46",
974                        ~"-L/usr/local/lib/gcc44", ~"-lstdc++",
975                        ~"-Wl,-z,origin",
976                        ~"-Wl,-rpath,/usr/local/lib/gcc46",
977                        ~"-Wl,-rpath,/usr/local/lib/gcc44"]);
978     }
979
980     // OS X 10.6 introduced 'compact unwind info', which is produced by the
981     // linker from the dwarf unwind info. Unfortunately, it does not seem to
982     // understand how to unwind our __morestack frame, so we have to turn it
983     // off. This has impacted some other projects like GHC.
984     if sess.targ_cfg.os == session::os_macos {
985         args.push(~"-Wl,-no_compact_unwind");
986     }
987
988     // Stack growth requires statically linking a __morestack function
989     args.push(~"-lmorestack");
990
991     // Always want the runtime linked in
992     args.push(~"-lrustrt");
993
994     // FIXME (#2397): At some point we want to rpath our guesses as to where
995     // extern libraries might live, based on the addl_lib_search_paths
996     args.push_all(rpath::get_rpath_flags(sess, &output));
997
998     // Finally add all the linker arguments provided on the command line
999     args.push_all(sess.opts.linker_args);
1000
1001     return args;
1002 }