Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Self contained linking option #72738

Merged
merged 3 commits into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 54 additions & 26 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,12 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
// The third parameter is for env vars, used on windows to set up the
// path for MSVC to find its DLLs, and gcc to find its bundled
// toolchain
fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
fn get_linker(
sess: &Session,
linker: &Path,
flavor: LinkerFlavor,
self_contained: bool,
) -> Command {
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");

// If our linker looks like a batch script on Windows then to execute this
Expand Down Expand Up @@ -199,7 +204,7 @@ fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {

// The compiler's sysroot often has some bundled tools, so add it to the
// PATH for the child.
let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
let mut msvc_changed_path = false;
if sess.target.target.options.is_like_msvc {
if let Some(ref tool) = msvc_tool {
Expand Down Expand Up @@ -551,19 +556,25 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
"Linker does not support -static-pie command line option. Retrying with -static instead."
);
// Mirror `add_(pre,post)_link_objects` to replace CRT objects.
let fallback = crt_objects_fallback(sess, crate_type);
let self_contained = crt_objects_fallback(sess, crate_type);
let opts = &sess.target.target.options;
let pre_objects =
if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
let post_objects =
if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
let pre_objects = if self_contained {
&opts.pre_link_objects_fallback
} else {
&opts.pre_link_objects
};
let post_objects = if self_contained {
&opts.post_link_objects_fallback
} else {
&opts.post_link_objects
};
let get_objects = |objects: &CrtObjects, kind| {
objects
.get(&kind)
.iter()
.copied()
.flatten()
.map(|obj| get_object_file_path(sess, obj).into_os_string())
.map(|obj| get_object_file_path(sess, obj, self_contained).into_os_string())
.collect::<Vec<_>>()
};
let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe);
Expand Down Expand Up @@ -1066,9 +1077,11 @@ fn get_crt_libs_path(sess: &Session) -> Option<PathBuf> {
}
}

fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf {
// prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details
if sess.target.target.llvm_target.contains("windows-gnu") {
if sess.opts.debugging_opts.link_self_contained.is_none()
&& sess.target.target.llvm_target.contains("windows-gnu")
{
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
let file_path = compiler_libs_path.join(name);
if file_path.exists() {
Expand All @@ -1081,9 +1094,12 @@ fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
if file_path.exists() {
return file_path;
}
let file_path = fs.get_selfcontained_lib_path().join(name);
if file_path.exists() {
return file_path;
// Special directory with objects used only in self-contained linkage mode
if self_contained {
let file_path = fs.get_self_contained_lib_path().join(name);
if file_path.exists() {
return file_path;
}
}
for search_path in fs.search_paths() {
let file_path = search_path.dir.join(name);
Expand Down Expand Up @@ -1268,6 +1284,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
/// Whether we link to our own CRT objects instead of relying on gcc to pull them.
/// We only provide such support for a very limited number of targets.
fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained {
return self_contained;
}

match sess.target.target.options.crt_objects_fallback {
// FIXME: Find a better heuristic for "native musl toolchain is available",
// based on host and linker path, for example.
Expand All @@ -1287,12 +1307,13 @@ fn add_pre_link_objects(
cmd: &mut dyn Linker,
sess: &Session,
link_output_kind: LinkOutputKind,
fallback: bool,
self_contained: bool,
) {
let opts = &sess.target.target.options;
let objects = if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
let objects =
if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
for obj in objects.get(&link_output_kind).iter().copied().flatten() {
cmd.add_object(&get_object_file_path(sess, obj));
cmd.add_object(&get_object_file_path(sess, obj, self_contained));
}
}

Expand All @@ -1301,12 +1322,13 @@ fn add_post_link_objects(
cmd: &mut dyn Linker,
sess: &Session,
link_output_kind: LinkOutputKind,
fallback: bool,
self_contained: bool,
) {
let opts = &sess.target.target.options;
let objects = if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
let objects =
if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
for obj in objects.get(&link_output_kind).iter().copied().flatten() {
cmd.add_object(&get_object_file_path(sess, obj));
cmd.add_object(&get_object_file_path(sess, obj, self_contained));
}
}

Expand Down Expand Up @@ -1468,9 +1490,12 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'
}

/// Add sysroot and other globally set directories to the directory search list.
fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
// Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details.
if cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") {
if sess.opts.debugging_opts.link_self_contained.is_none()
&& cfg!(windows)
&& sess.target.target.llvm_target.contains("windows-gnu")
{
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
cmd.include_path(&compiler_libs_path);
}
Expand All @@ -1481,8 +1506,11 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));

let lib_path = sess.target_filesearch(PathKind::All).get_selfcontained_lib_path();
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
// Special directory with libraries used only in self-contained linkage mode
if self_contained {
let lib_path = sess.target_filesearch(PathKind::All).get_self_contained_lib_path();
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
}
}

/// Add options making relocation sections in the produced ELF files read-only
Expand Down Expand Up @@ -1545,13 +1573,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
codegen_results: &CodegenResults,
target_cpu: &str,
) -> Command {
let base_cmd = get_linker(sess, path, flavor);
let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback);
// FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
// to the linker args construction.
assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp");
let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
let link_output_kind = link_output_kind(sess, crate_type);
let crt_objects_fallback = crt_objects_fallback(sess, crate_type);

// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
add_pre_link_args(cmd, sess, flavor);
Expand Down Expand Up @@ -1597,7 +1625,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(

// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
// FIXME: Order-dependent, at least relatively to other args adding searh directories.
add_library_search_dirs(cmd, sess);
add_library_search_dirs(cmd, sess, crt_objects_fallback);

// OBJECT-FILES-YES
add_local_crate_regular_objects(cmd, codegen_results);
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_session/filesearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl<'a> FileSearch<'a> {
make_target_lib_path(self.sysroot, self.triple)
}

pub fn get_selfcontained_lib_path(&self) -> PathBuf {
pub fn get_self_contained_lib_path(&self) -> PathBuf {
self.get_lib_path().join("self-contained")
}

Expand Down Expand Up @@ -92,13 +92,13 @@ impl<'a> FileSearch<'a> {
}

// Returns a list of directories where target-specific tool binaries are located.
pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
let mut p = PathBuf::from(self.sysroot);
p.push(find_libdir(self.sysroot).as_ref());
p.push(RUST_LIB_DIR);
p.push(&self.triple);
p.push("bin");
vec![p.clone(), p.join("self-contained")]
if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p.clone()] }
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/librustc_session/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"keep hygiene data after analysis (default: no)"),
link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
"link native libraries in the linker invocation (default: yes)"),
link_self_contained: Option<bool> = (None, parse_opt_bool, [TRACKED],
"control whether to link Rust provided C objects/libraries or rely
on C toolchain installed in the system"),
link_only: bool = (false, parse_bool, [TRACKED],
"link the `.rlink` file generated by `-Z no-link` (default: no)"),
llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
Expand Down