link.rs 25.7 KB
Newer Older
M
Marijn Haverbeke 已提交
1
import ctypes::{c_int, c_uint};
2
import driver::session;
3
import session::session;
4
import lib::llvm::llvm;
5
import front::attr;
6
import middle::ty;
7
import metadata::{encoder, cstore};
8
import middle::trans::common::crate_ctxt;
9
import std::fs;
10
import std::run;
11
import std::sha1::sha1;
12
import syntax::ast;
13
import syntax::print::pprust;
14
import lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data, True, False};
15
import util::filesearch;
16
import middle::ast_map::{path, path_mod, path_name};
17

P
Patrick Walton 已提交
18
enum output_type {
P
Patrick Walton 已提交
19 20 21 22 23 24
    output_type_none,
    output_type_bitcode,
    output_type_assembly,
    output_type_llvm_assembly,
    output_type_object,
    output_type_exe,
25 26
}

27
fn llvm_err(sess: session, msg: str) unsafe {
28
    let buf = llvm::LLVMRustGetLastError();
29
    if buf == ptr::null() {
30
        sess.fatal(msg);
31
    } else { sess.fatal(msg + ": " + str::from_cstr(buf)); }
32 33
}

T
Tim Chevalier 已提交
34
fn load_intrinsics_bc(sess: session) -> option<ModuleRef> {
35
    let path = alt filesearch::search(
36
        sess.filesearch,
37 38
        bind filesearch::pick_file("intrinsics.bc", _)) {
      option::some(path) { path }
39
      option::none {
40 41 42
        sess.warn("couldn't find intrinsics.bc");
        ret option::none;
      }
43
    };
44 45
    let membuf = str::as_buf(path, {|buf|
        llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
46
                                   });
M
Marijn Haverbeke 已提交
47
    if membuf as uint == 0u {
B
Brian Anderson 已提交
48
        llvm_err(sess, "installation problem: couldn't open " + path);
49 50
        fail;
    }
M
Marijn Haverbeke 已提交
51
    let llintrinsicsmod = llvm::LLVMRustParseBitcode(membuf);
52
    llvm::LLVMDisposeMemoryBuffer(membuf);
M
Marijn Haverbeke 已提交
53
    if llintrinsicsmod as uint == 0u {
54 55 56 57 58 59 60
        sess.warn("couldn't parse intrinsics.bc");
        ret option::none;
    }

    ret option::some(llintrinsicsmod);
}

61
fn load_intrinsics_ll(sess: session) -> ModuleRef {
62
    let path = alt filesearch::search(
63
        sess.filesearch,
64 65
        bind filesearch::pick_file("intrinsics.ll", _)) {
      option::some(path) { path }
66
      option::none { sess.fatal("couldn't find intrinsics.ll") }
67 68 69 70 71 72
    };
    let llintrinsicsmod = str::as_buf(path, { |buf|
        llvm::LLVMRustParseAssemblyFile(buf)
                                        });
    if llintrinsicsmod as uint == 0u {
        llvm_err(sess, "couldn't parse intrinsics.ll");
73 74
        fail;
    }
75 76 77
    ret llintrinsicsmod;
}

78
fn link_intrinsics(sess: session, llmod: ModuleRef) {
79 80 81
    let llintrinsicsmod = {
        alt load_intrinsics_bc(sess) {
          option::some(m) { m }
82
          option::none {
83 84 85 86 87 88 89 90 91
            // When the bitcode format changes we can't parse a .bc
            // file produced with a newer LLVM (as happens when stage0
            // is trying to build against a new LLVM revision), in
            // that case we'll try to parse the assembly.
            sess.warn("couldn't parse intrinsics.bc, trying intrinsics.ll");
            load_intrinsics_ll(sess)
          }
        }
    };
M
Marijn Haverbeke 已提交
92
    let linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod);
93
    llvm::LLVMDisposeModule(llintrinsicsmod);
M
Marijn Haverbeke 已提交
94
    if linkres == False {
B
Brian Anderson 已提交
95
        llvm_err(sess, "couldn't link the module with the intrinsics");
96 97
        fail;
    }
98 99
}

100
mod write {
M
Marijn Haverbeke 已提交
101 102 103
    fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
        if ot == output_type_assembly || ot == output_type_object ||
               ot == output_type_exe {
104 105 106 107 108 109 110
            ret true;
        }
        ret false;
    }

    // Decides what to call an intermediate file, given the name of the output
    // and the extension to use.
111
    fn mk_intermediate_name(output_path: str, extension: str) -> str unsafe {
K
Kevin Cantu 已提交
112
        let stem = alt str::index(output_path, '.') {
K
Kevin Cantu 已提交
113
                       option::some(dot_pos) {
K
Kevin Cantu 已提交
114
                           str::slice(output_path, 0u, dot_pos)
K
Kevin Cantu 已提交
115 116 117 118
                       }
                       option::none { output_path }
                   };

B
Brian Anderson 已提交
119
        ret stem + "." + extension;
120
    }
K
Kevin Cantu 已提交
121

122 123
    fn run_passes(sess: session, llmod: ModuleRef, output: str) {
        let opts = sess.opts;
M
Marijn Haverbeke 已提交
124
        if opts.time_llvm_passes { llvm::LLVMRustEnableTimePasses(); }
G
Graydon Hoare 已提交
125
        link_intrinsics(sess, llmod);
M
Marijn Haverbeke 已提交
126
        let pm = mk_pass_manager();
127
        let td = mk_target_data(
128
            sess.targ_cfg.target_strs.data_layout);
129
        llvm::LLVMAddTargetData(td.lltd, pm.llpm);
130 131 132 133 134
        // TODO: run the linter here also, once there are llvm-c bindings for
        // it.

        // Generate a pre-optimization intermediate file if -save-temps was
        // specified.
135

M
Marijn Haverbeke 已提交
136 137
        if opts.save_temps {
            alt opts.output_type {
138
              output_type_bitcode {
M
Marijn Haverbeke 已提交
139
                if opts.optimize != 0u {
B
Brian Anderson 已提交
140 141 142 143 144
                    let filename = mk_intermediate_name(output, "no-opt.bc");
                    str::as_buf(filename,
                                {|buf|
                                    llvm::LLVMWriteBitcodeToFile(llmod, buf)
                                });
145
                }
M
Marijn Haverbeke 已提交
146 147
              }
              _ {
B
Brian Anderson 已提交
148 149 150 151 152
                let filename = mk_intermediate_name(output, "bc");
                str::as_buf(filename,
                            {|buf|
                                llvm::LLVMWriteBitcodeToFile(llmod, buf)
                            });
M
Marijn Haverbeke 已提交
153
              }
154 155
            }
        }
M
Marijn Haverbeke 已提交
156
        if opts.verify { llvm::LLVMAddVerifierPass(pm.llpm); }
157 158 159 160 161 162
        // FIXME: This is mostly a copy of the bits of opt's -O2 that are
        // available in the C api.
        // FIXME2: We might want to add optimization levels like -O1, -O2,
        // -Os, etc
        // FIXME3: Should we expose and use the pass lists used by the opt
        // tool?
163

M
Marijn Haverbeke 已提交
164 165
        if opts.optimize != 0u {
            let fpm = mk_pass_manager();
166
            llvm::LLVMAddTargetData(td.lltd, fpm.llpm);
167 168

            let FPMB = llvm::LLVMPassManagerBuilderCreate();
169
            llvm::LLVMPassManagerBuilderSetOptLevel(FPMB, 2u as c_uint);
170 171 172 173
            llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(FPMB,
                                                                    fpm.llpm);
            llvm::LLVMPassManagerBuilderDispose(FPMB);

174
            llvm::LLVMRunPassManager(fpm.llpm, llmod);
175 176
            let threshold = 225u;
            if opts.optimize == 3u { threshold = 275u; }
177

178
            let MPMB = llvm::LLVMPassManagerBuilderCreate();
179
            llvm::LLVMPassManagerBuilderSetOptLevel(MPMB,
180
                                                    opts.optimize as c_uint);
181
            llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, False);
182 183 184 185 186
            llvm::LLVMPassManagerBuilderSetDisableUnitAtATime(MPMB, False);
            llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(MPMB, False);
            llvm::LLVMPassManagerBuilderSetDisableSimplifyLibCalls(MPMB,
                                                                   False);

187
            if threshold != 0u {
188
                llvm::LLVMPassManagerBuilderUseInlinerWithThreshold
189
                    (MPMB, threshold as c_uint);
190 191 192 193 194
            }
            llvm::LLVMPassManagerBuilderPopulateModulePassManager(MPMB,
                                                                  pm.llpm);

            llvm::LLVMPassManagerBuilderDispose(MPMB);
195
        }
M
Marijn Haverbeke 已提交
196 197
        if opts.verify { llvm::LLVMAddVerifierPass(pm.llpm); }
        if is_object_or_assembly_or_exe(opts.output_type) {
198 199 200 201 202 203
            let LLVMAssemblyFile  = 0 as c_int;
            let LLVMObjectFile    = 1 as c_int;
            let LLVMOptNone       = 0 as c_int; // -O0
            let LLVMOptLess       = 1 as c_int; // -O1
            let LLVMOptDefault    = 2 as c_int; // -O2, -Os
            let LLVMOptAggressive = 3 as c_int; // -O3
M
Marijn Haverbeke 已提交
204 205

            let CodeGenOptLevel;
206
            alt check opts.optimize {
M
Marijn Haverbeke 已提交
207 208 209 210
              0u { CodeGenOptLevel = LLVMOptNone; }
              1u { CodeGenOptLevel = LLVMOptLess; }
              2u { CodeGenOptLevel = LLVMOptDefault; }
              3u { CodeGenOptLevel = LLVMOptAggressive; }
211 212
            }

M
Marijn Haverbeke 已提交
213 214 215
            let FileType;
            if opts.output_type == output_type_object ||
                   opts.output_type == output_type_exe {
216
                FileType = LLVMObjectFile;
217
            } else { FileType = LLVMAssemblyFile; }
218
            // Write optimized bitcode if --save-temps was on.
219

M
Marijn Haverbeke 已提交
220
            if opts.save_temps {
221
                // Always output the bitcode file with --save-temps
222

B
Brian Anderson 已提交
223
                let filename = mk_intermediate_name(output, "opt.bc");
224
                llvm::LLVMRunPassManager(pm.llpm, llmod);
B
Brian Anderson 已提交
225 226 227 228
                str::as_buf(filename,
                            {|buf|
                                llvm::LLVMWriteBitcodeToFile(llmod, buf)
                            });
229 230
                pm = mk_pass_manager();
                // Save the assembly file if -S is used
231

M
Marijn Haverbeke 已提交
232
                if opts.output_type == output_type_assembly {
233
                    let _: () = str::as_buf(
234
                        sess.targ_cfg.target_strs.target_triple,
235 236 237 238 239 240 241 242
                        {|buf_t|
                            str::as_buf(output, {|buf_o|
                                llvm::LLVMRustWriteOutputFile(
                                    pm.llpm,
                                    llmod,
                                    buf_t,
                                    buf_o,
                                    LLVMAssemblyFile,
243
                                    CodeGenOptLevel,
244
                                    true)})});
245
                }
246

M
Marijn Haverbeke 已提交
247

248 249
                // Save the object file for -c or --save-temps alone
                // This .o is needed when an exe is built
M
Marijn Haverbeke 已提交
250 251
                if opts.output_type == output_type_object ||
                       opts.output_type == output_type_exe {
252
                    let _: () =
253
                        str::as_buf(
254
                            sess.targ_cfg.target_strs.target_triple,
255 256 257 258 259 260 261 262
                            {|buf_t|
                                str::as_buf(output, {|buf_o|
                                    llvm::LLVMRustWriteOutputFile(
                                        pm.llpm,
                                        llmod,
                                        buf_t,
                                        buf_o,
                                        LLVMObjectFile,
263
                                        CodeGenOptLevel,
264
                                        true)})});
265
                }
266 267 268
            } else {
                // If we aren't saving temps then just output the file
                // type corresponding to the '-c' or '-S' flag used
269

B
Brian Anderson 已提交
270
                let _: () =
271
                    str::as_buf(
272
                        sess.targ_cfg.target_strs.target_triple,
273 274 275 276 277 278 279 280
                        {|buf_t|
                            str::as_buf(output, {|buf_o|
                                llvm::LLVMRustWriteOutputFile(
                                    pm.llpm,
                                    llmod,
                                    buf_t,
                                    buf_o,
                                    FileType,
281
                                    CodeGenOptLevel,
282
                                    true)})});
283
            }
284
            // Clean up and return
285

286
            llvm::LLVMDisposeModule(llmod);
M
Marijn Haverbeke 已提交
287
            if opts.time_llvm_passes { llvm::LLVMRustPrintPassTimings(); }
288 289 290
            ret;
        }

291 292 293 294 295 296 297 298 299 300 301 302
        if opts.output_type == output_type_llvm_assembly {
            // Given options "-S --emit-llvm": output LLVM assembly
            str::as_buf(output, {|buf_o|
                llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o)});
        } else {
            // If only a bitcode file is asked for by using the '--emit-llvm'
            // flag, then output it here
            llvm::LLVMRunPassManager(pm.llpm, llmod);
            str::as_buf(output,
                        {|buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) });
        }

303
        llvm::LLVMDisposeModule(llmod);
M
Marijn Haverbeke 已提交
304
        if opts.time_llvm_passes { llvm::LLVMRustPrintPassTimings(); }
305 306 307
    }
}

308

309 310 311 312 313 314 315 316 317 318 319 320
/*
 * Name mangling and its relationship to metadata. This is complex. Read
 * carefully.
 *
 * The semantic model of Rust linkage is, broadly, that "there's no global
 * namespace" between crates. Our aim is to preserve the illusion of this
 * model despite the fact that it's not *quite* possible to implement on
 * modern linkers. We initially didn't use system linkers at all, but have
 * been convinced of their utility.
 *
 * There are a few issues to handle:
 *
E
Erick Tryzelaar 已提交
321
 *  - Linkers operate on a flat namespace, so we have to flatten names.
322 323 324 325 326 327 328 329 330 331 332
 *    We do this using the C++ namespace-mangling technique. Foo::bar
 *    symbols and such.
 *
 *  - Symbols with the same name but different types need to get different
 *    linkage-names. We do this by hashing a string-encoding of the type into
 *    a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
 *    we use SHA1) to "prevent collisions". This is not airtight but 16 hex
 *    digits on uniform probability means you're going to need 2**32 same-name
 *    symbols in the same process before you're even hitting birthday-paradox
 *    collision probability.
 *
L
Lindsey Kuper 已提交
333
 *  - Symbols in different crates but with same names "within" the crate need
334 335 336 337 338 339 340
 *    to get different linkage-names.
 *
 * So here is what we do:
 *
 *  - Separate the meta tags into two sets: exported and local. Only work with
 *    the exported ones when considering linkage.
 *
L
Lindsey Kuper 已提交
341
 *  - Consider two exported tags as special (and mandatory): name and vers.
342 343 344 345 346 347
 *    Every crate gets them; if it doesn't name them explicitly we infer them
 *    as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
 *
 *  - Define CMETA as all the non-name, non-vers exported meta tags in the
 *    crate (in sorted order).
 *
348
 *  - Define CMH as hash(CMETA + hashes of dependent crates).
349 350 351 352 353 354 355 356 357 358
 *
 *  - Compile our crate to lib CNAME-CMH-CVERS.so
 *
 *  - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
 *
 *  - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
 *    name, non-name metadata, and type sense, and versioned in the way
 *    system linkers understand.
 *
 */
359

B
Brian Anderson 已提交
360
type link_meta = {name: str, vers: str, extras_hash: str};
361

362
fn build_link_meta(sess: session, c: ast::crate, output: str,
M
Marijn Haverbeke 已提交
363
                   sha: sha1) -> link_meta {
364

M
Marijn Haverbeke 已提交
365
    type provided_metas =
T
Tim Chevalier 已提交
366 367
        {name: option<str>,
         vers: option<str>,
368
         cmh_items: [@ast::meta_item]};
369

370
    fn provided_link_metas(sess: session, c: ast::crate) ->
M
Marijn Haverbeke 已提交
371
       provided_metas {
T
Tim Chevalier 已提交
372 373
        let name: option<str> = none;
        let vers: option<str> = none;
B
Brian Anderson 已提交
374
        let cmh_items: [@ast::meta_item] = [];
M
Marijn Haverbeke 已提交
375
        let linkage_metas = attr::find_linkage_metas(c.node.attrs);
376
        attr::require_unique_names(sess, linkage_metas);
377
        for meta: @ast::meta_item in linkage_metas {
B
Brian Anderson 已提交
378
            if attr::get_meta_item_name(meta) == "name" {
M
Marijn Haverbeke 已提交
379
                alt attr::get_meta_item_value_str(meta) {
380
                  some(v) { name = some(v); }
381
                  none { cmh_items += [meta]; }
382
                }
B
Brian Anderson 已提交
383
            } else if attr::get_meta_item_name(meta) == "vers" {
M
Marijn Haverbeke 已提交
384
                alt attr::get_meta_item_value_str(meta) {
385
                  some(v) { vers = some(v); }
386
                  none { cmh_items += [meta]; }
387
                }
B
Brian Anderson 已提交
388
            } else { cmh_items += [meta]; }
389
        }
M
Marijn Haverbeke 已提交
390
        ret {name: name, vers: vers, cmh_items: cmh_items};
391 392
    }

393
    // This calculates CMH as defined above
394
    fn crate_meta_extras_hash(sha: sha1, _crate: ast::crate,
395 396
                              metas: provided_metas,
                              dep_hashes: [str]) -> str {
397
        fn len_and_str(s: str) -> str {
398
            ret #fmt["%u_%s", str::len_bytes(s), s];
399
        }
400

401
        fn len_and_str_lit(l: ast::lit) -> str {
402
            ret len_and_str(pprust::lit_to_str(@l));
403
        }
404

M
Marijn Haverbeke 已提交
405
        let cmh_items = attr::sort_meta_items(metas.cmh_items);
406 407

        sha.reset();
408
        for m_: @ast::meta_item in cmh_items {
M
Marijn Haverbeke 已提交
409 410 411
            let m = m_;
            alt m.node {
              ast::meta_name_value(key, value) {
412
                sha.input_str(len_and_str(key));
M
Marijn Haverbeke 已提交
413 414
                sha.input_str(len_and_str_lit(value));
              }
B
Brian Anderson 已提交
415
              ast::meta_word(name) { sha.input_str(len_and_str(name)); }
M
Marijn Haverbeke 已提交
416 417 418 419
              ast::meta_list(_, _) {
                // FIXME (#607): Implement this
                fail "unimplemented meta_item variant";
              }
420
            }
421
        }
422 423 424 425 426

        for dh in dep_hashes {
            sha.input_str(len_and_str(dh));
        }

427
        ret truncated_sha1_result(sha);
428 429
    }

430 431
    fn warn_missing(sess: session, name: str, default: str) {
        if !sess.building_library { ret; }
B
Brian Anderson 已提交
432
        sess.warn(#fmt["missing crate link meta '%s', using '%s' as default",
433
                       name, default]);
434 435
    }

436
    fn crate_meta_name(sess: session, _crate: ast::crate,
437
                       output: str, metas: provided_metas) -> str {
M
Marijn Haverbeke 已提交
438 439
        ret alt metas.name {
              some(v) { v }
440
              none {
441
                let name =
M
Marijn Haverbeke 已提交
442
                    {
K
Kevin Cantu 已提交
443 444
                        let os = str::split_byte(
                                   fs::basename(output), '.' as u8);
445 446 447 448
                        if (vec::len(os) < 2u) {
                            sess.fatal(#fmt("Output file name %s doesn't\
                              appear to have an extension", output));
                        }
B
Brian Anderson 已提交
449
                        vec::pop(os);
B
Brian Anderson 已提交
450
                        str::connect(os, ".")
M
Marijn Haverbeke 已提交
451
                    };
B
Brian Anderson 已提交
452
                warn_missing(sess, "name", name);
453
                name
M
Marijn Haverbeke 已提交
454 455
              }
            };
456
    }
457

458
    fn crate_meta_vers(sess: session, _crate: ast::crate,
459
                       metas: provided_metas) -> str {
M
Marijn Haverbeke 已提交
460 461
        ret alt metas.vers {
              some(v) { v }
462
              none {
B
Brian Anderson 已提交
463 464
                let vers = "0.0";
                warn_missing(sess, "vers", vers);
465
                vers
M
Marijn Haverbeke 已提交
466 467
              }
            };
468 469
    }

M
Marijn Haverbeke 已提交
470 471 472
    let provided_metas = provided_link_metas(sess, c);
    let name = crate_meta_name(sess, c, output, provided_metas);
    let vers = crate_meta_vers(sess, c, provided_metas);
473
    let dep_hashes = cstore::get_dep_hashes(sess.cstore);
474 475
    let extras_hash =
        crate_meta_extras_hash(sha, c, provided_metas, dep_hashes);
476

M
Marijn Haverbeke 已提交
477
    ret {name: name, vers: vers, extras_hash: extras_hash};
478 479
}

480
fn truncated_sha1_result(sha: sha1) -> str unsafe {
481
    ret str::slice(sha.result_str(), 0u, 16u);
482 483
}

484 485

// This calculates STH for a symbol, as defined above
486
fn symbol_hash(tcx: ty::ctxt, sha: sha1, t: ty::t, link_meta: link_meta) ->
B
Brian Anderson 已提交
487
   str {
488 489 490
    // NB: do *not* use abbrevs here as we want the symbol names
    // to be independent of one another in the crate.

491
    sha.reset();
492
    sha.input_str(link_meta.name);
B
Brian Anderson 已提交
493
    sha.input_str("-");
494
    // FIXME: This wants to be link_meta.meta_hash
495
    sha.input_str(link_meta.name);
B
Brian Anderson 已提交
496
    sha.input_str("-");
497
    sha.input_str(encoder::encoded_ty(tcx, t));
M
Marijn Haverbeke 已提交
498
    let hash = truncated_sha1_result(sha);
499 500
    // Prefix with _ so that it never blends into adjacent digits

B
Brian Anderson 已提交
501
    ret "_" + hash;
502 503
}

504
fn get_symbol_hash(ccx: crate_ctxt, t: ty::t) -> str {
B
Brian Anderson 已提交
505
    let hash = "";
M
Marijn Haverbeke 已提交
506 507
    alt ccx.type_sha1s.find(t) {
      some(h) { hash = h; }
508
      none {
M
Marijn Haverbeke 已提交
509 510 511
        hash = symbol_hash(ccx.tcx, ccx.sha, t, ccx.link_meta);
        ccx.type_sha1s.insert(t, hash);
      }
512 513
    }
    ret hash;
514 515
}

516
fn mangle(ss: path) -> str {
517 518
    // Follow C++ namespace-mangling style

B
Brian Anderson 已提交
519
    let n = "_ZN"; // Begin name-sequence.
520

521 522
    for s in ss {
        alt s { path_name(s) | path_mod(s) {
523
          n += #fmt["%u%s", str::len_bytes(s), s];
524 525
        } }
    }
B
Brian Anderson 已提交
526
    n += "E"; // End name-sequence.
527
    n
528 529
}

530
fn exported_name(path: path, hash: str, _vers: str) -> str {
531
    // FIXME: versioning isn't working yet
532
    ret mangle(path + [path_name(hash)]); //  + "@" + vers;
533

534 535
}

536
fn mangle_exported_name(ccx: crate_ctxt, path: path, t: ty::t) -> str {
M
Marijn Haverbeke 已提交
537
    let hash = get_symbol_hash(ccx, t);
538
    ret exported_name(path, hash, ccx.link_meta.vers);
539 540
}

541
fn mangle_internal_name_by_type_only(ccx: crate_ctxt, t: ty::t, name: str) ->
542
   str {
M
Marijn Haverbeke 已提交
543 544
    let s = util::ppaux::ty_to_short_str(ccx.tcx, t);
    let hash = get_symbol_hash(ccx, t);
545
    ret mangle([path_name(name), path_name(s), path_name(hash)]);
546 547
}

548
fn mangle_internal_name_by_path_and_seq(ccx: crate_ctxt, path: path,
549
                                        flav: str) -> str {
550
    ret mangle(path + [path_name(ccx.names(flav))]);
551 552
}

553
fn mangle_internal_name_by_path(_ccx: crate_ctxt, path: path) -> str {
554 555 556
    ret mangle(path);
}

557
fn mangle_internal_name_by_seq(ccx: crate_ctxt, flav: str) -> str {
558
    ret ccx.names(flav);
559
}
560 561

// If the user wants an exe generated we need to invoke
562
// cc to link the object file with some libs
563
fn link_binary(sess: session,
564
               obj_filename: str,
565
               out_filename: str,
K
Kevin Cantu 已提交
566
               lm: link_meta) {
567
    // Converts a library file name into a cc -l argument
K
Kevin Cantu 已提交
568
    fn unlib(config: @session::config, filename: str) -> str unsafe {
569
        let rmlib = fn@(filename: str) -> str {
570
            let found = str::find(filename, "lib");
571 572 573
            if config.os == session::os_macos ||
                (config.os == session::os_linux ||
                 config.os == session::os_freebsd) &&
574
                option::is_some(found) && option::get(found) == 0u {
575
                ret str::slice(filename, 3u,
576
                               str::len_bytes(filename));
577 578
            } else { ret filename; }
        };
579
        fn rmext(filename: str) -> str {
K
Kevin Cantu 已提交
580
            let parts = str::split_byte(filename, '.' as u8);
581 582 583 584
            vec::pop(parts);
            ret str::connect(parts, ".");
        }
        ret alt config.os {
585 586 587
              session::os_macos { rmext(rmlib(filename)) }
              session::os_linux { rmext(rmlib(filename)) }
              session::os_freebsd { rmext(rmlib(filename)) }
588 589 590 591
              _ { rmext(filename) }
            };
    }

592
    let output = if sess.building_library {
593 594 595
        let long_libname =
            std::os::dylib_filename(#fmt("%s-%s-%s",
                                         lm.name, lm.extras_hash, lm.vers));
596 597 598 599
        #debug("link_meta.name:  %s", lm.name);
        #debug("long_libname: %s", long_libname);
        #debug("out_filename: %s", out_filename);
        #debug("dirname(out_filename): %s", fs::dirname(out_filename));
600

601 602 603
        fs::connect(fs::dirname(out_filename), long_libname)
    } else { out_filename };

604
    log(debug, "output: " + output);
605

606 607
    // The default library location, we need this to find the runtime.
    // The location of crates will be determined as needed.
608
    let stage: str = "-L" + sess.filesearch.get_target_lib_path();
609

J
Jyun-Yan You 已提交
610 611
    // In the future, FreeBSD will use clang as default compiler.
    // It would be flexible to use cc (system's default C compiler)
612 613 614 615 616 617 618 619 620
    // instead of hard-coded gcc.
    // For win32, there is no cc command,
    // so we add a condition to make it use gcc.
    let cc_prog: str =
        if sess.targ_cfg.os == session::os_win32 { "gcc" } else { "cc" };
    // The invocations of cc share some flags across platforms

    let cc_args =
        [stage] + sess.targ_cfg.target_strs.cc_args +
621
        ["-o", output, obj_filename];
622

623
    let lib_cmd;
624
    let os = sess.targ_cfg.os;
625 626 627 628
    if os == session::os_macos {
        lib_cmd = "-dynamiclib";
    } else { lib_cmd = "-shared"; }

629
    let cstore = sess.cstore;
630 631
    for cratepath: str in cstore::get_used_crate_files(cstore) {
        if str::ends_with(cratepath, ".rlib") {
632
            cc_args += [cratepath];
633 634 635 636
            cont;
        }
        let cratepath = cratepath;
        let dir = fs::dirname(cratepath);
637
        if dir != "" { cc_args += ["-L" + dir]; }
638
        let libarg = unlib(sess.targ_cfg, fs::basename(cratepath));
639
        cc_args += ["-l" + libarg];
640 641 642
    }

    let ula = cstore::get_used_link_args(cstore);
643
    for arg: str in ula { cc_args += [arg]; }
644 645

    let used_libs = cstore::get_used_libraries(cstore);
646
    for l: str in used_libs { cc_args += ["-l" + l]; }
647

648
    if sess.building_library {
649
        cc_args += [lib_cmd];
B
Brian Anderson 已提交
650 651 652

        // On mac we need to tell the linker to let this library
        // be rpathed
653
        if sess.targ_cfg.os == session::os_macos {
654
            cc_args += ["-Wl,-install_name,@rpath/"
655
                        + fs::basename(output)];
B
Brian Anderson 已提交
656
        }
657 658
    } else {
        // FIXME: why do we hardcode -lm?
659
        cc_args += ["-lm"];
660 661
    }

B
Brian Anderson 已提交
662
    // Always want the runtime linked in
663
    cc_args += ["-lrustrt"];
664

665 666
    // On linux librt and libdl are an indirect dependencies via rustrt,
    // and binutils 2.22+ won't add them automatically
667
    if sess.targ_cfg.os == session::os_linux {
668
        cc_args += ["-lrt", "-ldl"];
669 670
    }

671
    if sess.targ_cfg.os == session::os_freebsd {
672
        cc_args += ["-lrt", "-L/usr/local/lib", "-lexecinfo",
J
Jyun-Yan You 已提交
673 674
                     "-L/usr/local/lib/gcc46",
                     "-L/usr/local/lib/gcc44", "-lstdc++",
J
Jyun-Yan You 已提交
675 676 677
                     "-Wl,-z,origin",
                     "-Wl,-rpath,/usr/local/lib/gcc46",
                     "-Wl,-rpath,/usr/local/lib/gcc44"];
U
User Jyyou 已提交
678 679
    }

680 681 682 683
    // OS X 10.6 introduced 'compact unwind info', which is produced by the
    // linker from the dwarf unwind info. Unfortunately, it does not seem to
    // understand how to unwind our __morestack frame, so we have to turn it
    // off. This has impacted some other projects like GHC.
684
    if sess.targ_cfg.os == session::os_macos {
685
        cc_args += ["-Wl,-no_compact_unwind"];
686 687
    }

688
    // Stack growth requires statically linking a __morestack function
689
    cc_args += ["-lmorestack"];
690

691
    cc_args += rpath::get_rpath_flags(sess, output);
B
Brian Anderson 已提交
692

693 694 695
    #debug("%s link args: %s", cc_prog, str::connect(cc_args, " "));
    // We run 'cc' here
    let prog = run::program_output(cc_prog, cc_args);
696
    if 0 != prog.status {
697 698 699 700
        sess.err(#fmt["linking with %s failed with code %d",
                      cc_prog, prog.status]);
        sess.note(#fmt["%s arguments: %s",
                       cc_prog, str::connect(cc_args, " ")]);
701
        sess.note(prog.err + prog.out);
702 703 704
        sess.abort_if_errors();
    }

705
    // Clean up on Darwin
706
    if sess.targ_cfg.os == session::os_macos {
707
        run::run_program("dsymutil", [output]);
708 709 710
    }

    // Remove the temporary object file if we aren't saving temps
711
    if !sess.opts.save_temps {
712
        run::run_program("rm", [obj_filename]);
713
    }
714
}
715 716 717 718 719 720 721 722 723
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//