1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use driver::session::Session;
15 use lib::llvm::ModuleRef;
17 use metadata::common::LinkMeta;
18 use metadata::{encoder, csearch, cstore};
19 use middle::trans::common::CrateContext;
23 use core::hash::Streaming;
25 use core::io::WriterUtil;
26 use core::libc::{c_int, c_uint};
27 use core::os::consts::{macos, freebsd, linux, android, win32};
30 use syntax::ast_map::{path, path_mod, path_name};
32 use syntax::print::pprust;
35 pub enum output_type {
39 output_type_llvm_assembly,
44 pub fn llvm_err(sess: Session, msg: ~str) -> ! {
46 let cstr = llvm::LLVMRustGetLastError();
47 if cstr == ptr::null() {
50 sess.fatal(msg + ~": " + str::raw::from_c_str(cstr));
55 pub fn WriteOutputFile(sess: Session,
56 PM: lib::llvm::PassManagerRef, M: ModuleRef,
60 // FIXME: When #2334 is fixed, change
64 EnableSegmentedStacks: bool) {
66 do str::as_c_str(Triple) |Triple| {
67 do str::as_c_str(Feature) |Feature| {
68 do str::as_c_str(Output) |Output| {
69 let result = llvm::LLVMRustWriteOutputFile(
77 EnableSegmentedStacks);
79 llvm_err(sess, ~"Could not write output");
88 use back::link::llvm_err;
89 use driver::session::Session;
91 use lib::llvm::{ModuleRef, PassManagerRef};
94 use core::libc::c_int;
98 #[abi = "rust-intrinsic"]
99 pub extern "rust-intrinsic" {
100 pub fn morestack_addr() -> *();
109 pub fn exec(sess: Session,
115 let manager = llvm::LLVMRustPrepareJIT(rusti::morestack_addr());
117 // We need to tell JIT where to resolve all linked
118 // symbols from. The equivalent of -lstd, -lcore, etc.
119 // By default the JIT will resolve symbols from the std and
120 // core linked into rustc. We don't want that,
121 // incase the user wants to use an older std library.
123 let cstore = sess.cstore;
124 for cstore::get_used_crate_files(cstore).each |cratepath| {
125 let path = cratepath.to_str();
127 debug!("linking: %s", path);
129 let _: () = str::as_c_str(
132 if !llvm::LLVMRustLoadCrate(manager, buf_t) {
133 llvm_err(sess, ~"Could not link");
135 debug!("linked: %s", path);
139 // The execute function will return a void pointer
140 // to the _rust_main function. We can do closure
141 // magic here to turn it straight into a callable rust
142 // closure. It will also cleanup the memory manager
145 let entry = llvm::LLVMRustExecuteJIT(manager,
148 if ptr::is_null(entry) {
149 llvm_err(sess, ~"Could not JIT");
151 let closure = Closure {
155 let func: &fn(argv: ~[@~str]) = cast::transmute(closure);
157 func(~[sess.opts.binary]);
165 use back::link::{WriteOutputFile, output_type};
166 use back::link::{output_type_assembly, output_type_bitcode};
167 use back::link::{output_type_exe, output_type_llvm_assembly};
168 use back::link::{output_type_object};
169 use back::link::output_type;
170 use driver::session::Session;
173 use lib::llvm::{False, ModuleRef, mk_pass_manager, mk_target_data};
176 use core::libc::{c_int, c_uint};
177 use core::path::Path;
180 pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
181 if ot == output_type_assembly || ot == output_type_object ||
182 ot == output_type_exe {
188 pub fn run_passes(sess: Session,
190 output_type: output_type,
193 let opts = sess.opts;
194 if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
195 let mut pm = mk_pass_manager();
196 let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
197 llvm::LLVMAddTargetData(td.lltd, pm.llpm);
198 // FIXME (#2812): run the linter here also, once there are llvm-c
201 // Generate a pre-optimization intermediate file if -save-temps
207 output_type_bitcode => {
208 if opts.optimize != session::No {
209 let filename = output.with_filetype("no-opt.bc");
210 str::as_c_str(filename.to_str(), |buf| {
211 llvm::LLVMWriteBitcodeToFile(llmod, buf)
216 let filename = output.with_filetype("bc");
217 str::as_c_str(filename.to_str(), |buf| {
218 llvm::LLVMWriteBitcodeToFile(llmod, buf)
223 if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
224 // FIXME (#2396): This is mostly a copy of the bits of opt's -O2
225 // that are available in the C api.
226 // Also: We might want to add optimization levels like -O1, -O2,
228 // Also: Should we expose and use the pass lists used by the opt
231 if opts.optimize != session::No {
232 let fpm = mk_pass_manager();
233 llvm::LLVMAddTargetData(td.lltd, fpm.llpm);
235 let FPMB = llvm::LLVMPassManagerBuilderCreate();
236 llvm::LLVMPassManagerBuilderSetOptLevel(FPMB, 2u as c_uint);
237 llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(
239 llvm::LLVMPassManagerBuilderDispose(FPMB);
241 llvm::LLVMRunPassManager(fpm.llpm, llmod);
242 let mut threshold = 225;
243 if opts.optimize == session::Aggressive { threshold = 275; }
245 let MPMB = llvm::LLVMPassManagerBuilderCreate();
246 llvm::LLVMPassManagerBuilderSetOptLevel(MPMB,
249 llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, False);
250 llvm::LLVMPassManagerBuilderSetDisableUnitAtATime(MPMB,
252 llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(MPMB,
254 llvm::LLVMPassManagerBuilderSetDisableSimplifyLibCalls(MPMB,
258 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold
259 (MPMB, threshold as c_uint);
261 llvm::LLVMPassManagerBuilderPopulateModulePassManager(
264 llvm::LLVMPassManagerBuilderDispose(MPMB);
266 if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
267 if is_object_or_assembly_or_exe(output_type) || opts.jit {
268 let LLVMOptNone = 0 as c_int; // -O0
269 let LLVMOptLess = 1 as c_int; // -O1
270 let LLVMOptDefault = 2 as c_int; // -O2, -Os
271 let LLVMOptAggressive = 3 as c_int; // -O3
273 let CodeGenOptLevel = match opts.optimize {
274 session::No => LLVMOptNone,
275 session::Less => LLVMOptLess,
276 session::Default => LLVMOptDefault,
277 session::Aggressive => LLVMOptAggressive
281 // If we are using JIT, go ahead and create and
282 // execute the engine now.
283 // JIT execution takes ownership of the module,
284 // so don't dispose and return.
286 jit::exec(sess, pm.llpm, llmod, CodeGenOptLevel, true);
288 if sess.time_llvm_passes() {
289 llvm::LLVMRustPrintPassTimings();
295 if output_type == output_type_object ||
296 output_type == output_type_exe {
297 FileType = lib::llvm::ObjectFile;
298 } else { FileType = lib::llvm::AssemblyFile; }
299 // Write optimized bitcode if --save-temps was on.
302 // Always output the bitcode file with --save-temps
304 let filename = output.with_filetype("opt.bc");
305 llvm::LLVMRunPassManager(pm.llpm, llmod);
306 str::as_c_str(filename.to_str(), |buf| {
307 llvm::LLVMWriteBitcodeToFile(llmod, buf)
309 pm = mk_pass_manager();
311 // Save the assembly file if -S is used
312 if output_type == output_type_assembly {
317 sess.targ_cfg.target_strs.target_triple,
320 lib::llvm::AssemblyFile as c_uint,
325 // Save the object file for -c or --save-temps alone
326 // This .o is needed when an exe is built
327 if output_type == output_type_object ||
328 output_type == output_type_exe {
333 sess.targ_cfg.target_strs.target_triple,
336 lib::llvm::ObjectFile as c_uint,
341 // If we aren't saving temps then just output the file
342 // type corresponding to the '-c' or '-S' flag used
347 sess.targ_cfg.target_strs.target_triple,
354 // Clean up and return
356 llvm::LLVMDisposeModule(llmod);
357 if sess.time_llvm_passes() {
358 llvm::LLVMRustPrintPassTimings();
363 if output_type == output_type_llvm_assembly {
364 // Given options "-S --emit-llvm": output LLVM assembly
365 str::as_c_str(output.to_str(), |buf_o| {
366 llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o)});
368 // If only a bitcode file is asked for by using the
369 // '--emit-llvm' flag, then output it here
370 llvm::LLVMRunPassManager(pm.llpm, llmod);
371 str::as_c_str(output.to_str(),
372 |buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) );
375 llvm::LLVMDisposeModule(llmod);
376 if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
380 pub fn run_ndk(sess: Session, assembly: &Path, object: &Path) {
381 let cc_prog: ~str = match &sess.opts.android_cross_path {
382 &Some(copy path) => {
383 fmt!("%s/bin/arm-linux-androideabi-gcc", path)
386 sess.fatal(~"need Android NDK path for building \
387 (--android-cross-path)")
390 let mut cc_args = ~[];
393 cc_args.push(object.to_str());
394 cc_args.push(assembly.to_str());
396 let prog = run::program_output(cc_prog, cc_args);
398 if prog.status != 0 {
399 sess.err(fmt!("building with `%s` failed with code %d",
400 cc_prog, prog.status));
401 sess.note(fmt!("%s arguments: %s",
402 cc_prog, str::connect(cc_args, ~" ")));
403 sess.note(prog.err + prog.out);
404 sess.abort_if_errors();
411 * Name mangling and its relationship to metadata. This is complex. Read
414 * The semantic model of Rust linkage is, broadly, that "there's no global
415 * namespace" between crates. Our aim is to preserve the illusion of this
416 * model despite the fact that it's not *quite* possible to implement on
417 * modern linkers. We initially didn't use system linkers at all, but have
418 * been convinced of their utility.
420 * There are a few issues to handle:
422 * - Linkers operate on a flat namespace, so we have to flatten names.
423 * We do this using the C++ namespace-mangling technique. Foo::bar
426 * - Symbols with the same name but different types need to get different
427 * linkage-names. We do this by hashing a string-encoding of the type into
428 * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
429 * we use SHA1) to "prevent collisions". This is not airtight but 16 hex
430 * digits on uniform probability means you're going to need 2**32 same-name
431 * symbols in the same process before you're even hitting birthday-paradox
432 * collision probability.
434 * - Symbols in different crates but with same names "within" the crate need
435 * to get different linkage-names.
437 * So here is what we do:
439 * - Separate the meta tags into two sets: exported and local. Only work with
440 * the exported ones when considering linkage.
442 * - Consider two exported tags as special (and mandatory): name and vers.
443 * Every crate gets them; if it doesn't name them explicitly we infer them
444 * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
446 * - Define CMETA as all the non-name, non-vers exported meta tags in the
447 * crate (in sorted order).
449 * - Define CMH as hash(CMETA + hashes of dependent crates).
451 * - Compile our crate to lib CNAME-CMH-CVERS.so
453 * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
455 * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
456 * name, non-name metadata, and type sense, and versioned in the way
457 * system linkers understand.
461 pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
462 symbol_hasher: &hash::State) -> LinkMeta {
464 struct ProvidedMetas {
467 cmh_items: ~[@ast::meta_item]
470 fn provided_link_metas(sess: Session, c: &ast::crate) ->
474 let mut cmh_items = ~[];
475 let linkage_metas = attr::find_linkage_metas(c.node.attrs);
476 attr::require_unique_names(sess.diagnostic(), linkage_metas);
477 for linkage_metas.each |meta| {
478 if *attr::get_meta_item_name(*meta) == ~"name" {
479 match attr::get_meta_item_value_str(*meta) {
480 // Changing attr would avoid the need for the copy
482 Some(v) => { name = Some(v.to_managed()); }
483 None => cmh_items.push(*meta)
485 } else if *attr::get_meta_item_name(*meta) == ~"vers" {
486 match attr::get_meta_item_value_str(*meta) {
487 Some(v) => { vers = Some(v.to_managed()); }
488 None => cmh_items.push(*meta)
490 } else { cmh_items.push(*meta); }
500 // This calculates CMH as defined above
501 fn crate_meta_extras_hash(symbol_hasher: &hash::State,
502 cmh_items: ~[@ast::meta_item],
503 dep_hashes: ~[~str]) -> @str {
504 fn len_and_str(s: &str) -> ~str {
505 fmt!("%u_%s", s.len(), s)
508 fn len_and_str_lit(l: ast::lit) -> ~str {
509 len_and_str(pprust::lit_to_str(@l))
512 let cmh_items = attr::sort_meta_items(cmh_items);
514 fn hash(symbol_hasher: &hash::State, m: &@ast::meta_item) {
516 ast::meta_name_value(key, value) => {
517 symbol_hasher.write_str(len_and_str(*key));
518 symbol_hasher.write_str(len_and_str_lit(value));
520 ast::meta_word(name) => {
521 symbol_hasher.write_str(len_and_str(*name));
523 ast::meta_list(name, ref mis) => {
524 symbol_hasher.write_str(len_and_str(*name));
526 hash(symbol_hasher, m_);
532 symbol_hasher.reset();
533 for cmh_items.each |m| {
534 hash(symbol_hasher, m);
537 for dep_hashes.each |dh| {
538 symbol_hasher.write_str(len_and_str(*dh));
541 // tjc: allocation is unfortunate; need to change core::hash
542 return truncated_hash_result(symbol_hasher).to_managed();
545 fn warn_missing(sess: Session, name: &str, default: &str) {
546 if !*sess.building_library { return; }
547 sess.warn(fmt!("missing crate link meta `%s`, using `%s` as default",
551 fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>)
553 return match opt_name {
556 // to_managed could go away if there was a version of
557 // filestem that returned an @str
558 let name = session::expect(sess,
560 || fmt!("output file name `%s` doesn't\
561 appear to have a stem",
562 output.to_str())).to_managed();
563 warn_missing(sess, ~"name", name);
569 fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str {
570 return match opt_vers {
574 warn_missing(sess, ~"vers", vers);
584 } = provided_link_metas(sess, c);
585 let name = crate_meta_name(sess, output, opt_name);
586 let vers = crate_meta_vers(sess, opt_vers);
587 let dep_hashes = cstore::get_dep_hashes(sess.cstore);
589 crate_meta_extras_hash(symbol_hasher, cmh_items,
595 extras_hash: extras_hash
599 pub fn truncated_hash_result(symbol_hasher: &hash::State) -> ~str {
600 symbol_hasher.result_str()
604 // This calculates STH for a symbol, as defined above
605 pub fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &hash::State, t: ty::t,
606 link_meta: LinkMeta) -> @str {
607 // NB: do *not* use abbrevs here as we want the symbol names
608 // to be independent of one another in the crate.
610 symbol_hasher.reset();
611 symbol_hasher.write_str(link_meta.name);
612 symbol_hasher.write_str(~"-");
613 symbol_hasher.write_str(link_meta.extras_hash);
614 symbol_hasher.write_str(~"-");
615 symbol_hasher.write_str(encoder::encoded_ty(tcx, t));
616 let mut hash = truncated_hash_result(symbol_hasher);
617 // Prefix with _ so that it never blends into adjacent digits
618 str::unshift_char(&mut hash, '_');
619 // tjc: allocation is unfortunate; need to change core::hash
623 pub fn get_symbol_hash(ccx: @CrateContext, t: ty::t) -> @str {
624 match ccx.type_hashcodes.find(&t) {
627 let hash = symbol_hash(ccx.tcx, ccx.symbol_hasher, t, ccx.link_meta);
628 ccx.type_hashcodes.insert(t, hash);
635 // Name sanitation. LLVM will happily accept identifiers with weird names, but
637 pub fn sanitize(s: &str) -> ~str {
638 let mut result = ~"";
639 for str::each_char(s) |c| {
641 '@' => result += ~"_sbox_",
642 '~' => result += ~"_ubox_",
643 '*' => result += ~"_ptr_",
644 '&' => result += ~"_ref_",
645 ',' => result += ~"_",
647 '{' | '(' => result += ~"_of_",
651 | '_' => result.push_char(c),
653 if c > 'z' && char::is_XID_continue(c) {
660 // Underscore-qualify anything that didn't start as an ident.
661 if result.len() > 0u &&
662 result[0] != '_' as u8 &&
663 ! char::is_XID_start(result[0] as char) {
664 return ~"_" + result;
670 pub fn mangle(sess: Session, ss: path) -> ~str {
671 // Follow C++ namespace-mangling style
673 let mut n = ~"_ZN"; // Begin name-sequence.
676 match *s { path_name(s) | path_mod(s) => {
677 let sani = sanitize(*sess.str_of(s));
678 n += fmt!("%u%s", str::len(sani), sani);
681 n += ~"E"; // End name-sequence.
685 pub fn exported_name(sess: Session,
688 vers: &str) -> ~str {
691 vec::append_one(path, path_name(sess.ident_of(hash.to_owned()))),
692 path_name(sess.ident_of(vers.to_owned()))));
695 pub fn mangle_exported_name(ccx: @CrateContext,
698 let hash = get_symbol_hash(ccx, t);
699 return exported_name(ccx.sess, path,
704 pub fn mangle_internal_name_by_type_only(ccx: @CrateContext,
706 name: &str) -> ~str {
707 let s = ppaux::ty_to_short_str(ccx.tcx, t);
708 let hash = get_symbol_hash(ccx, t);
709 return mangle(ccx.sess,
710 ~[path_name(ccx.sess.ident_of(name.to_owned())),
711 path_name(ccx.sess.ident_of(s)),
712 path_name(ccx.sess.ident_of(hash.to_owned()))]);
715 pub fn mangle_internal_name_by_path_and_seq(ccx: @CrateContext,
717 flav: ~str) -> ~str {
718 return mangle(ccx.sess,
719 vec::append_one(path, path_name((ccx.names)(flav))));
722 pub fn mangle_internal_name_by_path(ccx: @CrateContext, path: path) -> ~str {
723 return mangle(ccx.sess, path);
726 pub fn mangle_internal_name_by_seq(ccx: @CrateContext, flav: ~str) -> ~str {
727 return fmt!("%s_%u", flav, (ccx.names)(flav).repr);
731 pub fn output_dll_filename(os: session::os, lm: LinkMeta) -> ~str {
732 let libname = fmt!("%s-%s-%s", lm.name, lm.extras_hash, lm.vers);
733 let (dll_prefix, dll_suffix) = match os {
734 session::os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
735 session::os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
736 session::os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
737 session::os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
738 session::os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
740 return str::from_slice(dll_prefix) + libname +
741 str::from_slice(dll_suffix);
744 // If the user wants an exe generated we need to invoke
745 // cc to link the object file with some libs
746 pub fn link_binary(sess: Session,
750 // In the future, FreeBSD will use clang as default compiler.
751 // It would be flexible to use cc (system's default C compiler)
752 // instead of hard-coded gcc.
753 // For win32, there is no cc command,
754 // so we add a condition to make it use gcc.
755 let cc_prog: ~str = match sess.opts.linker {
756 Some(copy linker) => linker,
758 if sess.targ_cfg.os == session::os_android {
759 match &sess.opts.android_cross_path {
760 &Some(copy path) => {
761 fmt!("%s/bin/arm-linux-androideabi-gcc", path)
764 sess.fatal(~"need Android NDK path for linking \
765 (--android-cross-path)")
768 } else if sess.targ_cfg.os == session::os_win32 {
775 // The invocations of cc share some flags across platforms
778 let output = if *sess.building_library {
779 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
780 debug!("link_meta.name: %s", lm.name);
781 debug!("long_libname: %s", long_libname);
782 debug!("out_filename: %s", out_filename.to_str());
783 debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
785 out_filename.dir_path().push(long_libname)
787 /*bad*/copy *out_filename
790 debug!("output: %s", output.to_str());
791 let mut cc_args = link_args(sess, obj_filename, out_filename, lm);
792 debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" "));
794 let prog = run::program_output(cc_prog, cc_args);
795 if 0 != prog.status {
796 sess.err(fmt!("linking with `%s` failed with code %d",
797 cc_prog, prog.status));
798 sess.note(fmt!("%s arguments: %s",
799 cc_prog, str::connect(cc_args, ~" ")));
800 sess.note(prog.err + prog.out);
801 sess.abort_if_errors();
804 // Clean up on Darwin
805 if sess.targ_cfg.os == session::os_macos {
806 run::run_program(~"dsymutil", ~[output.to_str()]);
809 // Remove the temporary object file if we aren't saving temps
810 if !sess.opts.save_temps {
811 if ! os::remove_file(obj_filename) {
812 sess.warn(fmt!("failed to delete object file `%s`",
813 obj_filename.to_str()));
818 pub fn link_args(sess: Session,
821 lm:LinkMeta) -> ~[~str] {
823 // Converts a library file-stem into a cc -l argument
824 fn unlib(config: @session::config, stem: ~str) -> ~str {
825 if stem.starts_with("lib") &&
826 config.os != session::os_win32 {
827 stem.slice(3, stem.len()).to_owned()
834 let output = if *sess.building_library {
835 let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
836 out_filename.dir_path().push(long_libname)
838 /*bad*/copy *out_filename
841 // The default library location, we need this to find the runtime.
842 // The location of crates will be determined as needed.
843 let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
845 let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
848 args.push(output.to_str());
849 args.push(obj_filename.to_str());
852 let os = sess.targ_cfg.os;
853 if os == session::os_macos {
854 lib_cmd = ~"-dynamiclib";
856 lib_cmd = ~"-shared";
861 let cstore = sess.cstore;
862 for cstore::get_used_crate_files(cstore).each |cratepath| {
863 if cratepath.filetype() == Some(~".rlib") {
864 args.push(cratepath.to_str());
867 let dir = cratepath.dirname();
868 if dir != ~"" { args.push(~"-L" + dir); }
869 let libarg = unlib(sess.targ_cfg, cratepath.filestem().get());
870 args.push(~"-l" + libarg);
873 let ula = cstore::get_used_link_args(cstore);
874 for ula.each |arg| { args.push(/*bad*/copy *arg); }
876 // Add all the link args for external crates.
877 do cstore::iter_crate_data(cstore) |crate_num, _| {
878 let link_args = csearch::get_link_args_for_crate(cstore, crate_num);
879 do vec::consume(link_args) |_, link_arg| {
884 // # Extern library linking
886 // User-supplied library search paths (-L on the cammand line) These are
887 // the same paths used to find Rust crates, so some of them may have been
888 // added already by the previous crate linking code. This only allows them
889 // to be found at compile time so it is still entirely up to outside
890 // forces to make sure that library can be found at runtime.
892 for sess.opts.addl_lib_search_paths.each |path| {
893 args.push(~"-L" + path.to_str());
896 // The names of the extern libraries
897 let used_libs = cstore::get_used_libraries(cstore);
898 for used_libs.each |l| { args.push(~"-l" + *l); }
900 if *sess.building_library {
903 // On mac we need to tell the linker to let this library
905 if sess.targ_cfg.os == session::os_macos {
906 args.push(~"-Wl,-install_name,@rpath/"
907 + output.filename().get());
911 // On linux librt and libdl are an indirect dependencies via rustrt,
912 // and binutils 2.22+ won't add them automatically
913 if sess.targ_cfg.os == session::os_linux {
914 args.push_all(~[~"-lrt", ~"-ldl"]);
916 // LLVM implements the `frem` instruction as a call to `fmod`,
917 // which lives in libm. Similar to above, on some linuxes we
918 // have to be explicit about linking to it. See #2510
921 else if sess.targ_cfg.os == session::os_android {
922 args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++",
923 ~"-lgnustl_shared"]);
927 if sess.targ_cfg.os == session::os_freebsd {
928 args.push_all(~[~"-pthread", ~"-lrt",
929 ~"-L/usr/local/lib", ~"-lexecinfo",
930 ~"-L/usr/local/lib/gcc46",
931 ~"-L/usr/local/lib/gcc44", ~"-lstdc++",
933 ~"-Wl,-rpath,/usr/local/lib/gcc46",
934 ~"-Wl,-rpath,/usr/local/lib/gcc44"]);
937 // OS X 10.6 introduced 'compact unwind info', which is produced by the
938 // linker from the dwarf unwind info. Unfortunately, it does not seem to
939 // understand how to unwind our __morestack frame, so we have to turn it
940 // off. This has impacted some other projects like GHC.
941 if sess.targ_cfg.os == session::os_macos {
942 args.push(~"-Wl,-no_compact_unwind");
945 // Stack growth requires statically linking a __morestack function
946 args.push(~"-lmorestack");
948 // Always want the runtime linked in
949 args.push(~"-lrustrt");
951 // FIXME (#2397): At some point we want to rpath our guesses as to where
952 // extern libraries might live, based on the addl_lib_search_paths
953 args.push_all(rpath::get_rpath_flags(sess, &output));
955 // Finally add all the linker arguments provided on the command line
956 args.push_all(sess.opts.linker_args);