diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index aaa425c93348a..adaffe5873dab 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -747,6 +747,71 @@ pub fn link_binary(sess: Session, obj_filename: &Path, out_filename: &Path, lm: LinkMeta) { + // In the future, FreeBSD will use clang as default compiler. + // It would be flexible to use cc (system's default C compiler) + // 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_android { + match &sess.opts.android_cross_path { + &Some(copy path) => { + fmt!("%s/bin/arm-linux-androideabi-gcc", path) + } + &None => { + sess.fatal(~"need Android NDK path for linking \ + (--android-cross-path)") + } + } + } else if sess.targ_cfg.os == session::os_win32 { ~"gcc" } + else { ~"cc" }; + // The invocations of cc share some flags across platforms + + + let output = if *sess.building_library { + let long_libname = output_dll_filename(sess.targ_cfg.os, lm); + debug!("link_meta.name: %s", lm.name); + debug!("long_libname: %s", long_libname); + debug!("out_filename: %s", out_filename.to_str()); + debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); + + out_filename.dir_path().push(long_libname) + } else { + /*bad*/copy *out_filename + }; + + debug!("output: %s", output.to_str()); + let mut cc_args = link_args(sess, obj_filename, out_filename, lm); + debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); + // We run 'cc' here + let prog = run::program_output(cc_prog, cc_args); + if 0 != prog.status { + 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, ~" "))); + sess.note(prog.err + prog.out); + sess.abort_if_errors(); + } + + // Clean up on Darwin + if sess.targ_cfg.os == session::os_macos { + run::run_program(~"dsymutil", ~[output.to_str()]); + } + + // Remove the temporary object file if we aren't saving temps + if !sess.opts.save_temps { + if ! os::remove_file(obj_filename) { + sess.warn(fmt!("failed to delete object file `%s`", + obj_filename.to_str())); + } + } +} + +pub fn link_args(sess: Session, + obj_filename: &Path, + out_filename: &Path, + lm:LinkMeta) -> ~[~str] { + // Converts a library file-stem into a cc -l argument fn unlib(config: @session::config, stem: ~str) -> ~str { if stem.starts_with("lib") && @@ -757,48 +822,23 @@ pub fn link_binary(sess: Session, } } + let output = if *sess.building_library { let long_libname = output_dll_filename(sess.targ_cfg.os, lm); - debug!("link_meta.name: %s", lm.name); - debug!("long_libname: %s", long_libname); - debug!("out_filename: %s", out_filename.to_str()); - debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); - out_filename.dir_path().push(long_libname) } else { /*bad*/copy *out_filename }; - debug!("output: %s", output.to_str()); - // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str(); - // In the future, FreeBSD will use clang as default compiler. - // It would be flexible to use cc (system's default C compiler) - // 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_android { - match &sess.opts.android_cross_path { - &Some(copy path) => { - fmt!("%s/bin/arm-linux-androideabi-gcc", path) - } - &None => { - sess.fatal(~"need Android NDK path for linking \ - (--android-cross-path)") - } - } - } else if sess.targ_cfg.os == session::os_win32 { ~"gcc" } - else { ~"cc" }; - // The invocations of cc share some flags across platforms + let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); - let mut cc_args = - vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); - cc_args.push(~"-o"); - cc_args.push(output.to_str()); - cc_args.push(obj_filename.to_str()); + args.push(~"-o"); + args.push(output.to_str()); + args.push(obj_filename.to_str()); let lib_cmd; let os = sess.targ_cfg.os; @@ -813,23 +853,23 @@ pub fn link_binary(sess: Session, let cstore = sess.cstore; for cstore::get_used_crate_files(cstore).each |cratepath| { if cratepath.filetype() == Some(~".rlib") { - cc_args.push(cratepath.to_str()); + args.push(cratepath.to_str()); loop; } let dir = cratepath.dirname(); - if dir != ~"" { cc_args.push(~"-L" + dir); } + if dir != ~"" { args.push(~"-L" + dir); } let libarg = unlib(sess.targ_cfg, cratepath.filestem().get()); - cc_args.push(~"-l" + libarg); + args.push(~"-l" + libarg); } let ula = cstore::get_used_link_args(cstore); - for ula.each |arg| { cc_args.push(/*bad*/copy *arg); } + for ula.each |arg| { args.push(/*bad*/copy *arg); } // Add all the link args for external crates. do cstore::iter_crate_data(cstore) |crate_num, _| { let link_args = csearch::get_link_args_for_crate(cstore, crate_num); do vec::consume(link_args) |_, link_arg| { - cc_args.push(link_arg); + args.push(link_arg); } } @@ -842,20 +882,20 @@ pub fn link_binary(sess: Session, // forces to make sure that library can be found at runtime. for sess.opts.addl_lib_search_paths.each |path| { - cc_args.push(~"-L" + path.to_str()); + args.push(~"-L" + path.to_str()); } // The names of the extern libraries let used_libs = cstore::get_used_libraries(cstore); - for used_libs.each |l| { cc_args.push(~"-l" + *l); } + for used_libs.each |l| { args.push(~"-l" + *l); } if *sess.building_library { - cc_args.push(lib_cmd); + args.push(lib_cmd); // On mac we need to tell the linker to let this library // be rpathed if sess.targ_cfg.os == session::os_macos { - cc_args.push(~"-Wl,-install_name,@rpath/" + args.push(~"-Wl,-install_name,@rpath/" + output.filename().get()); } } @@ -863,27 +903,27 @@ pub fn link_binary(sess: Session, // On linux librt and libdl are an indirect dependencies via rustrt, // and binutils 2.22+ won't add them automatically if sess.targ_cfg.os == session::os_linux { - cc_args.push_all(~[~"-lrt", ~"-ldl"]); + args.push_all(~[~"-lrt", ~"-ldl"]); // LLVM implements the `frem` instruction as a call to `fmod`, // which lives in libm. Similar to above, on some linuxes we // have to be explicit about linking to it. See #2510 - cc_args.push(~"-lm"); + args.push(~"-lm"); } else if sess.targ_cfg.os == session::os_android { - cc_args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", + args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]); - cc_args.push(~"-lm"); + args.push(~"-lm"); } if sess.targ_cfg.os == session::os_freebsd { - cc_args.push_all(~[~"-pthread", ~"-lrt", - ~"-L/usr/local/lib", ~"-lexecinfo", - ~"-L/usr/local/lib/gcc46", - ~"-L/usr/local/lib/gcc44", ~"-lstdc++", - ~"-Wl,-z,origin", - ~"-Wl,-rpath,/usr/local/lib/gcc46", - ~"-Wl,-rpath,/usr/local/lib/gcc44"]); + args.push_all(~[~"-pthread", ~"-lrt", + ~"-L/usr/local/lib", ~"-lexecinfo", + ~"-L/usr/local/lib/gcc46", + ~"-L/usr/local/lib/gcc44", ~"-lstdc++", + ~"-Wl,-z,origin", + ~"-Wl,-rpath,/usr/local/lib/gcc46", + ~"-Wl,-rpath,/usr/local/lib/gcc44"]); } // OS X 10.6 introduced 'compact unwind info', which is produced by the @@ -891,47 +931,25 @@ pub fn link_binary(sess: Session, // understand how to unwind our __morestack frame, so we have to turn it // off. This has impacted some other projects like GHC. if sess.targ_cfg.os == session::os_macos { - cc_args.push(~"-Wl,-no_compact_unwind"); + args.push(~"-Wl,-no_compact_unwind"); } // Stack growth requires statically linking a __morestack function - cc_args.push(~"-lmorestack"); + args.push(~"-lmorestack"); // Always want the runtime linked in - cc_args.push(~"-lrustrt"); + args.push(~"-lrustrt"); // FIXME (#2397): At some point we want to rpath our guesses as to where // extern libraries might live, based on the addl_lib_search_paths - cc_args.push_all(rpath::get_rpath_flags(sess, &output)); + args.push_all(rpath::get_rpath_flags(sess, &output)); // Finally add all the linker arguments provided on the command line - cc_args.push_all(sess.opts.linker_args); - - debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); - // We run 'cc' here - let prog = run::program_output(cc_prog, cc_args); - if 0 != prog.status { - 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, ~" "))); - sess.note(prog.err + prog.out); - sess.abort_if_errors(); - } + args.push_all(sess.opts.linker_args); - // Clean up on Darwin - if sess.targ_cfg.os == session::os_macos { - run::run_program(~"dsymutil", ~[output.to_str()]); - } - - // Remove the temporary object file if we aren't saving temps - if !sess.opts.save_temps { - if ! os::remove_file(obj_filename) { - sess.warn(fmt!("failed to delete object file `%s`", - obj_filename.to_str())); - } - } + return args; } + // // Local Variables: // mode: rust diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index fbcbd4461ac10..102b663161096 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -234,7 +234,6 @@ pub fn compile_rest(sess: Session, let rp_set = time(time_passes, ~"region parameterization inference", || middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate)); - let outputs = outputs.get(); let (llmod, link_meta) = { @@ -309,6 +308,11 @@ pub fn compile_rest(sess: Session, }; + if (sess.opts.output_info & session::out_link_args) > 0 { + io::println(str::connect(link::link_args(sess, + &outputs.obj_filename, &outputs.out_filename, link_meta), " ")); + } + // NB: Android hack if sess.targ_cfg.arch == abi::Arm && (sess.opts.output_type == link::output_type_object || @@ -659,6 +663,12 @@ pub fn build_session_options(binary: @~str, let test = opt_present(matches, ~"test"); let android_cross_path = getopts::opt_maybe_str( matches, ~"android-cross-path"); + + let mut output_info = 0; + if opt_present(matches, "print-link-args") { + output_info |= session::out_link_args; + } + let sopts = @session::options { crate_type: crate_type, is_static: static, @@ -681,6 +691,7 @@ pub fn build_session_options(binary: @~str, parse_only: parse_only, no_trans: no_trans, debugging_opts: debugging_opts, + output_info: output_info, android_cross_path: android_cross_path }; return sopts; diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 94d1da20f9268..19b99f46b5ed5 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -100,6 +100,9 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ] } +// Information output flags +pub static out_link_args : uint = 1 << 0; + #[deriving(Eq)] pub enum OptLevel { No, // -O0 @@ -136,6 +139,7 @@ pub struct options { parse_only: bool, no_trans: bool, debugging_opts: uint, + output_info: uint, android_cross_path: Option<~str> } @@ -310,6 +314,7 @@ pub fn basic_options() -> @options { parse_only: false, no_trans: false, debugging_opts: 0u, + output_info: 0u, android_cross_path: None } }