From bb88c989faeace3dd50027a748aeb992739907e4 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Tue, 3 Jul 2018 12:24:24 -0600 Subject: [PATCH 1/4] Add lldb to the build This optionally adds lldb (and clang, which it needs) to the build. Because rust uses LLVM 7, and because clang 7 is not yet released, a recent git master version of clang is used. The lldb that is used includes the Rust plugin. lldb is only built when asked for, or when doing a nightly build on macOS. Only macOS is done for now due to difficulties with the Python dependency. --- .gitmodules | 8 +++ config.toml.example | 4 ++ src/Cargo.lock | 2 +- src/bootstrap/builder.rs | 1 + src/bootstrap/config.rs | 3 + src/bootstrap/configure.py | 1 + src/bootstrap/dist.rs | 114 +++++++++++++++++++++++++++++++++++++ src/bootstrap/lib.rs | 43 +++++++++----- src/bootstrap/native.rs | 20 ++++++- src/clang | 1 + src/lldb | 1 + src/tools/rust-installer | 2 +- 12 files changed, 182 insertions(+), 18 deletions(-) create mode 160000 src/clang create mode 160000 src/lldb diff --git a/.gitmodules b/.gitmodules index f3eb902709ca7..02cbde25e629e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -56,3 +56,11 @@ [submodule "src/libbacktrace"] path = src/libbacktrace url = https://github.com/rust-lang-nursery/libbacktrace +[submodule "src/lldb"] + path = src/lldb + url = https://github.com/rust-lang-nursery/lldb/ + branch = rust-release-70 +[submodule "src/clang"] + path = src/clang + url = https://github.com/rust-lang-nursery/clang/ + branch = master diff --git a/config.toml.example b/config.toml.example index 99073416334f5..b095d6a98268f 100644 --- a/config.toml.example +++ b/config.toml.example @@ -354,6 +354,10 @@ # sysroot. #llvm-tools = false +# Indicates whether LLDB will be made available in the sysroot. +# This is only built if LLVM is also being built. +#lldb = false + # Whether to deny warnings in crates #deny-warnings = true diff --git a/src/Cargo.lock b/src/Cargo.lock index b2e41589893cc..58120aaf9e59a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1011,7 +1011,7 @@ name = "installer" version = "0.0.0" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 724d3b741903f..386b37c405e40 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -461,6 +461,7 @@ impl<'a> Builder<'a> { dist::Rustfmt, dist::Clippy, dist::LlvmTools, + dist::Lldb, dist::Extended, dist::HashSign ), diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 0a8a5c87d0da1..43e7a8aa82fa4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -87,6 +87,7 @@ pub struct Config { pub llvm_link_jobs: Option, pub lld_enabled: bool, + pub lldb_enabled: bool, pub llvm_tools_enabled: bool, // rust codegen options @@ -310,6 +311,7 @@ struct Rust { codegen_backends_dir: Option, wasm_syscall: Option, lld: Option, + lldb: Option, llvm_tools: Option, deny_warnings: Option, backtrace_on_ice: Option, @@ -538,6 +540,7 @@ impl Config { } set(&mut config.wasm_syscall, rust.wasm_syscall); set(&mut config.lld_enabled, rust.lld); + set(&mut config.lldb_enabled, rust.lldb); set(&mut config.llvm_tools_enabled, rust.llvm_tools); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 9fdba044f4be3..c2843101eb61a 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -335,6 +335,7 @@ def set(key, value): elif option.name == 'full-tools': set('rust.codegen-backends', ['llvm', 'emscripten']) set('rust.lld', True) + set('rust.lldb', True) set('rust.llvm-tools', True) set('build.extended', True) elif option.name == 'option-checking': diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 188e64cd668dd..ab3c67128302f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -47,6 +47,8 @@ pub fn pkgname(builder: &Builder, component: &str) -> String { format!("{}-{}", component, builder.rustfmt_package_vers()) } else if component == "llvm-tools" { format!("{}-{}", component, builder.llvm_tools_package_vers()) + } else if component == "lldb" { + format!("{}-{}", component, builder.lldb_package_vers()) } else { assert!(component.starts_with("rust")); format!("{}-{}", component, builder.rust_package_vers()) @@ -1396,6 +1398,7 @@ impl Step for Extended { let rls_installer = builder.ensure(Rls { stage, target }); let llvm_tools_installer = builder.ensure(LlvmTools { stage, target }); let clippy_installer = builder.ensure(Clippy { stage, target }); + let lldb_installer = builder.ensure(Lldb { target }); let mingw_installer = builder.ensure(Mingw { host: target }); let analysis_installer = builder.ensure(Analysis { compiler: builder.compiler(stage, self.host), @@ -1435,6 +1438,7 @@ impl Step for Extended { tarballs.extend(clippy_installer.clone()); tarballs.extend(rustfmt_installer.clone()); tarballs.extend(llvm_tools_installer.clone()); + tarballs.extend(lldb_installer.clone()); tarballs.push(analysis_installer); tarballs.push(std_installer); if builder.config.docs { @@ -1869,6 +1873,7 @@ impl Step for HashSign { cmd.arg(builder.package_vers(&builder.release_num("clippy"))); cmd.arg(builder.package_vers(&builder.release_num("rustfmt"))); cmd.arg(builder.llvm_tools_package_vers()); + cmd.arg(builder.lldb_package_vers()); cmd.arg(addr); builder.create_dir(&distdir(builder)); @@ -1963,3 +1968,112 @@ impl Step for LlvmTools { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } } + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Lldb { + pub target: Interned, +} + +impl Step for Lldb { + type Output = Option; + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/lldb") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Lldb { + target: run.target, + }); + } + + fn run(self, builder: &Builder) -> Option { + let target = self.target; + + builder.info(&format!("Dist Lldb ({})", target)); + let src = builder.src.join("src/lldb"); + let name = pkgname(builder, "lldb"); + + let tmp = tmpdir(builder); + let image = tmp.join("lldb-image"); + drop(fs::remove_dir_all(&image)); + + // Prepare the image directory + let bindir = builder + .llvm_out(target) + .join("bin"); + let dst = image.join("bin"); + t!(fs::create_dir_all(&dst)); + for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] { + let exe = bindir.join(exe(program, &target)); + builder.install(&exe, &dst, 0o755); + } + + // The libraries. + let libdir = builder.llvm_out(target).join("lib"); + let dst = image.join("lib"); + t!(fs::create_dir_all(&dst)); + for entry in t!(fs::read_dir(&libdir)) { + // let entry = t!(entry); + let entry = entry.unwrap(); + if let Ok(name) = entry.file_name().into_string() { + if name.starts_with("liblldb.") && !name.ends_with(".a") { + if t!(entry.file_type()).is_symlink() { + builder.copy_to_folder(&entry.path(), &dst); + } else { + builder.install(&entry.path(), &dst, 0o755); + } + } + } + } + + // The lldb scripts might be installed in lib/python$version + // or in lib64/python$version. If lib64 exists, use it; + // otherwise lib. + let libdir = builder.llvm_out(target).join("lib64"); + let (libdir, libdir_name) = if libdir.exists() { + (libdir, "lib64") + } else { + (builder.llvm_out(target).join("lib"), "lib") + }; + for entry in t!(fs::read_dir(&libdir)) { + let entry = t!(entry); + if let Ok(name) = entry.file_name().into_string() { + if name.starts_with("python") { + let dst = image.join(libdir_name) + .join(entry.file_name()); + t!(fs::create_dir_all(&dst)); + builder.cp_r(&entry.path(), &dst); + break; + } + } + } + + // Prepare the overlay + let overlay = tmp.join("lldb-overlay"); + drop(fs::remove_dir_all(&overlay)); + builder.create_dir(&overlay); + builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); + builder.create(&overlay.join("version"), &builder.lldb_vers()); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=lldb-installed.") + .arg("--image-dir").arg(&image) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) + .arg("--non-installed-overlay").arg(&overlay) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=lldb-preview"); + + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) + } +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1efff19dfb993..41834ba3165a8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -151,6 +151,11 @@ use std::process::{self, Command}; use std::slice; use std::str; +#[cfg(unix)] +use std::os::unix::fs::symlink as symlink_file; +#[cfg(windows)] +use std::os::windows::fs::symlink_file; + use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; use filetime::FileTime; @@ -1005,6 +1010,14 @@ impl Build { self.rust_version() } + fn lldb_package_vers(&self) -> String { + self.package_vers(&self.rust_version()) + } + + fn lldb_vers(&self) -> String { + self.rust_version() + } + /// Returns the `version` string associated with this compiler for Rust /// itself. /// @@ -1123,20 +1136,24 @@ impl Build { pub fn copy(&self, src: &Path, dst: &Path) { if self.config.dry_run { return; } let _ = fs::remove_file(&dst); - // Attempt to "easy copy" by creating a hard link (symlinks don't work on - // windows), but if that fails just fall back to a slow `copy` operation. - if let Ok(()) = fs::hard_link(src, dst) { - return - } - if let Err(e) = fs::copy(src, dst) { - panic!("failed to copy `{}` to `{}`: {}", src.display(), - dst.display(), e) + let metadata = t!(src.symlink_metadata()); + if metadata.file_type().is_symlink() { + let link = t!(fs::read_link(src)); + t!(symlink_file(link, dst)); + } else if let Ok(()) = fs::hard_link(src, dst) { + // Attempt to "easy copy" by creating a hard link + // (symlinks don't work on windows), but if that fails + // just fall back to a slow `copy` operation. + } else { + if let Err(e) = fs::copy(src, dst) { + panic!("failed to copy `{}` to `{}`: {}", src.display(), + dst.display(), e) + } + t!(fs::set_permissions(dst, metadata.permissions())); + let atime = FileTime::from_last_access_time(&metadata); + let mtime = FileTime::from_last_modification_time(&metadata); + t!(filetime::set_file_times(dst, atime, mtime)); } - let metadata = t!(src.metadata()); - t!(fs::set_permissions(dst, metadata.permissions())); - let atime = FileTime::from_last_access_time(&metadata); - let mtime = FileTime::from_last_modification_time(&metadata); - t!(filetime::set_file_times(dst, atime, mtime)); } /// Search-and-replaces within a file. (Not maximally efficiently: allocates a diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 9aeb4e0edaed5..e20dab5f077a3 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -149,7 +149,6 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_ENABLE_LIBXML2", "OFF") .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); @@ -163,6 +162,14 @@ impl Step for Llvm { cfg.define("LLVM_OCAML_INSTALL_PATH", env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); + // Build clang and lldb if asked, or if doing a macOS nightly + // build. LLVM_ENABLE_PROJECTS allows them to be checked out + // parallel to src/llvm, and makes conditionally building them + // simpler. + let want_lldb = builder.config.lldb_enabled || + (target.contains("apple-darwin") && + builder.config.channel == "nightly"); + // This setting makes the LLVM tools link to the dynamic LLVM library, // which saves both memory during parallel links and overall disk space // for the tools. We don't distribute any of those tools, so this is @@ -170,12 +177,13 @@ impl Step for Llvm { // // If we are shipping llvm tools then we statically link them LLVM if (target.contains("linux-gnu") || target.contains("apple-darwin")) && - !builder.config.llvm_tools_enabled { + !builder.config.llvm_tools_enabled && + !want_lldb { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } // For distribution we want the LLVM tools to be *statically* linked to libstdc++ - if builder.config.llvm_tools_enabled { + if builder.config.llvm_tools_enabled || want_lldb { if !target.contains("windows") { if target.contains("apple") { cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++"); @@ -196,6 +204,12 @@ impl Step for Llvm { cfg.define("LLVM_BUILD_32_BITS", "ON"); } + if want_lldb { + cfg.define("LLVM_ENABLE_PROJECTS", "clang;lldb"); + } else { + cfg.define("LLVM_ENABLE_LIBXML2", "OFF"); + } + if let Some(num_linkers) = builder.config.llvm_link_jobs { if num_linkers > 0 { cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); diff --git a/src/clang b/src/clang new file mode 160000 index 0000000000000..6fda594059bd4 --- /dev/null +++ b/src/clang @@ -0,0 +1 @@ +Subproject commit 6fda594059bd48b6b2ddcb34eda0a278aee2214e diff --git a/src/lldb b/src/lldb new file mode 160000 index 0000000000000..3dbe998969d45 --- /dev/null +++ b/src/lldb @@ -0,0 +1 @@ +Subproject commit 3dbe998969d457c5cef245f61b48bdaed0f5c059 diff --git a/src/tools/rust-installer b/src/tools/rust-installer index 89414e44dc948..27dec6cae3a81 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit 89414e44dc94844888e59c08bc31dcccb1792800 +Subproject commit 27dec6cae3a8132d8a073aad6775425c85095c99 From 4aa21d173dc9986076e51580eada6c62d7c61bff Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 26 Jul 2018 07:33:12 -0600 Subject: [PATCH 2/4] Ignore clang and lldb in tidy --- src/tools/tidy/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index bb041b39785ec..baf2d2ebbc959 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -56,8 +56,10 @@ pub mod libcoretest; fn filter_dirs(path: &Path) -> bool { let skip = [ + "src/clang", "src/dlmalloc", "src/jemalloc", + "src/lldb", "src/llvm", "src/llvm-emscripten", "src/libbacktrace", From 77075781f38bdfe90f025b6834e16cae586c5f69 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 27 Jul 2018 07:55:50 -0600 Subject: [PATCH 3/4] Do not try to distribute lldb if it was not built --- src/bootstrap/dist.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index ab3c67128302f..c1ce0a6d3e327 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1992,6 +1992,17 @@ impl Step for Lldb { fn run(self, builder: &Builder) -> Option { let target = self.target; + // Do nothing if lldb was not built. This is difficult to + // determine in should_run because the target is not available + // at that point. + let bindir = builder + .llvm_out(target) + .join("bin"); + let lldb_exe = bindir.join(exe("lldb", &target)); + if !lldb_exe.exists() { + return None; + } + builder.info(&format!("Dist Lldb ({})", target)); let src = builder.src.join("src/lldb"); let name = pkgname(builder, "lldb"); @@ -2001,9 +2012,6 @@ impl Step for Lldb { drop(fs::remove_dir_all(&image)); // Prepare the image directory - let bindir = builder - .llvm_out(target) - .join("bin"); let dst = image.join("bin"); t!(fs::create_dir_all(&dst)); for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] { From 1d43f251dfd91de276966fe74452282b95a7aae2 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 27 Jul 2018 08:46:01 -0600 Subject: [PATCH 4/4] Handle the dry_run case in the lldb dist step --- src/bootstrap/dist.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c1ce0a6d3e327..cff03e610e2a2 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1992,9 +1992,10 @@ impl Step for Lldb { fn run(self, builder: &Builder) -> Option { let target = self.target; - // Do nothing if lldb was not built. This is difficult to - // determine in should_run because the target is not available - // at that point. + if builder.config.dry_run { + return None; + } + let bindir = builder .llvm_out(target) .join("bin");