diff options
| author | bors <bors@rust-lang.org> | 2018-05-11 19:46:16 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-05-11 19:46:16 +0000 |
| commit | 0cd465087d800f6e1183ed3e8a71262039245902 (patch) | |
| tree | 1c864a01f0253070fc94f1b861bc581bb65dabae /src | |
| parent | 6ecbe9b7f71b41422f9c9e45b1d31eefacea31a3 (diff) | |
| parent | 490d05055abd36521abc41c2e551ac789820e80f (diff) | |
Auto merge of #50105 - mixi:crt-included, r=alexcrichton
Use the correct crt*.o files when linking musl targets. This is supposed to support optionally using the system copy of musl libc instead of the included one if supported. This currently only affects the start files, which is enough to allow building rustc on musl targets. Most of the changes are analogous to crt-static. Excluding the start files is something musl based distributions usually patch into their copy of rustc: - https://github.com/alpinelinux/aports/blob/eb064c8/community/rust/musl-fix-linux_musl_base.patch - https://github.com/voidlinux/void-packages/blob/77400fc/srcpkgs/rust/patches/link-musl-dynamically.patch For third-party distributions that not yet carry those patches it would be nice if it was supported without the need to patch upstream sources. ## Reasons ### What breaks? Some start files were missed when originally writing the logic to swap in musl start files (gcc comes with its own start files, which are suppressed by -nostdlib, but not manually included later on). This caused #36710, which also affects rustc with the internal llvm copy or any other system libraries that need crtbegin/crtend. ### How is it fixed? The system linker already has all the logic to decide which start files to include, so we can just defer to it (except of course if it doesn't target musl). ### Why is it optional? In #40113 it was first tried to remove the start files, which broke compiling musl-targeting static binaries with a glibc-targeting compiler. This is why it eventually landed without removing the start files. Being an option side-steps the issue. ### Why are the start files still installed? This has the nice side-effect, that the produced rust-std-* binaries can still be used by on a glibc-targeting system with a rustc built against glibc. ## Does it work? With the following build script (using [musl-cross-make](https://github.com/richfelker/musl-cross-make)): https://shadowice.org/~mixi/rust-musl/build.sh, I was able to cross-compile a musl-host musl-targeting rustc on a glibc-based system. The resulting binaries are at https://shadowice.org/~mixi/rust-musl/binaries/. This also requires #50103 and #50104 (which are also applied to the branch the build script uses).
Diffstat (limited to 'src')
| -rw-r--r-- | src/bootstrap/bin/rustc.rs | 9 | ||||
| -rw-r--r-- | src/bootstrap/bootstrap.py | 33 | ||||
| -rw-r--r-- | src/bootstrap/builder.rs | 4 | ||||
| -rw-r--r-- | src/librustc_target/spec/linux_musl_base.rs | 11 | ||||
| -rw-r--r-- | src/librustc_target/spec/mod.rs | 35 | ||||
| -rw-r--r-- | src/librustc_trans/back/link.rs | 27 | ||||
| -rw-r--r-- | src/test/run-make-fulldeps/issue-36710/Makefile | 12 | ||||
| -rw-r--r-- | src/test/run-make-fulldeps/issue-36710/foo.cpp | 25 | ||||
| -rw-r--r-- | src/test/run-make-fulldeps/issue-36710/foo.rs | 18 | ||||
| -rw-r--r-- | src/test/run-make-fulldeps/tools.mk | 2 | ||||
| -rw-r--r-- | src/tools/compiletest/src/runtest.rs | 2 |
11 files changed, 163 insertions, 15 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 3f97accaa4d..76d0e6e28ae 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -268,6 +268,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() { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 487440becf6..28f5192f2cd 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -489,7 +489,7 @@ class RustBuild(object): """ 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 @@ class RustBuild(object): >>> 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 @@ class RustBuild(object): 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()): diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index f87436504c6..17f19222e6e 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -690,6 +690,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); diff --git a/src/librustc_target/spec/linux_musl_base.rs b/src/librustc_target/spec/linux_musl_base.rs index 293f23eab38..4594d450c15 100644 --- a/src/librustc_target/spec/linux_musl_base.rs +++ b/src/librustc_target/spec/linux_musl_base.rs @@ -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; diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 48e771e0aaf..708a3865b23 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -421,20 +421,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, @@ -634,6 +640,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(), @@ -667,8 +674,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(), @@ -887,10 +898,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); @@ -1092,10 +1108,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); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index d39556e9bb1..299075ed03a 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -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); } diff --git a/src/test/run-make-fulldeps/issue-36710/Makefile b/src/test/run-make-fulldeps/issue-36710/Makefile new file mode 100644 index 00000000000..2cb0b4ccf26 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-36710/Makefile @@ -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 diff --git a/src/test/run-make-fulldeps/issue-36710/foo.cpp b/src/test/run-make-fulldeps/issue-36710/foo.cpp new file mode 100644 index 00000000000..fbd0ead7a50 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-36710/foo.cpp @@ -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; + } +} diff --git a/src/test/run-make-fulldeps/issue-36710/foo.rs b/src/test/run-make-fulldeps/issue-36710/foo.rs new file mode 100644 index 00000000000..6e50566ddfd --- /dev/null +++ b/src/test/run-make-fulldeps/issue-36710/foo.rs @@ -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); +} diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index af1707de6c0..3de358fa500 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -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) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1bac9ef66bb..4f18f238cab 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2524,7 +2524,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)) |
