diff --git a/.gitmodules b/.gitmodules index 5b7fd481299..55f586389b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -41,9 +41,6 @@ [submodule "src/dlmalloc"] path = src/dlmalloc url = https://github.com/alexcrichton/dlmalloc-rs.git -[submodule "src/binaryen"] - path = src/binaryen - url = https://github.com/alexcrichton/binaryen.git [submodule "src/doc/rust-by-example"] path = src/doc/rust-by-example url = https://github.com/rust-lang/rust-by-example @@ -53,3 +50,6 @@ [submodule "src/stdsimd"] path = src/stdsimd url = https://github.com/rust-lang-nursery/stdsimd +[submodule "src/tools/lld"] + path = src/tools/lld + url = https://github.com/rust-lang/lld.git diff --git a/.travis.yml b/.travis.yml index 0d8641e45ed..4738f91665d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,7 +81,7 @@ matrix: # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7. - env: > RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended --enable-profiler --enable-emscripten" + RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 @@ -95,7 +95,7 @@ matrix: - env: > RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers --enable-profiler --enable-emscripten" + RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 diff --git a/README.md b/README.md index e78bbb82711..19ef96fae01 100644 --- a/README.md +++ b/README.md @@ -129,9 +129,6 @@ CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64. python x.py build ``` -If you are seeing build failure when compiling `rustc_binaryen`, make sure the path -length of the rust folder is not longer than 22 characters. - #### Specifying an ABI [specifying-an-abi]: #specifying-an-abi diff --git a/appveyor.yml b/appveyor.yml index 0ea15dd671c..0735ead8923 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -67,21 +67,19 @@ environment: # 32/64 bit MSVC and GNU deployment - RUST_CONFIGURE_ARGS: > --build=x86_64-pc-windows-msvc - --enable-extended + --enable-full-tools --enable-profiler - --enable-emscripten SCRIPT: python x.py dist DEPLOY: 1 - RUST_CONFIGURE_ARGS: > --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc - --enable-extended + --enable-full-tools --enable-profiler - --enable-emscripten SCRIPT: python x.py dist DEPLOY: 1 - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-emscripten + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools SCRIPT: python x.py dist MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z @@ -89,7 +87,7 @@ environment: DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-emscripten + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 diff --git a/config.toml.example b/config.toml.example index 3dfd25aade1..b47f9163c0d 100644 --- a/config.toml.example +++ b/config.toml.example @@ -329,6 +329,10 @@ # target, as without this option the test output will not be captured. #wasm-syscall = false +# Indicates whether LLD will be compiled and made available in the sysroot for +# rustc to execute. +#lld = false + # ============================================================================= # Options for specific targets # diff --git a/src/Cargo.lock b/src/Cargo.lock index 7b4bfecea3f..7620fe8ddb3 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1818,15 +1818,6 @@ dependencies = [ "syntax 0.0.0", ] -[[package]] -name = "rustc_binaryen" -version = "0.0.0" -dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rustc_borrowck" version = "0.0.0" @@ -2107,7 +2098,6 @@ dependencies = [ "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_back 0.0.0", - "rustc_binaryen 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", diff --git a/src/binaryen b/src/binaryen deleted file mode 160000 index 17841e155ed..00000000000 --- a/src/binaryen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 17841e155edf858c8ea7802dd5f5ecbef54b989f diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index ca35a896e08..6c3c48aba72 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -224,7 +224,7 @@ fn main() { // flesh out rpath support more fully in the future. cmd.arg("-Z").arg("osx-rpath-install-name"); Some("-Wl,-rpath,@loader_path/../lib") - } else if !target.contains("windows") { + } else if !target.contains("windows") && !target.contains("wasm32") { Some("-Wl,-rpath,$ORIGIN/../lib") } else { None diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 77df372d4fa..d8f7cd7ed92 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -641,6 +641,10 @@ class RustBuild(object): continue if self.get_toml('jemalloc'): continue + if module.endswith("lld"): + config = self.get_toml('lld') + if config is None or config == 'false': + continue filtered_submodules.append(module) run(["git", "submodule", "update", "--init", "--recursive"] + filtered_submodules, diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index bc75d31e06e..8cbb1f3d0e9 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -316,7 +316,7 @@ macro_rules! describe { tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest, tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient, tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, - native::Llvm, tool::Rustfmt, tool::Miri), + native::Llvm, tool::Rustfmt, tool::Miri, native::Lld), Kind::Check => describe!(check::Std, check::Test, check::Rustc), Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass, test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind, diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index e531fdaf292..9e1b1f7db2f 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -79,6 +79,9 @@ pub fn find(build: &mut Build) { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false) .target(&target).host(&build.build); + if target.contains("msvc") { + cfg.static_crt(true); + } let config = build.config.target_config.get(&target); if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 30ca9dffc19..695cf04a82c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -747,6 +747,21 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, } } +fn copy_lld_to_sysroot(builder: &Builder, + target_compiler: Compiler, + lld_install_root: &Path) { + let target = target_compiler.host; + + let dst = builder.sysroot_libdir(target_compiler, target) + .parent() + .unwrap() + .join("bin"); + t!(fs::create_dir_all(&dst)); + + let exe = exe("lld", &target); + copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe)); +} + /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { @@ -896,6 +911,14 @@ fn run(self, builder: &Builder) -> Compiler { } } + let lld_install = if build.config.lld_enabled && target_compiler.stage > 0 { + Some(builder.ensure(native::Lld { + target: target_compiler.host, + })) + } else { + None + }; + let stage = target_compiler.stage; let host = target_compiler.host; println!("Assembling stage{} compiler ({})", stage, host); @@ -915,6 +938,9 @@ fn run(self, builder: &Builder) -> Compiler { copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); + if let Some(lld_install) = lld_install { + copy_lld_to_sysroot(builder, target_compiler, &lld_install); + } // Link the compiler binary itself into place let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 361fc704bc0..f15d4d35858 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -81,6 +81,8 @@ pub struct Config { pub llvm_experimental_targets: String, pub llvm_link_jobs: Option, + pub lld_enabled: bool, + // rust codegen options pub rust_optimize: bool, pub rust_codegen_units: Option, @@ -292,6 +294,7 @@ struct Rust { codegen_backends: Option>, codegen_backends_dir: Option, wasm_syscall: Option, + lld: Option, } /// TOML representation of how each build target is configured. @@ -480,6 +483,7 @@ pub fn parse(args: &[String]) -> Config { set(&mut config.quiet_tests, rust.quiet_tests); set(&mut config.test_miri, rust.test_miri); set(&mut config.wasm_syscall, rust.wasm_syscall); + set(&mut config.lld_enabled, rust.lld); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 99a3ee4e4c3..e9b4a233d0a 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -66,6 +66,7 @@ o("dist-src", "rust.dist-src", "when building tarballs enables building a source o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo") o("profiler", "build.profiler", "build the profiler runtime") o("emscripten", None, "compile the emscripten backend as well as LLVM") +o("full-tools", None, "enable all tools") # Optimization and debugging options. These may be overridden by the release # channel, etc. @@ -326,6 +327,10 @@ for key in known_args: set('build.target', value.split(',')) elif option.name == 'emscripten': set('rust.codegen-backends', ['llvm', 'emscripten']) + elif option.name == 'full-tools': + set('rust.codegen-backends', ['llvm', 'emscripten']) + set('rust.lld', True) + set('build.extended', True) elif option.name == 'option-checking': # this was handled above pass diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 05630b8431f..02ef7c0e1ff 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -28,7 +28,7 @@ use {Build, Compiler, Mode}; use channel; -use util::{cp_r, libdir, is_dylib, cp_filtered, copy, replace_in_file}; +use util::{cp_r, libdir, is_dylib, cp_filtered, copy, replace_in_file, exe}; use builder::{Builder, RunConfig, ShouldRun, Step}; use compile; use native; @@ -443,6 +443,22 @@ fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) { t!(fs::create_dir_all(&backends_dst)); cp_r(&backends_src, &backends_dst); + // Copy over lld if it's there + if builder.config.lld_enabled { + let exe = exe("lld", &compiler.host); + let src = builder.sysroot_libdir(compiler, host) + .parent() + .unwrap() + .join("bin") + .join(&exe); + let dst = image.join("lib/rustlib") + .join(&*host) + .join("bin") + .join(&exe); + t!(fs::create_dir_all(&dst.parent().unwrap())); + copy(&src, &dst); + } + // Man pages t!(fs::create_dir_all(image.join("share/man/man1"))); let man_src = build.src.join("src/doc/man"); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 90f50275b6b..f3d9246c6fc 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -501,6 +501,10 @@ fn emscripten_llvm_out(&self, target: Interned) -> PathBuf { self.out.join(&*target).join("llvm-emscripten") } + fn lld_out(&self, target: Interned) -> PathBuf { + self.out.join(&*target).join("lld") + } + /// Output directory for all documentation for a target fn doc_out(&self, target: Interned) -> PathBuf { self.out.join(&*target).join("doc") @@ -685,7 +689,9 @@ fn linker(&self, target: Interned) -> Option<&Path> { .and_then(|c| c.linker.as_ref()) { Some(linker) } else if target != self.config.build && - !target.contains("msvc") && !target.contains("emscripten") { + !target.contains("msvc") && + !target.contains("emscripten") && + !target.contains("wasm32") { Some(self.cc(target)) } else { None diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 653606e5d24..987d70fd047 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -81,11 +81,11 @@ fn run(self, builder: &Builder) -> PathBuf { let (out_dir, llvm_config_ret_dir) = if emscripten { let dir = build.emscripten_llvm_out(target); - let config_dir = dir.join("bin"); + let config_dir = dir.join("build/bin"); (dir, config_dir) } else { (build.llvm_out(target), - build.llvm_out(build.config.build).join("bin")) + build.llvm_out(build.config.build).join("build/bin")) }; let done_stamp = out_dir.join("llvm-finished-building"); let build_llvm_config = llvm_config_ret_dir @@ -110,9 +110,6 @@ fn run(self, builder: &Builder) -> PathBuf { // http://llvm.org/docs/CMake.html let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" }; let mut cfg = cmake::Config::new(build.src.join(root)); - if build.config.ninja { - cfg.generator("Ninja"); - } let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) { (false, _) => "Debug", @@ -139,9 +136,7 @@ fn run(self, builder: &Builder) -> PathBuf { let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; - cfg.target(&target) - .host(&build.build) - .out_dir(&out_dir) + cfg.out_dir(&out_dir) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) .define("LLVM_TARGETS_TO_BUILD", llvm_targets) @@ -213,67 +208,7 @@ fn run(self, builder: &Builder) -> PathBuf { cfg.define("LLVM_NATIVE_BUILD", build.llvm_out(build.build).join("build")); } - let sanitize_cc = |cc: &Path| { - if target.contains("msvc") { - OsString::from(cc.to_str().unwrap().replace("\\", "/")) - } else { - cc.as_os_str().to_owned() - } - }; - - let configure_compilers = |cfg: &mut cmake::Config| { - // MSVC with CMake uses msbuild by default which doesn't respect these - // vars that we'd otherwise configure. In that case we just skip this - // entirely. - if target.contains("msvc") && !build.config.ninja { - return - } - - let cc = build.cc(target); - let cxx = build.cxx(target).unwrap(); - - // Handle msvc + ninja + ccache specially (this is what the bots use) - if target.contains("msvc") && - build.config.ninja && - build.config.ccache.is_some() { - let mut cc = env::current_exe().expect("failed to get cwd"); - cc.set_file_name("sccache-plus-cl.exe"); - - cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) - .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc)); - cfg.env("SCCACHE_PATH", - build.config.ccache.as_ref().unwrap()) - .env("SCCACHE_TARGET", target); - - // If ccache is configured we inform the build a little differently hwo - // to invoke ccache while also invoking our compilers. - } else if let Some(ref ccache) = build.config.ccache { - cfg.define("CMAKE_C_COMPILER", ccache) - .define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc)) - .define("CMAKE_CXX_COMPILER", ccache) - .define("CMAKE_CXX_COMPILER_ARG1", sanitize_cc(cxx)); - } else { - cfg.define("CMAKE_C_COMPILER", sanitize_cc(cc)) - .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx)); - } - - cfg.build_arg("-j").build_arg(build.jobs().to_string()); - cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" ")); - cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" ")); - if let Some(ar) = build.ar(target) { - if ar.is_absolute() { - // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it - // tries to resolve this path in the LLVM build directory. - cfg.define("CMAKE_AR", sanitize_cc(ar)); - } - } - }; - - configure_compilers(&mut cfg); - - if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=warn"); - } + configure_cmake(build, target, &mut cfg); // FIXME: we don't actually need to build all LLVM tools and all LLVM // libraries here, e.g. we just want a few components and a few @@ -304,6 +239,131 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) { panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version) } +fn configure_cmake(build: &Build, + target: Interned, + cfg: &mut cmake::Config) { + if build.config.ninja { + cfg.generator("Ninja"); + } + cfg.target(&target) + .host(&build.config.build); + + let sanitize_cc = |cc: &Path| { + if target.contains("msvc") { + OsString::from(cc.to_str().unwrap().replace("\\", "/")) + } else { + cc.as_os_str().to_owned() + } + }; + + // MSVC with CMake uses msbuild by default which doesn't respect these + // vars that we'd otherwise configure. In that case we just skip this + // entirely. + if target.contains("msvc") && !build.config.ninja { + return + } + + let cc = build.cc(target); + let cxx = build.cxx(target).unwrap(); + + // Handle msvc + ninja + ccache specially (this is what the bots use) + if target.contains("msvc") && + build.config.ninja && + build.config.ccache.is_some() { + let mut cc = env::current_exe().expect("failed to get cwd"); + cc.set_file_name("sccache-plus-cl.exe"); + + cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) + .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc)); + cfg.env("SCCACHE_PATH", + build.config.ccache.as_ref().unwrap()) + .env("SCCACHE_TARGET", target); + + // If ccache is configured we inform the build a little differently hwo + // to invoke ccache while also invoking our compilers. + } else if let Some(ref ccache) = build.config.ccache { + cfg.define("CMAKE_C_COMPILER", ccache) + .define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc)) + .define("CMAKE_CXX_COMPILER", ccache) + .define("CMAKE_CXX_COMPILER_ARG1", sanitize_cc(cxx)); + } else { + cfg.define("CMAKE_C_COMPILER", sanitize_cc(cc)) + .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx)); + } + + cfg.build_arg("-j").build_arg(build.jobs().to_string()); + cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" ")); + let mut cxxflags = build.cflags(target).join(" "); + if build.config.llvm_static_stdcpp && !target.contains("windows") { + cxxflags.push_str(" -static-libstdc++"); + } + cfg.define("CMAKE_CXX_FLAGS", cxxflags); + if let Some(ar) = build.ar(target) { + if ar.is_absolute() { + // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it + // tries to resolve this path in the LLVM build directory. + cfg.define("CMAKE_AR", sanitize_cc(ar)); + } + } + + if env::var_os("SCCACHE_ERROR_LOG").is_some() { + cfg.env("RUST_LOG", "sccache=warn"); + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Lld { + pub target: Interned, +} + +impl Step for Lld { + type Output = PathBuf; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/lld") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Lld { target: run.target }); + } + + /// Compile LLVM for `target`. + fn run(self, builder: &Builder) -> PathBuf { + let target = self.target; + let build = builder.build; + + let llvm_config = builder.ensure(Llvm { + target: self.target, + emscripten: false, + }); + + let out_dir = build.lld_out(target); + let done_stamp = out_dir.join("lld-finished-building"); + if done_stamp.exists() { + return out_dir + } + + let _folder = build.fold_output(|| "lld"); + println!("Building LLD for {}", target); + let _time = util::timeit(); + t!(fs::create_dir_all(&out_dir)); + + let mut cfg = cmake::Config::new(build.src.join("src/tools/lld")); + configure_cmake(build, target, &mut cfg); + + cfg.out_dir(&out_dir) + .profile("Release") + .define("LLVM_CONFIG_PATH", llvm_config) + .define("LLVM_INCLUDE_TESTS", "OFF"); + + cfg.build(); + + t!(File::create(&done_stamp)); + out_dir + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TestHelpers { pub target: Interned, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index b27ddfdbc5e..c0998c1e42c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -914,7 +914,7 @@ fn run(self, builder: &Builder) { } if build.config.llvm_enabled { - let llvm_config = build.llvm_config(target); + let llvm_config = build.llvm_config(build.config.build); let llvm_version = output(Command::new(&llvm_config).arg("--version")); cmd.arg("--llvm-version").arg(llvm_version); if !build.is_rust_llvm(target) { diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index da7c6233fc8..0ec57ee0886 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -82,10 +82,9 @@ RUN sh /scripts/sccache.sh ENV HOSTS=i686-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ + --enable-full-tools \ --enable-sanitizers \ - --enable-profiler \ - --enable-emscripten + --enable-profiler ENV SCRIPT python2.7 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS # This is the only builder which will create source tarballs diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 86b3beeb4e5..3b98b0aa926 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -82,10 +82,9 @@ RUN sh /scripts/sccache.sh ENV HOSTS=x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ + --enable-full-tools \ --enable-sanitizers \ - --enable-profiler \ - --enable-emscripten + --enable-profiler ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS # This is the only builder which will create source tarballs diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile index 106f907bab9..0972eb85191 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/wasm32-unknown/Dockerfile @@ -22,7 +22,8 @@ RUN sh /scripts/sccache.sh ENV TARGETS=wasm32-unknown-unknown ENV RUST_CONFIGURE_ARGS \ - --set build.nodejs=/node-v9.2.0-linux-x64/bin/node + --set build.nodejs=/node-v9.2.0-linux-x64/bin/node \ + --set rust.lld ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ src/test/ui \ diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js index 69647f37eec..98d6202a63f 100644 --- a/src/etc/wasm32-shim.js +++ b/src/etc/wasm32-shim.js @@ -107,6 +107,8 @@ imports.env = { exp2f: function(x) { return Math.pow(2, x); }, ldexp: function(x, y) { return x * Math.pow(2, y); }, ldexpf: function(x, y) { return x * Math.pow(2, y); }, + log: Math.log, + log2: Math.log2, log10: Math.log10, log10f: Math.log10, diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 8bf60b091a7..141c8954a33 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -43,14 +43,29 @@ use serialize::json::{Json, ToJson}; -macro_rules! linker_flavor { - ($(($variant:ident, $string:expr),)+) => { - #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, - RustcEncodable, RustcDecodable)] - pub enum LinkerFlavor { - $($variant,)+ - } +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, + RustcEncodable, RustcDecodable)] +pub enum LinkerFlavor { + Em, + Gcc, + Ld, + Msvc, + Lld(LldFlavor), +} +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, + RustcEncodable, RustcDecodable)] +pub enum LldFlavor { + Wasm, +} + +impl ToJson for LinkerFlavor { + fn to_json(&self) -> Json { + self.desc().to_json() + } +} +macro_rules! flavor_mappings { + ($((($($flavor:tt)*), $string:expr),)*) => ( impl LinkerFlavor { pub const fn one_of() -> &'static str { concat!("one of: ", $($string, " ",)+) @@ -58,32 +73,27 @@ pub const fn one_of() -> &'static str { pub fn from_str(s: &str) -> Option { Some(match s { - $($string => LinkerFlavor::$variant,)+ + $($string => $($flavor)*,)+ _ => return None, }) } pub fn desc(&self) -> &str { match *self { - $(LinkerFlavor::$variant => $string,)+ + $($($flavor)* => $string,)+ } } } - - impl ToJson for LinkerFlavor { - fn to_json(&self) -> Json { - self.desc().to_json() - } - } - } + ) } -linker_flavor! { - (Em, "em"), - (Binaryen, "binaryen"), - (Gcc, "gcc"), - (Ld, "ld"), - (Msvc, "msvc"), + +flavor_mappings! { + ((LinkerFlavor::Em), "em"), + ((LinkerFlavor::Gcc), "gcc"), + ((LinkerFlavor::Ld), "ld"), + ((LinkerFlavor::Msvc), "msvc"), + ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), } #[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_back/target/wasm32_unknown_unknown.rs b/src/librustc_back/target/wasm32_unknown_unknown.rs index 242860e5c6e..c771762cfc8 100644 --- a/src/librustc_back/target/wasm32_unknown_unknown.rs +++ b/src/librustc_back/target/wasm32_unknown_unknown.rs @@ -8,40 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// The wasm32-unknown-unknown target is currently a highly experimental version -// of a wasm-based target which does *not* use the Emscripten toolchain. Instead -// this is a pretty flavorful (aka hacked up) target right now. The definition -// and semantics of this target are likely to change and so this shouldn't be -// relied on just yet. +// The wasm32-unknown-unknown target is currently an experimental version of a +// wasm-based target which does *not* use the Emscripten toolchain. Instead +// this toolchain is based purely on LLVM's own toolchain, using LLVM's native +// WebAssembly backend as well as LLD for a native linker. // -// In general everyone is currently waiting on a linker for wasm code. In the -// meantime we have no means of actually making use of the traditional separate -// compilation model. At a high level this means that assembling Rust programs -// into a WebAssembly program looks like: -// -// 1. All intermediate artifacts are LLVM bytecode. We'll be using LLVM as -// a linker later on. -// 2. For the final artifact we emit one giant assembly file (WebAssembly -// doesn't have an object file format). To do this we force LTO to be turned -// on (`requires_lto` below) to ensure all Rust code is in one module. Any -// "linked" C library is basically just ignored. -// 3. Using LLVM we emit a `foo.s` file (assembly) with some... what I can only -// describe as arcane syntax. From there we need to actually change this -// into a wasm module. For this step we use the `binaryen` project. This -// project is mostly intended as a WebAssembly code generator, but for now -// we're just using its LLVM-assembly-to-wasm-module conversion utilities. -// -// And voila, out comes a web assembly module! There's some various tweaks here -// and there, but that's the high level at least. Note that this will be -// rethought from the ground up once a linker (lld) is available, so this is all -// temporary and should improve in the future. +// There's some trickery below on crate types supported and various defaults +// (aka panic=abort by default), but otherwise this is in general a relatively +// standard target. -use LinkerFlavor; +use {LinkerFlavor, LldFlavor}; use super::{Target, TargetOptions, PanicStrategy}; pub fn target() -> Result { let opts = TargetOptions { - linker: "not-used".to_string(), + linker: "lld".to_string(), // we allow dynamic linking, but only cdylibs. Basically we allow a // final library artifact that exports some symbols (a wasm module) but @@ -58,9 +39,6 @@ pub fn target() -> Result { dll_suffix: ".wasm".to_string(), linker_is_gnu: false, - // We're storing bitcode for now in all the rlibs - obj_is_bitcode: true, - // A bit of a lie, but "eh" max_atomic_width: Some(32), @@ -69,27 +47,17 @@ pub fn target() -> Result { // the future once unwinding is implemented. Don't rely on this. panic_strategy: PanicStrategy::Abort, - // There's no linker yet so we're forced to use LLVM as a linker. This - // means that we must always enable LTO for final artifacts. - requires_lto: true, - // Wasm doesn't have atomics yet, so tell LLVM that we're in a single // threaded model which will legalize atomics to normal operations. singlethread: true, - // Because we're always enabling LTO we can't enable builtin lowering as - // otherwise we'll lower the definition of the `memcpy` function to - // memcpy itself. Note that this is specifically because we're - // performing LTO with compiler-builtins. - no_builtins: true, - // no dynamic linking, no need for default visibility! default_hidden_visibility: true, .. Default::default() }; Ok(Target { - llvm_target: "wasm32-unknown-unknown".to_string(), + llvm_target: "wasm32-unknown-unknown-wasm".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), @@ -100,8 +68,7 @@ pub fn target() -> Result { target_vendor: "unknown".to_string(), data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(), arch: "wasm32".to_string(), - // A bit of a lie, but it gets the job done - linker_flavor: LinkerFlavor::Binaryen, + linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm), options: opts, }) } diff --git a/src/librustc_binaryen/BinaryenWrapper.cpp b/src/librustc_binaryen/BinaryenWrapper.cpp deleted file mode 100644 index 55f11665f6d..00000000000 --- a/src/librustc_binaryen/BinaryenWrapper.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2017 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. - -// This is a small C API inserted on top of the Binaryen C++ API which we use -// from Rust. Once we have a real linker for we'll be able to remove all this, -// and otherwise this is just all on a "as we need it" basis for now. - -#include -#include -#include -#include - -#include "s2wasm.h" -#include "wasm-binary.h" -#include "wasm-linker.h" - -using namespace wasm; - -struct BinaryenRustModule { - BufferWithRandomAccess buffer; - std::string sourceMapJSON; -}; - -struct BinaryenRustModuleOptions { - uint64_t globalBase; - bool debug; - uint64_t stackAllocation; - uint64_t initialMem; - uint64_t maxMem; - bool importMemory; - bool ignoreUnknownSymbols; - bool debugInfo; - std::string startFunction; - std::string sourceMapUrl; - - BinaryenRustModuleOptions() : - globalBase(0), - debug(false), - stackAllocation(0), - initialMem(0), - maxMem(0), - importMemory(false), - ignoreUnknownSymbols(false), - debugInfo(false), - startFunction(""), - sourceMapUrl("") - {} - -}; - -extern "C" BinaryenRustModuleOptions* -BinaryenRustModuleOptionsCreate() { - return new BinaryenRustModuleOptions; -} - -extern "C" void -BinaryenRustModuleOptionsFree(BinaryenRustModuleOptions *options) { - delete options; -} - -extern "C" void -BinaryenRustModuleOptionsSetDebugInfo(BinaryenRustModuleOptions *options, - bool debugInfo) { - options->debugInfo = debugInfo; -} - -extern "C" void -BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options, - char *start) { - options->startFunction = start; -} - -extern "C" void -BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options, - char *sourceMapUrl) { - options->sourceMapUrl = sourceMapUrl; -} - -extern "C" void -BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options, - uint64_t stack) { - options->stackAllocation = stack; -} - -extern "C" void -BinaryenRustModuleOptionsSetImportMemory(BinaryenRustModuleOptions *options, - bool import) { - options->importMemory = import; -} - -extern "C" BinaryenRustModule* -BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options, - const char *assembly) { - Linker linker( - options->globalBase, - options->stackAllocation, - options->initialMem, - options->maxMem, - options->importMemory, - options->ignoreUnknownSymbols, - options->startFunction, - options->debug); - - S2WasmBuilder mainbuilder(assembly, options->debug); - linker.linkObject(mainbuilder); - linker.layout(); - - auto ret = make_unique(); - { - WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug); - writer.setNamesSection(options->debugInfo); - - std::unique_ptr sourceMapStream = nullptr; - { - sourceMapStream = make_unique(); - writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl); - } - - // FIXME: support symbol maps? - // writer.setSymbolMap(symbolMap); - writer.write(); - - if (sourceMapStream) { - ret->sourceMapJSON = sourceMapStream->str(); - } - } - return ret.release(); -} - -extern "C" const uint8_t* -BinaryenRustModulePtr(const BinaryenRustModule *M) { - return M->buffer.data(); -} - -extern "C" size_t -BinaryenRustModuleLen(const BinaryenRustModule *M) { - return M->buffer.size(); -} - -extern "C" const char* -BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) { - return M->sourceMapJSON.data(); -} - -extern "C" size_t -BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) { - return M->sourceMapJSON.length(); -} - -extern "C" void -BinaryenRustModuleFree(BinaryenRustModule *M) { - delete M; -} diff --git a/src/librustc_binaryen/Cargo.toml b/src/librustc_binaryen/Cargo.toml deleted file mode 100644 index 9573c894714..00000000000 --- a/src/librustc_binaryen/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -# Wondering what this crate is? Take a look at the `lib.rs`! - -[package] -name = "rustc_binaryen" -version = "0.0.0" -authors = ["The Rust Project Developers"] - -[lib] -path = "lib.rs" - -[dependencies] -libc = "0.2" - -[build-dependencies] -cmake = "0.1" -cc = "1.0" diff --git a/src/librustc_binaryen/build.rs b/src/librustc_binaryen/build.rs deleted file mode 100644 index f23ff3cee55..00000000000 --- a/src/librustc_binaryen/build.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2017 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. - -extern crate cc; -extern crate cmake; - -use std::env; - -use cmake::Config; - -fn main() { - let target = env::var("TARGET").unwrap(); - - // Bring in `__emutls_get_address` which is apparently needed for now - if target.contains("pc-windows-gnu") { - println!("cargo:rustc-link-lib=gcc_eh"); - println!("cargo:rustc-link-lib=pthread"); - } - - Config::new("../binaryen") - .define("BUILD_STATIC_LIB", "ON") - .build_target("binaryen") - .build(); - - // I couldn't figure out how to link just one of these, so link everything. - println!("cargo:rustc-link-lib=static=asmjs"); - println!("cargo:rustc-link-lib=static=binaryen"); - println!("cargo:rustc-link-lib=static=cfg"); - println!("cargo:rustc-link-lib=static=emscripten-optimizer"); - println!("cargo:rustc-link-lib=static=ir"); - println!("cargo:rustc-link-lib=static=passes"); - println!("cargo:rustc-link-lib=static=support"); - println!("cargo:rustc-link-lib=static=wasm"); - - let out_dir = env::var("OUT_DIR").unwrap(); - println!("cargo:rustc-link-search=native={}/build/lib", out_dir); - - // Add in our own little shim along with some extra files that weren't - // included in the main build. - let mut cfg = cc::Build::new(); - cfg.file("BinaryenWrapper.cpp") - .file("../binaryen/src/wasm-linker.cpp") - .file("../binaryen/src/wasm-emscripten.cpp") - .include("../binaryen/src") - .cpp_link_stdlib(None) - .warnings(false) - .cpp(true); - - if !target.contains("msvc") { - cfg.flag("-std=c++11"); - } - cfg.compile("binaryen_wrapper"); -} diff --git a/src/librustc_binaryen/lib.rs b/src/librustc_binaryen/lib.rs deleted file mode 100644 index 36174e11ba0..00000000000 --- a/src/librustc_binaryen/lib.rs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2017 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. - -//! Rustc bindings to the binaryen project. -//! -//! This crate is a small shim around the binaryen project which provides us the -//! ability to take LLVM's output and generate a wasm module. Specifically this -//! only supports one operation, creating a module from LLVM's assembly format -//! and then serializing that module to a wasm module. - -extern crate libc; - -use std::slice; -use std::ffi::{CString, CStr}; - -/// In-memory representation of a serialized wasm module. -pub struct Module { - ptr: *mut BinaryenRustModule, -} - -impl Module { - /// Creates a new wasm module from the LLVM-assembly provided (in a C string - /// format). - /// - /// The actual module creation can be tweaked through the various options in - /// `ModuleOptions` as well. Any errors are just returned as a bland string. - pub fn new(assembly: &CStr, opts: &ModuleOptions) -> Result { - unsafe { - let ptr = BinaryenRustModuleCreate(opts.ptr, assembly.as_ptr()); - if ptr.is_null() { - Err(format!("failed to create binaryen module")) - } else { - Ok(Module { ptr }) - } - } - } - - /// Returns the data of the serialized wasm module. This is a `foo.wasm` - /// file contents. - pub fn data(&self) -> &[u8] { - unsafe { - let ptr = BinaryenRustModulePtr(self.ptr); - let len = BinaryenRustModuleLen(self.ptr); - slice::from_raw_parts(ptr, len) - } - } - - /// Returns the data of the source map JSON. - pub fn source_map(&self) -> &[u8] { - unsafe { - let ptr = BinaryenRustModuleSourceMapPtr(self.ptr); - let len = BinaryenRustModuleSourceMapLen(self.ptr); - slice::from_raw_parts(ptr, len) - } - } -} - -impl Drop for Module { - fn drop(&mut self) { - unsafe { - BinaryenRustModuleFree(self.ptr); - } - } -} - -pub struct ModuleOptions { - ptr: *mut BinaryenRustModuleOptions, -} - -impl ModuleOptions { - pub fn new() -> ModuleOptions { - unsafe { - let ptr = BinaryenRustModuleOptionsCreate(); - ModuleOptions { ptr } - } - } - - /// Turns on or off debug info. - /// - /// From what I can tell this just creates a "names" section of the wasm - /// module which contains a table of the original function names. - pub fn debuginfo(&mut self, debug: bool) -> &mut Self { - unsafe { - BinaryenRustModuleOptionsSetDebugInfo(self.ptr, debug); - } - self - } - - /// Configures a `start` function for the module, to be executed when it's - /// loaded. - pub fn start(&mut self, func: &str) -> &mut Self { - let func = CString::new(func).unwrap(); - unsafe { - BinaryenRustModuleOptionsSetStart(self.ptr, func.as_ptr()); - } - self - } - - /// Configures a `sourceMappingURL` custom section value for the module. - pub fn source_map_url(&mut self, url: &str) -> &mut Self { - let url = CString::new(url).unwrap(); - unsafe { - BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr()); - } - self - } - - /// Configures how much stack is initially allocated for the module. 1MB is - /// probably good enough for now. - pub fn stack(&mut self, amt: u64) -> &mut Self { - unsafe { - BinaryenRustModuleOptionsSetStackAllocation(self.ptr, amt); - } - self - } - - /// Flags whether the initial memory should be imported or exported. So far - /// we export it by default. - pub fn import_memory(&mut self, import: bool) -> &mut Self { - unsafe { - BinaryenRustModuleOptionsSetImportMemory(self.ptr, import); - } - self - } -} - -impl Drop for ModuleOptions { - fn drop(&mut self) { - unsafe { - BinaryenRustModuleOptionsFree(self.ptr); - } - } -} - -enum BinaryenRustModule {} -enum BinaryenRustModuleOptions {} - -extern { - fn BinaryenRustModuleCreate(opts: *const BinaryenRustModuleOptions, - assembly: *const libc::c_char) - -> *mut BinaryenRustModule; - fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8; - fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize; - fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8; - fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize; - fn BinaryenRustModuleFree(module: *mut BinaryenRustModule); - - fn BinaryenRustModuleOptionsCreate() - -> *mut BinaryenRustModuleOptions; - fn BinaryenRustModuleOptionsSetDebugInfo(module: *mut BinaryenRustModuleOptions, - debuginfo: bool); - fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions, - start: *const libc::c_char); - fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions, - sourceMapUrl: *const libc::c_char); - fn BinaryenRustModuleOptionsSetStackAllocation( - module: *mut BinaryenRustModuleOptions, - stack: u64, - ); - fn BinaryenRustModuleOptionsSetImportMemory( - module: *mut BinaryenRustModuleOptions, - import: bool, - ); - fn BinaryenRustModuleOptionsFree(module: *mut BinaryenRustModuleOptions); -} diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 500c4fdf4e8..4b9c93088a5 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -21,7 +21,6 @@ rustc-demangle = "0.1.4" rustc_allocator = { path = "../librustc_allocator" } rustc_apfloat = { path = "../librustc_apfloat" } rustc_back = { path = "../librustc_back" } -rustc_binaryen = { path = "../librustc_binaryen" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_trans/back/command.rs b/src/librustc_trans/back/command.rs index 0bccef1e62a..e5e0a4e3ba0 100644 --- a/src/librustc_trans/back/command.rs +++ b/src/librustc_trans/back/command.rs @@ -17,6 +17,8 @@ use std::mem; use std::process::{self, Output}; +use rustc_back::LldFlavor; + #[derive(Clone)] pub struct Command { program: Program, @@ -28,6 +30,7 @@ pub struct Command { enum Program { Normal(OsString), CmdBatScript(OsString), + Lld(OsString, LldFlavor) } impl Command { @@ -39,6 +42,10 @@ pub fn bat_script>(program: P) -> Command { Command::_new(Program::CmdBatScript(program.as_ref().to_owned())) } + pub fn lld>(program: P, flavor: LldFlavor) -> Command { + Command::_new(Program::Lld(program.as_ref().to_owned(), flavor)) + } + fn _new(program: Program) -> Command { Command { program, @@ -101,6 +108,13 @@ pub fn command(&self) -> process::Command { c.arg("/c").arg(p); c } + Program::Lld(ref p, flavor) => { + let mut c = process::Command::new(p); + c.arg("-flavor").arg(match flavor { + LldFlavor::Wasm => "wasm", + }); + c + } }; ret.args(&self.args); ret.envs(self.env.clone()); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 8f308e72686..c134203a773 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -15,6 +15,7 @@ use super::rpath::RPathConfig; use super::rpath; use metadata::METADATA_FILENAME; +use rustc_back::LinkerFlavor; use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest}; use rustc::session::config::{RUST_CGU_EXT, Lto}; use rustc::session::filesearch; @@ -27,7 +28,7 @@ use rustc::util::fs::fix_windows_verbatim_for_gcc; use rustc::hir::def_id::CrateNum; use tempdir::TempDir; -use rustc_back::{PanicStrategy, RelroLevel, LinkerFlavor}; +use rustc_back::{PanicStrategy, RelroLevel}; use context::get_reloc_model; use llvm; @@ -82,6 +83,10 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command, Vec<(OsString, OsString) } else if sess.target.target.options.is_like_msvc { let (cmd, envs) = msvc_link_exe_cmd(sess); (PathBuf::from("link.exe"), cmd, envs) + } else if let LinkerFlavor::Lld(f) = sess.linker_flavor() { + let linker = PathBuf::from(&sess.target.target.options.linker); + let cmd = Command::lld(&linker, f); + (linker, cmd, envs) } else { let linker = PathBuf::from(&sess.target.target.options.linker); let cmd = cmd(&linker); @@ -612,11 +617,6 @@ fn link_natively(sess: &Session, info!("preparing {:?} to {:?}", crate_type, out_filename); let flavor = sess.linker_flavor(); - // The "binaryen linker" is massively special, so skip everything below. - if flavor == LinkerFlavor::Binaryen { - return link_binaryen(sess, crate_type, out_filename, trans, tmpdir); - } - // The invocations of cc share some flags across platforms let (pname, mut cmd, envs) = get_linker(sess); // This will set PATH on windows @@ -1485,33 +1485,6 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { } } -/// For now "linking with binaryen" is just "move the one module we generated in -/// the backend to the final output" -/// -/// That is, all the heavy lifting happens during the `back::write` phase. Here -/// we just clean up after that. -/// -/// Note that this is super temporary and "will not survive the night", this is -/// guaranteed to get removed as soon as a linker for wasm exists. This should -/// not be used for anything other than wasm. -fn link_binaryen(sess: &Session, - _crate_type: config::CrateType, - out_filename: &Path, - trans: &CrateTranslation, - _tmpdir: &Path) { - assert!(trans.allocator_module.is_none()); - assert_eq!(trans.modules.len(), 1); - - let object = trans.modules[0].object.as_ref().expect("object must exist"); - let res = fs::hard_link(object, out_filename) - .or_else(|_| fs::copy(object, out_filename).map(|_| ())); - if let Err(e) = res { - sess.fatal(&format!("failed to create `{}`: {}", - out_filename.display(), - e)); - } -} - fn is_full_lto_enabled(sess: &Session) -> bool { match sess.lto() { Lto::Yes | diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 7e7811c56c7..a82270c5272 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -23,7 +23,7 @@ use rustc::session::Session; use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel}; use rustc::ty::TyCtxt; -use rustc_back::LinkerFlavor; +use rustc_back::{LinkerFlavor, LldFlavor}; use serialize::{json, Encoder}; /// For all the linkers we support, and information they might @@ -77,8 +77,11 @@ pub fn to_linker<'a>(&'a self, is_ld: true, }) as Box } - LinkerFlavor::Binaryen => { - panic!("can't instantiate binaryen linker") + + LinkerFlavor::Lld(LldFlavor::Wasm) => { + Box::new(WasmLd { + cmd, + }) as Box } } } @@ -785,3 +788,111 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { symbols } + +pub struct WasmLd { + cmd: Command, +} + +impl Linker for WasmLd { + fn link_dylib(&mut self, lib: &str) { + self.cmd.arg("-l").arg(lib); + } + + fn link_staticlib(&mut self, lib: &str) { + self.cmd.arg("-l").arg(lib); + } + + fn link_rlib(&mut self, lib: &Path) { + self.cmd.arg(lib); + } + + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn framework_path(&mut self, _path: &Path) { + panic!("frameworks not supported") + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn position_independent_executable(&mut self) { + } + + fn partial_relro(&mut self) { + } + + fn full_relro(&mut self) { + } + + fn build_static_executable(&mut self) { + } + + fn args(&mut self, args: &[String]) { + self.cmd.args(args); + } + + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.cmd.arg("-l").arg(lib); + } + + fn link_framework(&mut self, _framework: &str) { + panic!("frameworks not supported") + } + + fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { + self.cmd.arg("-l").arg(lib); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + self.cmd.arg(lib); + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + } + + fn optimize(&mut self) { + } + + fn debuginfo(&mut self) { + } + + fn no_default_libraries(&mut self) { + } + + fn build_dylib(&mut self, _out_filename: &Path) { + } + + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) { + } + + fn subsystem(&mut self, _subsystem: &str) { + } + + fn no_position_independent_executable(&mut self) { + } + + fn finalize(&mut self) -> Command { + self.cmd.arg("--threads"); + + // FIXME we probably shouldn't pass this but instead pass an explicit + // whitelist of symbols we'll allow to be undefined. Unfortunately + // though we can't handle symbols like `log10` that LLVM injects at a + // super late date without actually parsing object files. For now let's + // stick to this and hopefully fix it before stabilization happens. + self.cmd.arg("--allow-undefined"); + + // For now we just never have an entry symbol + self.cmd.arg("--no-entry"); + + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } +} diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 68c0ba02650..55ef4e7ed3a 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -21,7 +21,6 @@ use rustc::ty::maps::Providers; use rustc::util::nodemap::FxHashMap; use rustc_allocator::ALLOCATOR_METHODS; -use rustc_back::LinkerFlavor; use syntax::attr; pub type ExportedSymbols = FxHashMap< @@ -156,26 +155,12 @@ pub fn provide_extern(providers: &mut Providers) { let special_runtime_crate = tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); - // Dealing with compiler-builtins and wasm right now is super janky. - // There's no linker! As a result we need all of the compiler-builtins - // exported symbols to make their way through all the way to the end of - // compilation. We want to make sure that LLVM doesn't remove them as - // well because we may or may not need them in the final output - // artifact. For now just force them to always get exported at the C - // layer, and we'll worry about gc'ing them later. - let compiler_builtins_and_binaryen = - tcx.is_compiler_builtins(cnum) && - tcx.sess.linker_flavor() == LinkerFlavor::Binaryen; - let mut crate_exports: Vec<_> = tcx .exported_symbol_ids(cnum) .iter() .map(|&def_id| { let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = if compiler_builtins_and_binaryen && - tcx.contains_extern_indicator(def_id) { - SymbolExportLevel::C - } else if special_runtime_crate { + let export_level = if special_runtime_crate { // We can probably do better here by just ensuring that // it has hidden visibility rather than public // visibility, as this is primarily here to ensure it's diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index af5178eb565..1664aa9d0b3 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -23,7 +23,6 @@ AllPasses, Sanitizer, Lto}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; -use rustc_back::LinkerFlavor; use time_graph::{self, TimeGraph, Timeline}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; @@ -344,9 +343,7 @@ pub struct CodegenContext { pub tm_factory: Arc Result + Send + Sync>, pub msvc_imps_needed: bool, pub target_pointer_width: String, - binaryen_linker: bool, debuginfo: config::DebugInfoLevel, - wasm_import_memory: bool, // Number of cgus excluding the allocator/metadata modules pub total_cgus: usize, @@ -639,13 +636,6 @@ unsafe fn with_codegen(tm: TargetMachineRef, f(cpm) } - // If we're going to generate wasm code from the assembly that llvm - // generates then we'll be transitively affecting a ton of options below. - // This only happens on the wasm target now. - let asm2wasm = cgcx.binaryen_linker && - !cgcx.crate_types.contains(&config::CrateTypeRlib) && - mtrans.kind == ModuleKind::Regular; - // If we don't have the integrated assembler, then we need to emit asm // from LLVM and use `gcc` to create the object file. let asm_to_obj = config.emit_obj && config.no_integrated_as; @@ -654,10 +644,10 @@ unsafe fn with_codegen(tm: TargetMachineRef, // just llvm bitcode. In that case write bitcode, and possibly // delete the bitcode if it wasn't requested. Don't generate the // machine code, instead copy the .o file from the .bc - let write_bc = config.emit_bc || (config.obj_is_bitcode && !asm2wasm); - let rm_bc = !config.emit_bc && config.obj_is_bitcode && !asm2wasm; - let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm && !asm_to_obj; - let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode && !asm2wasm; + let write_bc = config.emit_bc || config.obj_is_bitcode; + let rm_bc = !config.emit_bc && config.obj_is_bitcode; + let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj; + let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); @@ -736,13 +726,13 @@ extern "C" fn demangle_callback(input_ptr: *const c_char, timeline.record("ir"); } - if config.emit_asm || (asm2wasm && config.emit_obj) || asm_to_obj { + if config.emit_asm || asm_to_obj { let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers // various errors like invalid IR or broken binaries, so we might have to clone the // module to produce the asm output - let llmod = if config.emit_obj && !asm2wasm { + let llmod = if config.emit_obj { llvm::LLVMCloneModule(llmod) } else { llmod @@ -751,24 +741,13 @@ extern "C" fn demangle_callback(input_ptr: *const c_char, write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) })?; - if config.emit_obj && !asm2wasm { + if config.emit_obj { llvm::LLVMDisposeModule(llmod); } timeline.record("asm"); } - if asm2wasm && config.emit_obj { - let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); - let suffix = ".wasm.map"; // FIXME use target suffix - let map = cgcx.output_filenames.path(OutputType::Exe) - .with_extension(&suffix[1..]); - binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map); - timeline.record("binaryen"); - - if !config.emit_asm { - drop(fs::remove_file(&assembly)); - } - } else if write_obj { + if write_obj { with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) @@ -808,49 +787,6 @@ extern "C" fn demangle_callback(input_ptr: *const c_char, &cgcx.output_filenames)) } -/// Translates the LLVM-generated `assembly` on the filesystem into a wasm -/// module using binaryen, placing the output at `object`. -/// -/// In this case the "object" is actually a full and complete wasm module. We -/// won't actually be doing anything else to the output for now. This is all -/// pretty janky and will get removed as soon as a linker for wasm exists. -fn binaryen_assemble(cgcx: &CodegenContext, - handler: &Handler, - assembly: &Path, - object: &Path, - map: &Path) { - use rustc_binaryen::{Module, ModuleOptions}; - - let input = fs::read(&assembly).and_then(|contents| { - Ok(CString::new(contents)?) - }); - let mut options = ModuleOptions::new(); - if cgcx.debuginfo != config::NoDebugInfo { - options.debuginfo(true); - let map_file_name = map.file_name().unwrap(); - options.source_map_url(map_file_name.to_str().unwrap()); - } - - options.stack(1024 * 1024); - options.import_memory(cgcx.wasm_import_memory); - let assembled = input.and_then(|input| { - Module::new(&input, &options) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) - }); - let err = assembled.and_then(|binary| { - fs::write(&object, binary.data()).and_then(|()| { - if cgcx.debuginfo != config::NoDebugInfo { - fs::write(map, binary.source_map()) - } else { - Ok(()) - } - }) - }); - if let Err(e) = err { - handler.err(&format!("failed to run binaryen assembler: {}", e)); - } -} - pub(crate) struct CompiledModules { pub modules: Vec, pub metadata_module: CompiledModule, @@ -1431,9 +1367,6 @@ fn start_executing_work(tcx: TyCtxt, each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); })); - let wasm_import_memory = - attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory"); - let assembler_cmd = if modules_config.no_integrated_as { // HACK: currently we use linker (gcc) as our assembler let (name, mut cmd, _) = get_linker(sess); @@ -1471,9 +1404,7 @@ fn start_executing_work(tcx: TyCtxt, total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), - binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen, debuginfo: tcx.sess.opts.debuginfo, - wasm_import_memory, assembler_cmd, }; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6cb9d2027c7..51ad17fe205 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -49,7 +49,6 @@ extern crate rustc_allocator; extern crate rustc_apfloat; extern crate rustc_back; -extern crate rustc_binaryen; extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_demangle; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 70ea015de4e..058df1d5169 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -414,9 +414,6 @@ pub fn new() -> Features { // Allow trait methods with arbitrary self types (active, arbitrary_self_types, "1.23.0", Some(44874)), - // #![wasm_import_memory] attribute - (active, wasm_import_memory, "1.22.0", None), - // `crate` in paths (active, crate_in_paths, "1.23.0", Some(45477)), @@ -985,11 +982,6 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { never be stable", cfg_fn!(rustc_attrs))), - ("wasm_import_memory", Whitelisted, Gated(Stability::Unstable, - "wasm_import_memory", - "wasm_import_memory attribute is currently unstable", - cfg_fn!(wasm_import_memory))), - ("rustc_args_required_const", Whitelisted, Gated(Stability::Unstable, "rustc_attrs", "never will be stable", diff --git a/src/test/run-pass/issue-15487.rs b/src/test/run-pass/issue-15487.rs index cc5db0af88b..3616ab9e6c7 100644 --- a/src/test/run-pass/issue-15487.rs +++ b/src/test/run-pass/issue-15487.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-windows +// ignore-wasm32-bare no libs to link #![feature(link_args)] diff --git a/src/test/ui/feature-gate-wasm_import_memory.rs b/src/test/ui/feature-gate-wasm_import_memory.rs deleted file mode 100644 index a010ebb3551..00000000000 --- a/src/test/ui/feature-gate-wasm_import_memory.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 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. - -#![wasm_import_memory] //~ ERROR: currently unstable - -fn main() {} - diff --git a/src/test/ui/feature-gate-wasm_import_memory.stderr b/src/test/ui/feature-gate-wasm_import_memory.stderr deleted file mode 100644 index 0ec50272467..00000000000 --- a/src/test/ui/feature-gate-wasm_import_memory.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: wasm_import_memory attribute is currently unstable - --> $DIR/feature-gate-wasm_import_memory.rs:11:1 - | -LL | #![wasm_import_memory] //~ ERROR: currently unstable - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(wasm_import_memory)] to the crate attributes to enable - -error: aborting due to previous error - -If you want more information on this error, try using "rustc --explain E0658" diff --git a/src/tools/lld b/src/tools/lld new file mode 160000 index 00000000000..b87873eaceb --- /dev/null +++ b/src/tools/lld @@ -0,0 +1 @@ +Subproject commit b87873eaceb75cf9342d5273f01ba2c020f61ca8 diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 1def3048ce0..5134c869912 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -50,7 +50,6 @@ macro_rules! tidy_error { fn filter_dirs(path: &Path) -> bool { let skip = [ - "src/binaryen", "src/dlmalloc", "src/jemalloc", "src/llvm", @@ -68,6 +67,7 @@ fn filter_dirs(path: &Path) -> bool { "src/tools/rust-installer", "src/tools/rustfmt", "src/tools/miri", + "src/tools/lld", "src/librustc/mir/interpret", "src/librustc_mir/interpret", "src/target",