From e75203ce82357f6d0f81d5644e77d3c2efe53fcb Mon Sep 17 00:00:00 2001 From: James Miller Date: Mon, 29 Apr 2013 14:54:41 +1200 Subject: [PATCH] Adds '--print-link-args' that outputs linker arguments that would be used --- src/librustc/back/link.rs | 294 +++++++++++++++++---------------- src/librustc/driver/driver.rs | 13 +- src/librustc/driver/session.rs | 5 + 3 files changed, 173 insertions(+), 139 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index aaa425c9334..adaffe5873d 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -747,34 +747,6 @@ pub fn link_binary(sess: Session, obj_filename: &Path, out_filename: &Path, lm: LinkMeta) { - // Converts a library file-stem into a cc -l argument - fn unlib(config: @session::config, stem: ~str) -> ~str { - if stem.starts_with("lib") && - config.os != session::os_win32 { - stem.slice(3, stem.len()).to_owned() - } else { - stem - } - } - - 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. @@ -794,119 +766,21 @@ pub fn link_binary(sess: Session, else { ~"cc" }; // The invocations of cc share some flags across platforms - 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()); - let lib_cmd; - let os = sess.targ_cfg.os; - if os == session::os_macos { - lib_cmd = ~"-dynamiclib"; + 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 { - lib_cmd = ~"-shared"; - } - - // # Crate linking - - let cstore = sess.cstore; - for cstore::get_used_crate_files(cstore).each |cratepath| { - if cratepath.filetype() == Some(~".rlib") { - cc_args.push(cratepath.to_str()); - loop; - } - let dir = cratepath.dirname(); - if dir != ~"" { cc_args.push(~"-L" + dir); } - let libarg = unlib(sess.targ_cfg, cratepath.filestem().get()); - cc_args.push(~"-l" + libarg); - } - - let ula = cstore::get_used_link_args(cstore); - for ula.each |arg| { cc_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); - } - } - - // # Extern library linking - - // User-supplied library search paths (-L on the cammand line) These are - // the same paths used to find Rust crates, so some of them may have been - // added already by the previous crate linking code. This only allows them - // to be found at compile time so it is still entirely up to outside - // 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()); - } - - // The names of the extern libraries - let used_libs = cstore::get_used_libraries(cstore); - for used_libs.each |l| { cc_args.push(~"-l" + *l); } - - if *sess.building_library { - cc_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/" - + output.filename().get()); - } - } - - // 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"]); - - // 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"); - } - else if sess.targ_cfg.os == session::os_android { - cc_args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", - ~"-lgnustl_shared"]); - cc_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"]); - } - - // 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. - if sess.targ_cfg.os == session::os_macos { - cc_args.push(~"-Wl,-no_compact_unwind"); - } - - // Stack growth requires statically linking a __morestack function - cc_args.push(~"-lmorestack"); - - // Always want the runtime linked in - cc_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)); - - // Finally add all the linker arguments provided on the command line - cc_args.push_all(sess.opts.linker_args); + /*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); @@ -932,6 +806,150 @@ pub fn link_binary(sess: Session, } } } + +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") && + config.os != session::os_win32 { + stem.slice(3, stem.len()).to_owned() + } else { + stem + } + } + + + let output = if *sess.building_library { + let long_libname = output_dll_filename(sess.targ_cfg.os, lm); + out_filename.dir_path().push(long_libname) + } else { + /*bad*/copy *out_filename + }; + + // 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(); + + let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); + + args.push(~"-o"); + args.push(output.to_str()); + args.push(obj_filename.to_str()); + + let lib_cmd; + let os = sess.targ_cfg.os; + if os == session::os_macos { + lib_cmd = ~"-dynamiclib"; + } else { + lib_cmd = ~"-shared"; + } + + // # Crate linking + + let cstore = sess.cstore; + for cstore::get_used_crate_files(cstore).each |cratepath| { + if cratepath.filetype() == Some(~".rlib") { + args.push(cratepath.to_str()); + loop; + } + let dir = cratepath.dirname(); + if dir != ~"" { args.push(~"-L" + dir); } + let libarg = unlib(sess.targ_cfg, cratepath.filestem().get()); + args.push(~"-l" + libarg); + } + + let ula = cstore::get_used_link_args(cstore); + 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| { + args.push(link_arg); + } + } + + // # Extern library linking + + // User-supplied library search paths (-L on the cammand line) These are + // the same paths used to find Rust crates, so some of them may have been + // added already by the previous crate linking code. This only allows them + // to be found at compile time so it is still entirely up to outside + // forces to make sure that library can be found at runtime. + + for sess.opts.addl_lib_search_paths.each |path| { + 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| { args.push(~"-l" + *l); } + + if *sess.building_library { + 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 { + args.push(~"-Wl,-install_name,@rpath/" + + output.filename().get()); + } + } + + // 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 { + 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 + args.push(~"-lm"); + } + else if sess.targ_cfg.os == session::os_android { + args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", + ~"-lgnustl_shared"]); + args.push(~"-lm"); + } + + if sess.targ_cfg.os == session::os_freebsd { + 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 + // 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. + if sess.targ_cfg.os == session::os_macos { + args.push(~"-Wl,-no_compact_unwind"); + } + + // Stack growth requires statically linking a __morestack function + args.push(~"-lmorestack"); + + // Always want the runtime linked in + 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 + args.push_all(rpath::get_rpath_flags(sess, &output)); + + // Finally add all the linker arguments provided on the command line + args.push_all(sess.opts.linker_args); + + return args; +} + // // Local Variables: // mode: rust diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index fbcbd4461ac..102b6631610 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 94d1da20f92..19b99f46b5e 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 } }