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

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

Merged
merged 6 commits into from
May 11, 2018
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
9 changes: 9 additions & 0 deletions src/bootstrap/bin/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
33 changes: 30 additions & 3 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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):
Expand Down Expand Up @@ -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()):
Expand Down
4 changes: 4 additions & 0 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 7 additions & 4 deletions src/librustc_target/spec/linux_musl_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
35 changes: 28 additions & 7 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
27 changes: 27 additions & 0 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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 {
Expand All @@ -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);
}
Expand Down
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
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down