about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJames Miller <bladeon@gmail.com>2013-04-29 14:54:41 +1200
committerJames Miller <bladeon@gmail.com>2013-04-29 14:54:41 +1200
commite75203ce82357f6d0f81d5644e77d3c2efe53fcb (patch)
tree0a366c7913782b2d27c90f1a0222e1746ef6a05c
parent00ede34fcb4d6de11e49360964565c8e487a678e (diff)
downloadrust-e75203ce82357f6d0f81d5644e77d3c2efe53fcb.tar.gz
rust-e75203ce82357f6d0f81d5644e77d3c2efe53fcb.zip
Adds '--print-link-args' that outputs linker arguments that would be used
-rw-r--r--src/librustc/back/link.rs176
-rw-r--r--src/librustc/driver/driver.rs13
-rw-r--r--src/librustc/driver/session.rs5
3 files changed, 114 insertions, 80 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,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 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
     }
 }