From a5a875d17b34b61326d803eb2edea526d3bd6914 Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Sun, 29 Apr 2018 11:17:54 +0200 Subject: [PATCH 1/6] musl: don't use the included startfiles with -crt-static This fixes #36710 with -crt-static. --- src/librustc_target/spec/linux_musl_base.rs | 9 +++++---- src/librustc_target/spec/mod.rs | 21 ++++++++++++++++----- src/librustc_trans/back/link.rs | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/librustc_target/spec/linux_musl_base.rs b/src/librustc_target/spec/linux_musl_base.rs index 293f23eab3883..7a3f3c2a518bc 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,9 @@ 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.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 1e94f03788586..57c7dd0992d68 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -420,12 +420,13 @@ pub struct TargetOptions { /// Linker to invoke pub linker: Option, - /// Linker arguments that are unconditionally passed *before* any - /// user-defined libraries. - pub pre_link_args: LinkArgs, + /// 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, always found within the /// sysroot folder. - pub pre_link_objects_exe: Vec, // ... when linking an executable + pub pre_link_objects_exe: Vec, // ... when linking an executable, unconditionally + pub pre_link_objects_exe_crt: Vec, // ... when linking an executable with a bundled crt pub pre_link_objects_dll: Vec, // ... when linking a dylib /// Linker arguments that are unconditionally passed after any /// user-defined but before post_link_objects. Standard platform @@ -433,7 +434,8 @@ pub struct TargetOptions { pub late_link_args: LinkArgs, /// Objects to link after all others, always found within the /// sysroot folder. - pub post_link_objects: Vec, + pub post_link_objects: Vec, // ... unconditionally + pub post_link_objects_crt: Vec, // ... when linking with a bundled crt /// Linker arguments that are unconditionally passed *after* any /// user-defined libraries. pub post_link_args: LinkArgs, @@ -633,6 +635,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 +669,10 @@ 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_dll: Vec::new(), post_link_objects: Vec::new(), + post_link_objects_crt: Vec::new(), late_link_args: LinkArgs::new(), link_env: Vec::new(), archive_format: "gnu".to_string(), @@ -886,10 +891,13 @@ 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_dll, list); key!(late_link_args, link_args); key!(post_link_objects, list); + key!(post_link_objects_crt, list); key!(post_link_args, link_args); key!(link_env, env); key!(asm_args, list); @@ -1091,10 +1099,13 @@ 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_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!(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 92f9a9e8ba974..67925178927e6 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,12 @@ 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)); + } + } + if sess.target.target.options.is_like_emscripten { cmd.arg("-s"); cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { @@ -656,6 +667,11 @@ 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 { + cmd.arg(root.join(obj)); + } + } if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { cmd.args(args); } From 5ecf29df052c7eca10fccc96f4179d338fe0014e Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Fri, 20 Apr 2018 20:50:50 +0200 Subject: [PATCH 2/6] bootstrap.py: respect crt-static Bootstrap requires serde_derive, which needs proc-macro crate types, so it won't work with crt-static. --- src/bootstrap/bootstrap.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 487440becf630..28f5192f2cdf4 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -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()): From ec2b861c2f8013e10ab1f6e01c9aed9ad1daaefe Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Sun, 29 Apr 2018 11:21:47 +0200 Subject: [PATCH 3/6] bootstrap: pass crt-static for the compiler host as well --- src/bootstrap/bin/rustc.rs | 9 +++++++++ src/bootstrap/builder.rs | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index b6ae824c37601..05fe7753720cc 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -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() { diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 08bb8ab481513..4e0f71086a372 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -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); From 6d9154a830dd9773fe8a4e34e1fc3dfb1ca6f935 Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Sun, 29 Apr 2018 11:29:05 +0200 Subject: [PATCH 4/6] musl: link crt{begin,end}.o from the system compiler This fixes #36710 with +crt-static. We only need to add crtbegin.o and crtend.o as we only do static linking with the bundled start files and there is no static-pie support in rustc yet. --- src/librustc_target/spec/linux_musl_base.rs | 2 ++ src/librustc_target/spec/mod.rs | 14 ++++++++++++-- src/librustc_trans/back/link.rs | 11 +++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/librustc_target/spec/linux_musl_base.rs b/src/librustc_target/spec/linux_musl_base.rs index 7a3f3c2a518bc..4594d450c1507 100644 --- a/src/librustc_target/spec/linux_musl_base.rs +++ b/src/librustc_target/spec/linux_musl_base.rs @@ -58,6 +58,8 @@ pub fn opts() -> TargetOptions { // they'll be included from there. 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 diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 57c7dd0992d68..233d1560d73d4 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -423,19 +423,23 @@ pub struct TargetOptions { /// 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, always found within the + /// Objects to link before all others, all except *_sys found within the /// sysroot folder. pub pre_link_objects_exe: Vec, // ... when linking an executable, unconditionally pub pre_link_objects_exe_crt: Vec, // ... when linking an executable with a bundled crt + pub pre_link_objects_exe_crt_sys: Vec, // ... when linking an executable with a bundled + // crt, from the system library search path pub pre_link_objects_dll: Vec, // ... 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, // ... unconditionally pub post_link_objects_crt: Vec, // ... when linking with a bundled crt + pub post_link_objects_crt_sys: Vec, // ... 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, @@ -670,9 +674,11 @@ impl Default for TargetOptions { 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(), @@ -894,10 +900,12 @@ impl Target { 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); @@ -1102,10 +1110,12 @@ impl ToJson for Target { 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 67925178927e6..07dfeda3b5a31 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -644,6 +644,12 @@ fn link_natively(sess: &Session, 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 { @@ -668,6 +674,11 @@ fn link_natively(sess: &Session, 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)); } From bd94bf5738c7a0fd148157831eabd1efede3b309 Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Wed, 2 May 2018 10:26:00 +0200 Subject: [PATCH 5/6] Add a test for issue 36710. --- .../run-make-fulldeps/issue-36710/Makefile | 12 +++++++++ .../run-make-fulldeps/issue-36710/foo.cpp | 25 +++++++++++++++++++ src/test/run-make-fulldeps/issue-36710/foo.rs | 18 +++++++++++++ src/test/run-make-fulldeps/tools.mk | 2 ++ 4 files changed, 57 insertions(+) create mode 100644 src/test/run-make-fulldeps/issue-36710/Makefile create mode 100644 src/test/run-make-fulldeps/issue-36710/foo.cpp create mode 100644 src/test/run-make-fulldeps/issue-36710/foo.rs 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 0000000000000..2cb0b4ccf2652 --- /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 0000000000000..fbd0ead7a506c --- /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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#include + +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 0000000000000..6e50566ddfde0 --- /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 or the MIT license +// , 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 af1707de6c02f..3de358fa50007 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) From 490d05055abd36521abc41c2e551ac789820e80f Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Thu, 10 May 2018 10:58:51 +0200 Subject: [PATCH 6/6] compiletest: escape CXX the same way as CC for MSVC --- src/tools/compiletest/src/runtest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index d1dac370c9ed9..79c1deecd2c0f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -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))