Adds '--print-link-args' that outputs linker arguments that would be used

This commit is contained in:
James Miller 2013-04-29 14:54:41 +12:00
parent 00ede34fcb
commit e75203ce82
3 changed files with 173 additions and 139 deletions

View file

@ -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

View file

@ -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;

View file

@ -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
}
}