From 75dcf9e35fb0a3f8e45ec9f4f7c0a4096fe60d2d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 11 Jan 2019 13:43:18 +0100 Subject: [PATCH 01/10] Add an end-to-end run-make test for cross-lang LTO. --- .../cross-lang-lto-clang/Makefile | 25 +++++++++++++++++++ .../cross-lang-lto-clang/clib.c | 9 +++++++ .../cross-lang-lto-clang/cmain.c | 12 +++++++++ .../cross-lang-lto-clang/main.rs | 11 ++++++++ .../cross-lang-lto-clang/rustlib.rs | 12 +++++++++ 5 files changed, 69 insertions(+) create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-clang/clib.c create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-clang/cmain.c create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-clang/main.rs create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-clang/rustlib.rs diff --git a/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile new file mode 100644 index 0000000000000..1e5df8f881289 --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile @@ -0,0 +1,25 @@ +# needs-matching-clang + +# This test makes sure that cross-language inlining actually works by checking +# the generated machine code. + +-include ../tools.mk + +all: cpp-executable rust-executable + +cpp-executable: + $(RUSTC) -Zcross-lang-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs + clang -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 + # Make sure we don't find a call instruction to the function we expect to + # always be inlined. + llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" + # As a sanity check, make sure we do find a call instruction to a + # non-inlined function + llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" + +rust-executable: + clang ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 + (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) + $(RUSTC) -Zcross-lang-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=clang -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain + llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" + llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" diff --git a/src/test/run-make-fulldeps/cross-lang-lto-clang/clib.c b/src/test/run-make-fulldeps/cross-lang-lto-clang/clib.c new file mode 100644 index 0000000000000..90f33f24dc424 --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-clang/clib.c @@ -0,0 +1,9 @@ +#include + +uint32_t c_always_inlined() { + return 1234; +} + +__attribute__((noinline)) uint32_t c_never_inlined() { + return 12345; +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-clang/cmain.c b/src/test/run-make-fulldeps/cross-lang-lto-clang/cmain.c new file mode 100644 index 0000000000000..e62a40117ce83 --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-clang/cmain.c @@ -0,0 +1,12 @@ +#include + +// A trivial function defined in Rust, returning a constant value. This should +// always be inlined. +uint32_t rust_always_inlined(); + + +uint32_t rust_never_inlined(); + +int main(int argc, char** argv) { + return rust_never_inlined() + rust_always_inlined(); +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-clang/main.rs b/src/test/run-make-fulldeps/cross-lang-lto-clang/main.rs new file mode 100644 index 0000000000000..8129dcb85d96a --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-clang/main.rs @@ -0,0 +1,11 @@ +#[link(name = "xyz")] +extern "C" { + fn c_always_inlined() -> u32; + fn c_never_inlined() -> u32; +} + +fn main() { + unsafe { + println!("blub: {}", c_always_inlined() + c_never_inlined()); + } +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-clang/rustlib.rs b/src/test/run-make-fulldeps/cross-lang-lto-clang/rustlib.rs new file mode 100644 index 0000000000000..8a74d74a420bd --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-clang/rustlib.rs @@ -0,0 +1,12 @@ +#![crate_type="staticlib"] + +#[no_mangle] +pub extern "C" fn rust_always_inlined() -> u32 { + 42 +} + +#[no_mangle] +#[inline(never)] +pub extern "C" fn rust_never_inlined() -> u32 { + 421 +} From 50b25105924a23f1070e916ce3bff4be5a7c9c58 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 11 Jan 2019 13:29:59 +0100 Subject: [PATCH 02/10] compiletest: Support opt-in Clang-based run-make tests. Some cross-language run-make tests need a Clang compiler that matches the LLVM version of rustc. Since such a compiler usually isn't available these tests (marked with the "needs-matching-clang" directive) are ignored by default. For some CI jobs we do need these tests to run unconditionally though. In order to support this a --force-clang-based-tests flag is added to compiletest. If this flag is specified, compiletest will fail if it can't detect an appropriate version of Clang. --- src/tools/compiletest/src/common.rs | 7 +++ src/tools/compiletest/src/header.rs | 9 +++ src/tools/compiletest/src/main.rs | 86 ++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 98bc6e8ac0084..d034630a4dfa3 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -144,6 +144,10 @@ pub struct Config { /// (or, alternatively, to silently run them like regular run-pass tests). pub force_valgrind: bool, + /// Whether to fail if we don't have a clang version available that matches + /// rustc's LLVM version. + pub force_clang_based_tests: bool, + /// The directory containing the tests to run pub src_base: PathBuf, @@ -205,6 +209,9 @@ pub struct Config { /// Is LLVM a system LLVM pub system_llvm: bool, + /// The version of Clang available to run-make tests (if any). + pub clang_version: Option, + /// Path to the android tools pub android_cross_path: PathBuf, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 5eb1f5ec5ffda..0d664d4852bbf 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -111,6 +111,11 @@ impl EarlyProps { if ignore_llvm(config, ln) { props.ignore = Ignore::Ignore; } + + if !config.force_clang_based_tests && + config.parse_needs_matching_clang(ln) { + props.ignore = Ignore::Ignore; + } } if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoBoth) && @@ -705,6 +710,10 @@ impl Config { } } + fn parse_needs_matching_clang(&self, line: &str) -> bool { + self.parse_name_directive(line, "needs-matching-clang") + } + /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `normalize-stderr-32bit`. fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 2e5feca54151c..bf6ea2a04035e 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -50,12 +50,32 @@ pub mod util; fn main() { env_logger::init(); - let config = parse_config(env::args().collect()); + let mut config = parse_config(env::args().collect()); if config.valgrind_path.is_none() && config.force_valgrind { panic!("Can't find Valgrind to run Valgrind tests"); } + // Some run-make tests need a version of Clang available that matches + // rustc's LLVM version. Since this isn't always the case, these tests are + // opt-in. + let clang_based_tests_possible = check_clang_based_tests_possible(&config); + match (clang_based_tests_possible, config.force_clang_based_tests) { + (Ok(_), true) | + (Err(_), false) => { + // Nothing to do + } + (Ok(_), false) => { + // If a valid clang version is available, run the tests even if + // they are not forced. + config.force_clang_based_tests = true; + } + (Err(msg), true) => { + // Tests are forced but we don't have a valid version of Clang. + panic!("{}", msg) + } + } + log_config(&config); run_tests(&config); } @@ -108,6 +128,11 @@ pub fn parse_config(args: Vec) -> Config { "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind", ) + .optflag( + "", + "force-clang-based-tests", + "fail if Clang-based run-make tests can't be run for some reason", + ) .optopt( "", "llvm-filecheck", @@ -189,6 +214,12 @@ pub fn parse_config(args: Vec) -> Config { "VERSION STRING", ) .optflag("", "system-llvm", "is LLVM the system LLVM") + .optopt( + "", + "clang-version", + "the version of Clang available to run-make tests", + "VERSION STRING", + ) .optopt( "", "android-cross-path", @@ -298,6 +329,7 @@ pub fn parse_config(args: Vec) -> Config { docck_python: matches.opt_str("docck-python").unwrap(), valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), + force_clang_based_tests: matches.opt_present("force-clang-based-tests"), llvm_filecheck: matches.opt_str("llvm-filecheck").map(|s| PathBuf::from(&s)), src_base, build_base: opt_path(matches, "build-base"), @@ -323,6 +355,7 @@ pub fn parse_config(args: Vec) -> Config { lldb_native_rust, llvm_version: matches.opt_str("llvm-version"), system_llvm: matches.opt_present("system-llvm"), + clang_version: matches.opt_str("clang-version"), android_cross_path: android_cross_path, adb_path: opt_str2(matches.opt_str("adb-path")), adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), @@ -1031,3 +1064,54 @@ fn test_extract_gdb_version() { 7012050: "GNU gdb (GDB) 7.12.50.20161027-git", } } + + +fn check_clang_based_tests_possible(config: &Config) -> Result<(), String> { + + let llvm_version = if let Some(llvm_version) = config.llvm_version.as_ref() { + llvm_version + } else { + return Err(format!("Running `compiletest` with `--force-clang-based-tests` \ + requires `--llvm-version` to be specified.")); + }; + + let clang_major_version = if let Some(ref version_string) = config.clang_version { + major_version_from_clang_version_string(version_string)? + } else { + return Err(format!("Clang is required for running tests \ + (because of --force-clang-based-tests) \ + but it does not seem to be available.")); + }; + + let rustc_llvm_major_version = major_version_from_llvm_version_string(&llvm_version)?; + + return if clang_major_version != rustc_llvm_major_version { + Err(format!("`--force-clang-based-tests` needs the major version of Clang \ + and rustc's LLVM to be the same. Clang version is: {}, \ + Rustc LLVM is: {}", + config.clang_version.clone().unwrap(), + llvm_version)) + } else { + Ok(()) + }; + + fn major_version_from_clang_version_string(clang_version: &str) -> Result<&str, String> { + let re = regex::Regex::new(r"clang version (\d)\.\d").unwrap(); + if let Some(captures) = re.captures(clang_version) { + Ok(captures.get(1).unwrap().as_str()) + } else { + Err(format!("Failed to parse major version from Clang version \ + string '{}'.", clang_version)) + } + } + + fn major_version_from_llvm_version_string(llvm_version: &str) -> Result<&str, String> { + let re = regex::Regex::new(r"(\d)\.\d").unwrap(); + if let Some(captures) = re.captures(llvm_version) { + Ok(captures.get(1).unwrap().as_str()) + } else { + Err(format!("Failed to parse major version from LLVM version \ + string '{}'.", llvm_version)) + } + } +} From ea4fb95dc9e234d35a7a94f6cdc37cb5103c35ed Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 11 Jan 2019 13:37:08 +0100 Subject: [PATCH 03/10] Support clang-based run-make tests in rustbuild. --- src/bootstrap/test.rs | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2edc78ebaa94f..ff66c75dc8c65 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1106,13 +1106,13 @@ impl Step for Compiletest { }).to_string() }) }; - let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") { + let (lldb_exe, clang_exe) = + if builder.config.lldb_enabled && !target.contains("emscripten") { // Test against the lldb that was just built. - builder.llvm_out(target) - .join("bin") - .join("lldb") + (builder.llvm_out(target).join("bin").join("lldb"), + builder.llvm_out(target).join("bin").join("clang")) } else { - PathBuf::from("lldb") + (PathBuf::from("lldb"), PathBuf::from("clang")) }; let lldb_version = Command::new(&lldb_exe) .arg("--version") @@ -1127,6 +1127,31 @@ impl Step for Compiletest { } } + let clang_version = Command::new(&clang_exe) + .arg("--version") + .output() + .map(|output| { String::from_utf8_lossy(&output.stdout).to_string() }) + .ok(); + if let Some(ref vers) = clang_version { + cmd.arg("--clang-version").arg(vers); + } + + if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") { + match &var.to_string_lossy()[..] { + "1" | "yes" | "on" => { + cmd.arg("--force-clang-based-tests"); + } + "0" | "no" | "off" => { + // Nothing to do. + } + other => { + // Let's make sure typos don't get unnoticed + panic!("Unrecognized option '{}' set in \ + RUSTBUILD_FORCE_CLANG_BASED_TESTS", other); + } + } + } + // Get paths from cmd args let paths = match &builder.config.cmd { Subcommand::Test { ref paths, .. } => &paths[..], From b38125c3bba8c6137bf47365c2009b647766059c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 15 Jan 2019 18:07:12 +0100 Subject: [PATCH 04/10] compiletest: Simplify handling of Clang-based tests. --- src/bootstrap/test.rs | 25 ++---- .../cross-lang-lto-clang/Makefile | 6 +- src/tools/compiletest/src/common.rs | 9 +- src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/main.rs | 89 ++----------------- src/tools/compiletest/src/runtest.rs | 4 + 6 files changed, 26 insertions(+), 109 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index ff66c75dc8c65..c9160aca9173e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1106,13 +1106,11 @@ impl Step for Compiletest { }).to_string() }) }; - let (lldb_exe, clang_exe) = - if builder.config.lldb_enabled && !target.contains("emscripten") { + let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") { // Test against the lldb that was just built. - (builder.llvm_out(target).join("bin").join("lldb"), - builder.llvm_out(target).join("bin").join("clang")) + builder.llvm_out(target).join("bin").join("lldb") } else { - (PathBuf::from("lldb"), PathBuf::from("clang")) + PathBuf::from("lldb") }; let lldb_version = Command::new(&lldb_exe) .arg("--version") @@ -1127,19 +1125,14 @@ impl Step for Compiletest { } } - let clang_version = Command::new(&clang_exe) - .arg("--version") - .output() - .map(|output| { String::from_utf8_lossy(&output.stdout).to_string() }) - .ok(); - if let Some(ref vers) = clang_version { - cmd.arg("--clang-version").arg(vers); - } - if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") { - match &var.to_string_lossy()[..] { + match &var.to_string_lossy().to_lowercase()[..] { "1" | "yes" | "on" => { - cmd.arg("--force-clang-based-tests"); + assert!(builder.config.lldb_enabled, + "RUSTBUILD_FORCE_CLANG_BASED_TESTS needs Clang/LLDB to \ + be built."); + let clang_exe = builder.llvm_out(target).join("bin").join("clang"); + cmd.arg("--run-clang-based-tests-with").arg(clang_exe); } "0" | "no" | "off" => { // Nothing to do. diff --git a/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile index 1e5df8f881289..cf687070bc2ed 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile @@ -9,7 +9,7 @@ all: cpp-executable rust-executable cpp-executable: $(RUSTC) -Zcross-lang-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs - clang -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 + $(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 # Make sure we don't find a call instruction to the function we expect to # always be inlined. llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" @@ -18,8 +18,8 @@ cpp-executable: llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" rust-executable: - clang ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 + $(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) - $(RUSTC) -Zcross-lang-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=clang -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain + $(RUSTC) -Zcross-lang-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index d034630a4dfa3..f6f8ef1dff485 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -144,9 +144,9 @@ pub struct Config { /// (or, alternatively, to silently run them like regular run-pass tests). pub force_valgrind: bool, - /// Whether to fail if we don't have a clang version available that matches - /// rustc's LLVM version. - pub force_clang_based_tests: bool, + /// The path to the Clang executable to run Clang-based tests with. If + /// `None` then these tests will be ignored. + pub run_clang_based_tests_with: Option, /// The directory containing the tests to run pub src_base: PathBuf, @@ -209,9 +209,6 @@ pub struct Config { /// Is LLVM a system LLVM pub system_llvm: bool, - /// The version of Clang available to run-make tests (if any). - pub clang_version: Option, - /// Path to the android tools pub android_cross_path: PathBuf, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0d664d4852bbf..6a00bd3c42611 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -112,7 +112,7 @@ impl EarlyProps { props.ignore = Ignore::Ignore; } - if !config.force_clang_based_tests && + if config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln) { props.ignore = Ignore::Ignore; } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index bf6ea2a04035e..682cce663a1ff 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -50,32 +50,12 @@ pub mod util; fn main() { env_logger::init(); - let mut config = parse_config(env::args().collect()); + let config = parse_config(env::args().collect()); if config.valgrind_path.is_none() && config.force_valgrind { panic!("Can't find Valgrind to run Valgrind tests"); } - // Some run-make tests need a version of Clang available that matches - // rustc's LLVM version. Since this isn't always the case, these tests are - // opt-in. - let clang_based_tests_possible = check_clang_based_tests_possible(&config); - match (clang_based_tests_possible, config.force_clang_based_tests) { - (Ok(_), true) | - (Err(_), false) => { - // Nothing to do - } - (Ok(_), false) => { - // If a valid clang version is available, run the tests even if - // they are not forced. - config.force_clang_based_tests = true; - } - (Err(msg), true) => { - // Tests are forced but we don't have a valid version of Clang. - panic!("{}", msg) - } - } - log_config(&config); run_tests(&config); } @@ -128,10 +108,11 @@ pub fn parse_config(args: Vec) -> Config { "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind", ) - .optflag( + .optopt( "", - "force-clang-based-tests", - "fail if Clang-based run-make tests can't be run for some reason", + "run-clang-based-tests-with", + "path to Clang executable", + "PATH", ) .optopt( "", @@ -214,12 +195,6 @@ pub fn parse_config(args: Vec) -> Config { "VERSION STRING", ) .optflag("", "system-llvm", "is LLVM the system LLVM") - .optopt( - "", - "clang-version", - "the version of Clang available to run-make tests", - "VERSION STRING", - ) .optopt( "", "android-cross-path", @@ -329,7 +304,7 @@ pub fn parse_config(args: Vec) -> Config { docck_python: matches.opt_str("docck-python").unwrap(), valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), - force_clang_based_tests: matches.opt_present("force-clang-based-tests"), + run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), llvm_filecheck: matches.opt_str("llvm-filecheck").map(|s| PathBuf::from(&s)), src_base, build_base: opt_path(matches, "build-base"), @@ -355,7 +330,6 @@ pub fn parse_config(args: Vec) -> Config { lldb_native_rust, llvm_version: matches.opt_str("llvm-version"), system_llvm: matches.opt_present("system-llvm"), - clang_version: matches.opt_str("clang-version"), android_cross_path: android_cross_path, adb_path: opt_str2(matches.opt_str("adb-path")), adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), @@ -1064,54 +1038,3 @@ fn test_extract_gdb_version() { 7012050: "GNU gdb (GDB) 7.12.50.20161027-git", } } - - -fn check_clang_based_tests_possible(config: &Config) -> Result<(), String> { - - let llvm_version = if let Some(llvm_version) = config.llvm_version.as_ref() { - llvm_version - } else { - return Err(format!("Running `compiletest` with `--force-clang-based-tests` \ - requires `--llvm-version` to be specified.")); - }; - - let clang_major_version = if let Some(ref version_string) = config.clang_version { - major_version_from_clang_version_string(version_string)? - } else { - return Err(format!("Clang is required for running tests \ - (because of --force-clang-based-tests) \ - but it does not seem to be available.")); - }; - - let rustc_llvm_major_version = major_version_from_llvm_version_string(&llvm_version)?; - - return if clang_major_version != rustc_llvm_major_version { - Err(format!("`--force-clang-based-tests` needs the major version of Clang \ - and rustc's LLVM to be the same. Clang version is: {}, \ - Rustc LLVM is: {}", - config.clang_version.clone().unwrap(), - llvm_version)) - } else { - Ok(()) - }; - - fn major_version_from_clang_version_string(clang_version: &str) -> Result<&str, String> { - let re = regex::Regex::new(r"clang version (\d)\.\d").unwrap(); - if let Some(captures) = re.captures(clang_version) { - Ok(captures.get(1).unwrap().as_str()) - } else { - Err(format!("Failed to parse major version from Clang version \ - string '{}'.", clang_version)) - } - } - - fn major_version_from_llvm_version_string(llvm_version: &str) -> Result<&str, String> { - let re = regex::Regex::new(r"(\d)\.\d").unwrap(); - if let Some(captures) = re.captures(llvm_version) { - Ok(captures.get(1).unwrap().as_str()) - } else { - Err(format!("Failed to parse major version from LLVM version \ - string '{}'.", llvm_version)) - } - } -} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 400c205d44b20..f0050f2adb957 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2587,6 +2587,10 @@ impl<'test> TestCx<'test> { cmd.env("RUSTC_LINKER", linker); } + if let Some(ref clang) = self.config.run_clang_based_tests_with { + cmd.env("CLANG", clang); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); From 48cb04fbca1d398c170b713b3fe7e681a8e39a4f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 16 Jan 2019 14:59:52 +0100 Subject: [PATCH 05/10] Enable Clang-based tests on x86_64-gnu-debug builder. --- src/ci/docker/x86_64-gnu-debug/Dockerfile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index bdde7ad7fe854..241c25aaa050b 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ + python2.7-dev \ git \ cmake \ sudo \ @@ -16,9 +17,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 + ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ + --enable-lld \ + --enable-lldb \ --enable-optimize -ENV SCRIPT python2.7 ../x.py build +ENV SCRIPT \ + python2.7 ../x.py build && \ + python2.7 ../x.py test src/test/run-make-fulldeps --test-args clang From 4460e7c919921ee0fbfd4804d2df33996f404581 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 24 Jan 2019 14:08:39 +0100 Subject: [PATCH 06/10] Add missing packages. --- src/ci/docker/x86_64-gnu-debug/Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 241c25aaa050b..1f2cdf36d156f 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -8,6 +8,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ python2.7 \ python2.7-dev \ + libxml2-dev \ + libncurses-dev \ + libedit-dev \ + swig \ + doxygen \ git \ cmake \ sudo \ From 9c29517af9cc44683fabcdf8c4b9b9c650e33ca6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 25 Jan 2019 12:34:59 +0100 Subject: [PATCH 07/10] bootstrap: Make LLD available to run-make tests. --- src/bootstrap/tool.rs | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 9f6db73e6f713..cd3afc59e560c 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -1,6 +1,5 @@ use std::fs; use std::env; -use std::iter; use std::path::PathBuf; use std::process::{Command, exit}; use std::collections::HashSet; @@ -666,19 +665,33 @@ impl<'a> Builder<'a> { // Add the llvm/bin directory to PATH since it contains lots of // useful, platform-independent tools - if tool.uses_llvm_tools() { + if tool.uses_llvm_tools() && !self.config.dry_run { + let mut additional_paths = vec![]; + if let Some(llvm_bin_path) = self.llvm_bin_path() { - if host.contains("windows") { - // On Windows, PATH and the dynamic library path are the same, - // so we just add the LLVM bin path to lib_path - lib_paths.push(llvm_bin_path); - } else { - let old_path = env::var_os("PATH").unwrap_or_default(); - let new_path = env::join_paths(iter::once(llvm_bin_path) - .chain(env::split_paths(&old_path))) - .expect("Could not add LLVM bin path to PATH"); - cmd.env("PATH", new_path); - } + additional_paths.push(llvm_bin_path); + } + + // If LLD is available, add that too. + if self.config.lld_enabled { + let lld_install_root = self.ensure(native::Lld { + target: self.config.build, + }); + + let lld_bin_path = lld_install_root.join("bin"); + additional_paths.push(lld_bin_path); + } + + if host.contains("windows") { + // On Windows, PATH and the dynamic library path are the same, + // so we just add the LLVM bin path to lib_path + lib_paths.extend(additional_paths); + } else { + let old_path = env::var_os("PATH").unwrap_or_default(); + let new_path = env::join_paths(additional_paths.into_iter() + .chain(env::split_paths(&old_path))) + .expect("Could not add LLVM bin path to PATH"); + cmd.env("PATH", new_path); } } @@ -686,7 +699,7 @@ impl<'a> Builder<'a> { } fn llvm_bin_path(&self) -> Option { - if self.config.llvm_enabled && !self.config.dry_run { + if self.config.llvm_enabled { let llvm_config = self.ensure(native::Llvm { target: self.config.build, emscripten: false, From 4f534ffbdb9bb9897ea6a1f7290e5e6fb4d86f02 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 28 Jan 2019 15:16:29 +0100 Subject: [PATCH 08/10] ci: Use clang as the C++ compiler for x86_64-gnu-debug. --- src/ci/docker/x86_64-gnu-debug/Dockerfile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 1f2cdf36d156f..10d92256dccca 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.10 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ @@ -17,7 +17,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - xz-utils + xz-utils \ + lld \ + clang COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -30,7 +32,11 @@ ENV RUST_CONFIGURE_ARGS \ --enable-debug \ --enable-lld \ --enable-lldb \ - --enable-optimize + --enable-optimize \ + --set target.x86_64-unknown-linux-gnu.linker=clang \ + --set target.x86_64-unknown-linux-gnu.cc=clang \ + --set target.x86_64-unknown-linux-gnu.cxx=clang++ + ENV SCRIPT \ python2.7 ../x.py build && \ python2.7 ../x.py test src/test/run-make-fulldeps --test-args clang From dc20c8cc25a6d1bc9baaa4cc3a879a9c0f9f6657 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Jan 2019 13:27:12 +0100 Subject: [PATCH 09/10] bootstrap: Expose LLVM_USE_LINKER cmake option to config.toml. --- config.toml.example | 4 ++++ src/bootstrap/config.rs | 3 +++ src/bootstrap/native.rs | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/config.toml.example b/config.toml.example index 23943d34b7ca8..548aa691633db 100644 --- a/config.toml.example +++ b/config.toml.example @@ -96,6 +96,10 @@ # that your host compiler ships with libc++. #use-libcxx = true +# The value specified here will be passed as `-DLLVM_USE_LINKER` to CMake. +#use-linker = "lld" + + # ============================================================================= # General build configuration options # ============================================================================= diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 9421817ae6d8e..2871db2c9a2d1 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -77,6 +77,7 @@ pub struct Config { pub llvm_experimental_targets: String, pub llvm_link_jobs: Option, pub llvm_version_suffix: Option, + pub llvm_use_linker: Option, pub lld_enabled: bool, pub lldb_enabled: bool, @@ -255,6 +256,7 @@ struct Llvm { version_suffix: Option, clang_cl: Option, use_libcxx: Option, + use_linker: Option, } #[derive(Deserialize, Default, Clone)] @@ -517,6 +519,7 @@ impl Config { config.llvm_version_suffix = llvm.version_suffix.clone(); config.llvm_clang_cl = llvm.clang_cl.clone(); set(&mut config.llvm_use_libcxx, llvm.use_libcxx); + config.llvm_use_linker = llvm.use_linker.clone(); } if let Some(ref rust) = toml.rust { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index cb9c86df55080..e4325179f63a5 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -231,6 +231,10 @@ impl Step for Llvm { cfg.define("LLVM_VERSION_SUFFIX", suffix); } + if let Some(ref linker) = builder.config.llvm_use_linker { + cfg.define("LLVM_USE_LINKER", linker); + } + if let Some(ref python) = builder.config.python { cfg.define("PYTHON_EXECUTABLE", python); } From b17c10de46b021cb25855d440b6a0c270d4d1f4e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Jan 2019 13:28:46 +0100 Subject: [PATCH 10/10] CI: Use lld for linking LLVM in the x86_64-gnu-debug image. --- src/ci/docker/x86_64-gnu-debug/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 10d92256dccca..1c7eff68adc15 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -33,6 +33,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-lld \ --enable-lldb \ --enable-optimize \ + --set llvm.use-linker=lld \ --set target.x86_64-unknown-linux-gnu.linker=clang \ --set target.x86_64-unknown-linux-gnu.cc=clang \ --set target.x86_64-unknown-linux-gnu.cxx=clang++