Skip to content

Commit cb527bf

Browse files
committed
auto merge of #6105 : Aatch/rust/linker-improv, r=pcwalton
Adds two extra flags: `--linker` which takes extra flags to pass to the linker, can be used multiple times and `--print-link-args` which prints out linker arguments. Currently `--print-link-args` needs execution to get past translation to get the `LinkMeta` data. I haven't done tests or updated any extra documentation yet, so this pull request is currently here for review.
2 parents 7a85767 + 2deefbe commit cb527bf

File tree

3 files changed

+171
-131
lines changed

3 files changed

+171
-131
lines changed

src/librustc/back/link.rs

+98-77
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,71 @@ pub fn link_binary(sess: Session,
747747
obj_filename: &Path,
748748
out_filename: &Path,
749749
lm: LinkMeta) {
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 = if sess.targ_cfg.os == session::os_android {
756+
match &sess.opts.android_cross_path {
757+
&Some(copy path) => {
758+
fmt!("%s/bin/arm-linux-androideabi-gcc", path)
759+
}
760+
&None => {
761+
sess.fatal(~"need Android NDK path for linking \
762+
(--android-cross-path)")
763+
}
764+
}
765+
} else if sess.targ_cfg.os == session::os_win32 { ~"gcc" }
766+
else { ~"cc" };
767+
// The invocations of cc share some flags across platforms
768+
769+
770+
let output = if *sess.building_library {
771+
let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
772+
debug!("link_meta.name: %s", lm.name);
773+
debug!("long_libname: %s", long_libname);
774+
debug!("out_filename: %s", out_filename.to_str());
775+
debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
776+
777+
out_filename.dir_path().push(long_libname)
778+
} else {
779+
/*bad*/copy *out_filename
780+
};
781+
782+
debug!("output: %s", output.to_str());
783+
let mut cc_args = link_args(sess, obj_filename, out_filename, lm);
784+
debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" "));
785+
// We run 'cc' here
786+
let prog = run::program_output(cc_prog, cc_args);
787+
if 0 != prog.status {
788+
sess.err(fmt!("linking with `%s` failed with code %d",
789+
cc_prog, prog.status));
790+
sess.note(fmt!("%s arguments: %s",
791+
cc_prog, str::connect(cc_args, ~" ")));
792+
sess.note(prog.err + prog.out);
793+
sess.abort_if_errors();
794+
}
795+
796+
// Clean up on Darwin
797+
if sess.targ_cfg.os == session::os_macos {
798+
run::run_program(~"dsymutil", ~[output.to_str()]);
799+
}
800+
801+
// Remove the temporary object file if we aren't saving temps
802+
if !sess.opts.save_temps {
803+
if ! os::remove_file(obj_filename) {
804+
sess.warn(fmt!("failed to delete object file `%s`",
805+
obj_filename.to_str()));
806+
}
807+
}
808+
}
809+
810+
pub fn link_args(sess: Session,
811+
obj_filename: &Path,
812+
out_filename: &Path,
813+
lm:LinkMeta) -> ~[~str] {
814+
750815
// Converts a library file-stem into a cc -l argument
751816
fn unlib(config: @session::config, stem: ~str) -> ~str {
752817
if stem.starts_with("lib") &&
@@ -757,48 +822,23 @@ pub fn link_binary(sess: Session,
757822
}
758823
}
759824

825+
760826
let output = if *sess.building_library {
761827
let long_libname = output_dll_filename(sess.targ_cfg.os, lm);
762-
debug!("link_meta.name: %s", lm.name);
763-
debug!("long_libname: %s", long_libname);
764-
debug!("out_filename: %s", out_filename.to_str());
765-
debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
766-
767828
out_filename.dir_path().push(long_libname)
768829
} else {
769830
/*bad*/copy *out_filename
770831
};
771832

772-
debug!("output: %s", output.to_str());
773-
774833
// The default library location, we need this to find the runtime.
775834
// The location of crates will be determined as needed.
776835
let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
777836

778-
// In the future, FreeBSD will use clang as default compiler.
779-
// It would be flexible to use cc (system's default C compiler)
780-
// instead of hard-coded gcc.
781-
// For win32, there is no cc command,
782-
// so we add a condition to make it use gcc.
783-
let cc_prog: ~str = if sess.targ_cfg.os == session::os_android {
784-
match &sess.opts.android_cross_path {
785-
&Some(copy path) => {
786-
fmt!("%s/bin/arm-linux-androideabi-gcc", path)
787-
}
788-
&None => {
789-
sess.fatal(~"need Android NDK path for linking \
790-
(--android-cross-path)")
791-
}
792-
}
793-
} else if sess.targ_cfg.os == session::os_win32 { ~"gcc" }
794-
else { ~"cc" };
795-
// The invocations of cc share some flags across platforms
837+
let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
796838

797-
let mut cc_args =
798-
vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
799-
cc_args.push(~"-o");
800-
cc_args.push(output.to_str());
801-
cc_args.push(obj_filename.to_str());
839+
args.push(~"-o");
840+
args.push(output.to_str());
841+
args.push(obj_filename.to_str());
802842

803843
let lib_cmd;
804844
let os = sess.targ_cfg.os;
@@ -813,23 +853,23 @@ pub fn link_binary(sess: Session,
813853
let cstore = sess.cstore;
814854
for cstore::get_used_crate_files(cstore).each |cratepath| {
815855
if cratepath.filetype() == Some(~".rlib") {
816-
cc_args.push(cratepath.to_str());
856+
args.push(cratepath.to_str());
817857
loop;
818858
}
819859
let dir = cratepath.dirname();
820-
if dir != ~"" { cc_args.push(~"-L" + dir); }
860+
if dir != ~"" { args.push(~"-L" + dir); }
821861
let libarg = unlib(sess.targ_cfg, cratepath.filestem().get());
822-
cc_args.push(~"-l" + libarg);
862+
args.push(~"-l" + libarg);
823863
}
824864

825865
let ula = cstore::get_used_link_args(cstore);
826-
for ula.each |arg| { cc_args.push(/*bad*/copy *arg); }
866+
for ula.each |arg| { args.push(/*bad*/copy *arg); }
827867

828868
// Add all the link args for external crates.
829869
do cstore::iter_crate_data(cstore) |crate_num, _| {
830870
let link_args = csearch::get_link_args_for_crate(cstore, crate_num);
831871
do vec::consume(link_args) |_, link_arg| {
832-
cc_args.push(link_arg);
872+
args.push(link_arg);
833873
}
834874
}
835875

@@ -842,93 +882,74 @@ pub fn link_binary(sess: Session,
842882
// forces to make sure that library can be found at runtime.
843883

844884
for sess.opts.addl_lib_search_paths.each |path| {
845-
cc_args.push(~"-L" + path.to_str());
885+
args.push(~"-L" + path.to_str());
846886
}
847887

848888
// The names of the extern libraries
849889
let used_libs = cstore::get_used_libraries(cstore);
850-
for used_libs.each |l| { cc_args.push(~"-l" + *l); }
890+
for used_libs.each |l| { args.push(~"-l" + *l); }
851891

852892
if *sess.building_library {
853-
cc_args.push(lib_cmd);
893+
args.push(lib_cmd);
854894

855895
// On mac we need to tell the linker to let this library
856896
// be rpathed
857897
if sess.targ_cfg.os == session::os_macos {
858-
cc_args.push(~"-Wl,-install_name,@rpath/"
898+
args.push(~"-Wl,-install_name,@rpath/"
859899
+ output.filename().get());
860900
}
861901
}
862902

863903
// On linux librt and libdl are an indirect dependencies via rustrt,
864904
// and binutils 2.22+ won't add them automatically
865905
if sess.targ_cfg.os == session::os_linux {
866-
cc_args.push_all(~[~"-lrt", ~"-ldl"]);
906+
args.push_all(~[~"-lrt", ~"-ldl"]);
867907

868908
// LLVM implements the `frem` instruction as a call to `fmod`,
869909
// which lives in libm. Similar to above, on some linuxes we
870910
// have to be explicit about linking to it. See #2510
871-
cc_args.push(~"-lm");
911+
args.push(~"-lm");
872912
}
873913
else if sess.targ_cfg.os == session::os_android {
874-
cc_args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++",
914+
args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++",
875915
~"-lgnustl_shared"]);
876-
cc_args.push(~"-lm");
916+
args.push(~"-lm");
877917
}
878918

879919
if sess.targ_cfg.os == session::os_freebsd {
880-
cc_args.push_all(~[~"-pthread", ~"-lrt",
881-
~"-L/usr/local/lib", ~"-lexecinfo",
882-
~"-L/usr/local/lib/gcc46",
883-
~"-L/usr/local/lib/gcc44", ~"-lstdc++",
884-
~"-Wl,-z,origin",
885-
~"-Wl,-rpath,/usr/local/lib/gcc46",
886-
~"-Wl,-rpath,/usr/local/lib/gcc44"]);
920+
args.push_all(~[~"-pthread", ~"-lrt",
921+
~"-L/usr/local/lib", ~"-lexecinfo",
922+
~"-L/usr/local/lib/gcc46",
923+
~"-L/usr/local/lib/gcc44", ~"-lstdc++",
924+
~"-Wl,-z,origin",
925+
~"-Wl,-rpath,/usr/local/lib/gcc46",
926+
~"-Wl,-rpath,/usr/local/lib/gcc44"]);
887927
}
888928

889929
// OS X 10.6 introduced 'compact unwind info', which is produced by the
890930
// linker from the dwarf unwind info. Unfortunately, it does not seem to
891931
// understand how to unwind our __morestack frame, so we have to turn it
892932
// off. This has impacted some other projects like GHC.
893933
if sess.targ_cfg.os == session::os_macos {
894-
cc_args.push(~"-Wl,-no_compact_unwind");
934+
args.push(~"-Wl,-no_compact_unwind");
895935
}
896936

897937
// Stack growth requires statically linking a __morestack function
898-
cc_args.push(~"-lmorestack");
938+
args.push(~"-lmorestack");
899939

900940
// Always want the runtime linked in
901-
cc_args.push(~"-lrustrt");
941+
args.push(~"-lrustrt");
902942

903943
// FIXME (#2397): At some point we want to rpath our guesses as to where
904944
// extern libraries might live, based on the addl_lib_search_paths
905-
cc_args.push_all(rpath::get_rpath_flags(sess, &output));
945+
args.push_all(rpath::get_rpath_flags(sess, &output));
906946

907-
debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" "));
908-
// We run 'cc' here
909-
let prog = run::program_output(cc_prog, cc_args);
910-
if 0 != prog.status {
911-
sess.err(fmt!("linking with `%s` failed with code %d",
912-
cc_prog, prog.status));
913-
sess.note(fmt!("%s arguments: %s",
914-
cc_prog, str::connect(cc_args, ~" ")));
915-
sess.note(prog.err + prog.out);
916-
sess.abort_if_errors();
917-
}
947+
// Finally add all the linker arguments provided on the command line
948+
args.push_all(sess.opts.linker_args);
918949

919-
// Clean up on Darwin
920-
if sess.targ_cfg.os == session::os_macos {
921-
run::run_program(~"dsymutil", ~[output.to_str()]);
922-
}
923-
924-
// Remove the temporary object file if we aren't saving temps
925-
if !sess.opts.save_temps {
926-
if ! os::remove_file(obj_filename) {
927-
sess.warn(fmt!("failed to delete object file `%s`",
928-
obj_filename.to_str()));
929-
}
930-
}
950+
return args;
931951
}
952+
932953
//
933954
// Local Variables:
934955
// mode: rust

0 commit comments

Comments
 (0)