Skip to content

Use the correct crt*.o files when linking musl targets. #50105

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

Merged
merged 6 commits into from
May 11, 2018
Merged
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
9 changes: 9 additions & 0 deletions src/bootstrap/bin/rustc.rs
Original file line number Diff line number Diff line change
@@ -261,6 +261,15 @@ fn main() {
if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
cmd.arg(format!("-Clinker={}", host_linker));
}

if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
if s == "true" {
cmd.arg("-C").arg("target-feature=+crt-static");
}
if s == "false" {
cmd.arg("-C").arg("target-feature=-crt-static");
}
}
}

if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() {
33 changes: 30 additions & 3 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
@@ -489,7 +489,7 @@ def bin_root(self):
"""
return os.path.join(self.build_dir, self.build, "stage0")

def get_toml(self, key):
def get_toml(self, key, section=None):
"""Returns the value of the given key in config.toml, otherwise returns None

>>> rb = RustBuild()
@@ -501,12 +501,29 @@ def get_toml(self, key):

>>> rb.get_toml("key3") is None
True

Optionally also matches the section the key appears in

>>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
>>> rb.get_toml('key', 'a')
'value1'
>>> rb.get_toml('key', 'b')
'value2'
>>> rb.get_toml('key', 'c') is None
True
"""

cur_section = None
for line in self.config_toml.splitlines():
section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
if section_match is not None:
cur_section = section_match.group(1)

match = re.match(r'^{}\s*=(.*)$'.format(key), line)
if match is not None:
value = match.group(1)
return self.get_string(value) or value.strip()
if section is None or section == cur_section:
return self.get_string(value) or value.strip()
return None

def cargo(self):
@@ -589,7 +606,17 @@ def build_bootstrap(self):
env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
(os.pathsep + env["LIBRARY_PATH"]) \
if "LIBRARY_PATH" in env else ""
env["RUSTFLAGS"] = "-Cdebuginfo=2"
env["RUSTFLAGS"] = "-Cdebuginfo=2 "

build_section = "target.{}".format(self.build_triple())
target_features = []
if self.get_toml("crt-static", build_section) == "true":
target_features += ["+crt-static"]
elif self.get_toml("crt-static", build_section) == "false":
target_features += ["-crt-static"]
if target_features:
env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " "

env["PATH"] = os.path.join(self.bin_root(), "bin") + \
os.pathsep + env["PATH"]
if not os.path.isfile(self.cargo()):
4 changes: 4 additions & 0 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
@@ -663,6 +663,10 @@ impl<'a> Builder<'a> {
cargo.env("RUSTC_CRT_STATIC", x.to_string());
}

if let Some(x) = self.crt_static(compiler.host) {
cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
}

// Enable usage of unstable features
cargo.env("RUSTC_BOOTSTRAP", "1");
self.add_rust_test_threads(&mut cargo);
11 changes: 7 additions & 4 deletions src/librustc_target/spec/linux_musl_base.rs
Original file line number Diff line number Diff line change
@@ -15,7 +15,8 @@ pub fn opts() -> TargetOptions {

// Make sure that the linker/gcc really don't pull in anything, including
// default objects, libs, etc.
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
base.pre_link_args_crt.insert(LinkerFlavor::Gcc, Vec::new());
base.pre_link_args_crt.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());

// At least when this was tested, the linker would not add the
// `GNU_EH_FRAME` program header to executables generated, which is required
@@ -55,9 +56,11 @@ pub fn opts() -> TargetOptions {
//
// Each target directory for musl has these object files included in it so
// they'll be included from there.
base.pre_link_objects_exe.push("crt1.o".to_string());
base.pre_link_objects_exe.push("crti.o".to_string());
base.post_link_objects.push("crtn.o".to_string());
base.pre_link_objects_exe_crt.push("crt1.o".to_string());
base.pre_link_objects_exe_crt.push("crti.o".to_string());
base.pre_link_objects_exe_crt_sys.push("crtbegin.o".to_string());
base.post_link_objects_crt_sys.push("crtend.o".to_string());
base.post_link_objects_crt.push("crtn.o".to_string());

// These targets statically link libc by default
base.crt_static_default = true;
35 changes: 28 additions & 7 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
@@ -420,20 +420,26 @@ pub struct TargetOptions {
/// Linker to invoke
pub linker: Option<String>,

/// Linker arguments that are unconditionally passed *before* any
/// user-defined libraries.
pub pre_link_args: LinkArgs,
/// Objects to link before all others, always found within the
/// Linker arguments that are passed *before* any user-defined libraries.
pub pre_link_args: LinkArgs, // ... unconditionally
pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
/// Objects to link before all others, all except *_sys found within the
/// sysroot folder.
pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
pub pre_link_objects_exe: Vec<String>, // ... when linking an executable, unconditionally
pub pre_link_objects_exe_crt: Vec<String>, // ... when linking an executable with a bundled crt
pub pre_link_objects_exe_crt_sys: Vec<String>, // ... when linking an executable with a bundled
// crt, from the system library search path
pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
/// Linker arguments that are unconditionally passed after any
/// user-defined but before post_link_objects. Standard platform
/// libraries that should be always be linked to, usually go here.
pub late_link_args: LinkArgs,
/// Objects to link after all others, always found within the
/// Objects to link after all others, all except *_sys found within the
/// sysroot folder.
pub post_link_objects: Vec<String>,
pub post_link_objects: Vec<String>, // ... unconditionally
pub post_link_objects_crt: Vec<String>, // ... when linking with a bundled crt
pub post_link_objects_crt_sys: Vec<String>, // ... when linking with a bundled crt, from the
// system library search path
/// Linker arguments that are unconditionally passed *after* any
/// user-defined libraries.
pub post_link_args: LinkArgs,
@@ -633,6 +639,7 @@ impl Default for TargetOptions {
is_builtin: false,
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
pre_link_args: LinkArgs::new(),
pre_link_args_crt: LinkArgs::new(),
post_link_args: LinkArgs::new(),
asm_args: Vec::new(),
cpu: "generic".to_string(),
@@ -666,8 +673,12 @@ impl Default for TargetOptions {
position_independent_executables: false,
relro_level: RelroLevel::None,
pre_link_objects_exe: Vec::new(),
pre_link_objects_exe_crt: Vec::new(),
pre_link_objects_exe_crt_sys: Vec::new(),
pre_link_objects_dll: Vec::new(),
post_link_objects: Vec::new(),
post_link_objects_crt: Vec::new(),
post_link_objects_crt_sys: Vec::new(),
late_link_args: LinkArgs::new(),
link_env: Vec::new(),
archive_format: "gnu".to_string(),
@@ -886,10 +897,15 @@ impl Target {
key!(is_builtin, bool);
key!(linker, optional);
key!(pre_link_args, link_args);
key!(pre_link_args_crt, link_args);
key!(pre_link_objects_exe, list);
key!(pre_link_objects_exe_crt, list);
key!(pre_link_objects_exe_crt_sys, list);
key!(pre_link_objects_dll, list);
key!(late_link_args, link_args);
key!(post_link_objects, list);
key!(post_link_objects_crt, list);
key!(post_link_objects_crt_sys, list);
key!(post_link_args, link_args);
key!(link_env, env);
key!(asm_args, list);
@@ -1091,10 +1107,15 @@ impl ToJson for Target {
target_option_val!(is_builtin);
target_option_val!(linker);
target_option_val!(link_args - pre_link_args);
target_option_val!(link_args - pre_link_args_crt);
target_option_val!(pre_link_objects_exe);
target_option_val!(pre_link_objects_exe_crt);
target_option_val!(pre_link_objects_exe_crt_sys);
target_option_val!(pre_link_objects_dll);
target_option_val!(link_args - late_link_args);
target_option_val!(post_link_objects);
target_option_val!(post_link_objects_crt);
target_option_val!(post_link_objects_crt_sys);
target_option_val!(link_args - post_link_args);
target_option_val!(env - link_env);
target_option_val!(asm_args);
27 changes: 27 additions & 0 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
@@ -621,6 +621,11 @@ fn link_natively(sess: &Session,
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
cmd.args(args);
}
if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
if sess.crt_static() {
cmd.args(args);
}
}
if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
cmd.args(args);
}
@@ -635,6 +640,18 @@ fn link_natively(sess: &Session,
cmd.arg(root.join(obj));
}

if crate_type == config::CrateTypeExecutable && sess.crt_static() {
for obj in &sess.target.target.options.pre_link_objects_exe_crt {
cmd.arg(root.join(obj));
}

for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys {
if flavor == LinkerFlavor::Gcc {
cmd.arg(format!("-l:{}", obj));
}
}
}

if sess.target.target.options.is_like_emscripten {
cmd.arg("-s");
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
@@ -656,6 +673,16 @@ fn link_natively(sess: &Session,
for obj in &sess.target.target.options.post_link_objects {
cmd.arg(root.join(obj));
}
if sess.crt_static() {
for obj in &sess.target.target.options.post_link_objects_crt_sys {
if flavor == LinkerFlavor::Gcc {
cmd.arg(format!("-l:{}", obj));
}
}
for obj in &sess.target.target.options.post_link_objects_crt {
cmd.arg(root.join(obj));
}
}
if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
cmd.args(args);
}
12 changes: 12 additions & 0 deletions src/test/run-make-fulldeps/issue-36710/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-include ../tools.mk

all: foo
$(call RUN,foo)

foo: foo.rs $(call NATIVE_STATICLIB,foo)
$(RUSTC) $< -lfoo $(EXTRACXXFLAGS)

$(TMPDIR)/libfoo.o: foo.cpp
$(call COMPILE_OBJ_CXX,$@,$<)

.PHONY: all
25 changes: 25 additions & 0 deletions src/test/run-make-fulldeps/issue-36710/foo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#include <stdint.h>

struct A {
A() { v = 1234; }
~A() { v = 1; }
uint32_t v;
};

A a;

extern "C" {
uint32_t get() {
return a.v;
}
}
18 changes: 18 additions & 0 deletions src/test/run-make-fulldeps/issue-36710/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Tests that linking to C++ code with global destructors works.

extern { fn get() -> u32; }

fn main() {
let i = unsafe { get() };
assert_eq!(i, 1234);
}
2 changes: 2 additions & 0 deletions src/test/run-make-fulldeps/tools.mk
Original file line number Diff line number Diff line change
@@ -59,12 +59,14 @@ endif

ifdef IS_MSVC
COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
COMPILE_OBJ_CXX = $(CXX) -c -Fo:`cygpath -w $(1)` $(2)
NATIVE_STATICLIB_FILE = $(1).lib
NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
-Fo:`cygpath -w $(TMPDIR)/$(1).obj`
else
COMPILE_OBJ = $(CC) -c -o $(1) $(2)
COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
NATIVE_STATICLIB_FILE = lib$(1).a
NATIVE_STATICLIB = $(call STATICLIB,$(1))
OUT_EXE=-o $(TMPDIR)/$(1)
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
@@ -2491,7 +2491,7 @@ impl<'test> TestCx<'test> {
.env("IS_WINDOWS", "1")
.env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
.env("CC", format!("'{}' {}", self.config.cc, cflags))
.env("CXX", &self.config.cxx);
.env("CXX", format!("'{}'", &self.config.cxx));
} else {
cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
.env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))