diff --git a/.gitmodules b/.gitmodules index ffa7b321ba6..65aafeea17b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -51,3 +51,6 @@ [submodule "src/doc/rust-by-example"] path = src/doc/rust-by-example url = https://github.com/rust-lang/rust-by-example +[submodule "src/llvm-emscripten"] + path = src/llvm-emscripten + url = https://github.com/rust-lang/llvm diff --git a/.travis.yml b/.travis.yml index 6e242b74894..1007aad925d 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" + RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended --enable-profiler --enable-emscripten" 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" + 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" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 diff --git a/appveyor.yml b/appveyor.yml index 1a186c080ce..7f1c538a32e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -63,6 +63,7 @@ environment: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler + --enable-emscripten SCRIPT: python x.py dist DEPLOY: 1 - RUST_CONFIGURE_ARGS: > @@ -70,10 +71,11 @@ environment: --target=i586-pc-windows-msvc --enable-extended --enable-profiler + --enable-emscripten SCRIPT: python x.py dist DEPLOY: 1 - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-emscripten 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 @@ -81,7 +83,7 @@ environment: DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-emscripten 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 18c1f160c03..1d60d8c9494 100644 --- a/config.toml.example +++ b/config.toml.example @@ -305,6 +305,13 @@ # result (broken, compiling, testing) into this JSON file. #save-toolstates = "/path/to/toolstates.json" +# This is an array of the codegen backends that will be compiled for the rustc +# that's being compiled. The default is to only build the LLVM codegen backend, +# but you can also optionally enable the "emscripten" backend for asm.js or +# make this an empty array (but that probably won't get too far in the +# bootstrap) +#codegen-backends = ["llvm"] + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index ecf9c0a7590..603a97ddfd4 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -640,14 +640,23 @@ class RustBuild(object): os.path.join(self.rust_root, ".gitmodules"), "--get-regexp", "path"] ).decode(default_encoding).splitlines()] - submodules = [module for module in submodules - if not ((module.endswith("llvm") and - self.get_toml('llvm-config')) or - (module.endswith("jemalloc") and - (self.get_toml('use-jemalloc') == "false" or - self.get_toml('jemalloc'))))] + filtered_submodules = [] + for module in submodules: + if module.endswith("llvm"): + if self.get_toml('llvm-config'): + continue + if module.endswith("llvm-emscripten"): + backends = self.get_toml('codegen-backends') + if backends is None or not 'emscripten' in backends: + continue + if module.endswith("jemalloc"): + if self.get_toml('use-jemalloc') == 'false': + continue + if self.get_toml('jemalloc'): + continue + filtered_submodules.append(module) run(["git", "submodule", "update", - "--init", "--recursive"] + submodules, + "--init", "--recursive"] + filtered_submodules, cwd=self.rust_root, verbose=self.verbose) run(["git", "submodule", "-q", "foreach", "git", "reset", "-q", "--hard"], diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index cb236cd7e73..fa289bbd76a 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -581,24 +581,30 @@ impl Step for RustcLink { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct RustcTrans { +pub struct CodegenBackend { pub compiler: Compiler, pub target: Interned, + pub backend: Interned, } -impl Step for RustcTrans { +impl Step for CodegenBackend { type Output = (); const ONLY_HOSTS: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc_trans").krate("rustc_trans") + run.path("src/librustc_trans") } fn make_run(run: RunConfig) { - run.builder.ensure(RustcTrans { + let backend = run.builder.config.rust_codegen_backends.get(0); + let backend = backend.cloned().unwrap_or_else(|| { + INTERNER.intern_str("llvm") + }); + run.builder.ensure(CodegenBackend { compiler: run.builder.compiler(run.builder.top_stage, run.host), target: run.target, + backend }); } @@ -609,58 +615,92 @@ impl Step for RustcTrans { builder.ensure(Rustc { compiler, target }); - // Build LLVM for our target. This will implicitly build the host LLVM - // if necessary. - builder.ensure(native::Llvm { target }); - if build.force_use_stage1(compiler, target) { - builder.ensure(RustcTrans { + builder.ensure(CodegenBackend { compiler: builder.compiler(1, build.build), target, + backend: self.backend, }); return; } - let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); - println!("Building stage{} trans artifacts ({} -> {})", - compiler.stage, &compiler.host, target); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); + let mut features = build.rustc_features().to_string(); cargo.arg("--manifest-path") - .arg(build.src.join("src/librustc_trans/Cargo.toml")) - .arg("--features").arg(build.rustc_features()); + .arg(build.src.join("src/librustc_trans/Cargo.toml")); rustc_cargo_env(build, &mut cargo); - // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_trans. - if build.is_rust_llvm(target) { - cargo.env("LLVM_RUSTLLVM", "1"); - } - cargo.env("LLVM_CONFIG", build.llvm_config(target)); - let target_config = build.config.target_config.get(&target); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } - // Building with a static libstdc++ is only supported on linux right now, - // not for MSVC or macOS - if build.config.llvm_static_stdcpp && - !target.contains("freebsd") && - !target.contains("windows") && - !target.contains("apple") { - let file = compiler_file(build, - build.cxx(target).unwrap(), - target, - "libstdc++.a"); - cargo.env("LLVM_STATIC_STDCPP", file); - } - if build.config.llvm_link_shared { - cargo.env("LLVM_LINK_SHARED", "1"); + match &*self.backend { + "llvm" | "emscripten" => { + // Build LLVM for our target. This will implicitly build the + // host LLVM if necessary. + let llvm_config = builder.ensure(native::Llvm { + target, + emscripten: self.backend == "emscripten", + }); + + if self.backend == "emscripten" { + features.push_str(" emscripten"); + } + + let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + println!("Building stage{} codegen artifacts ({} -> {}, {})", + compiler.stage, &compiler.host, target, self.backend); + + // Pass down configuration from the LLVM build into the build of + // librustc_llvm and librustc_trans. + if build.is_rust_llvm(target) { + cargo.env("LLVM_RUSTLLVM", "1"); + } + cargo.env("LLVM_CONFIG", &llvm_config); + if self.backend != "emscripten" { + let target_config = build.config.target_config.get(&target); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); + } + } + // Building with a static libstdc++ is only supported on linux right now, + // not for MSVC or macOS + if build.config.llvm_static_stdcpp && + !target.contains("freebsd") && + !target.contains("windows") && + !target.contains("apple") { + let file = compiler_file(build, + build.cxx(target).unwrap(), + target, + "libstdc++.a"); + cargo.env("LLVM_STATIC_STDCPP", file); + } + if build.config.llvm_link_shared { + cargo.env("LLVM_LINK_SHARED", "1"); + } + } + _ => panic!("unknown backend: {}", self.backend), } - run_cargo(build, - &mut cargo, - &librustc_trans_stamp(build, compiler, target), - false); + let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target) + .join(".tmp.stamp"); + let files = run_cargo(build, + cargo.arg("--features").arg(features), + &tmp_stamp, + false); + let mut files = files.into_iter() + .filter(|f| { + let filename = f.file_name().unwrap().to_str().unwrap(); + is_dylib(filename) && filename.contains("rustc_trans-") + }); + let codegen_backend = match files.next() { + Some(f) => f, + None => panic!("no dylibs built for codegen backend?"), + }; + if let Some(f) = files.next() { + panic!("codegen backend built two dylibs:\n{}\n{}", + codegen_backend.display(), + f.display()); + } + let stamp = codegen_backend_stamp(build, compiler, target, self.backend); + let codegen_backend = codegen_backend.to_str().unwrap(); + t!(t!(File::create(&stamp)).write_all(codegen_backend.as_bytes())); } } @@ -682,33 +722,29 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, // not linked into the main compiler by default but is rather dynamically // selected at runtime for inclusion. // - // Here we're looking for the output dylib of the `RustcTrans` step and + // Here we're looking for the output dylib of the `CodegenBackend` step and // we're copying that into the `codegen-backends` folder. let libdir = builder.sysroot_libdir(target_compiler, target); let dst = libdir.join("codegen-backends"); t!(fs::create_dir_all(&dst)); - let stamp = librustc_trans_stamp(build, compiler, target); - let mut copied = None; - for file in read_stamp_file(&stamp) { - let filename = match file.file_name().and_then(|s| s.to_str()) { - Some(s) => s, - None => continue, + for backend in builder.config.rust_codegen_backends.iter() { + let stamp = codegen_backend_stamp(build, compiler, target, *backend); + let mut dylib = String::new(); + t!(t!(File::open(&stamp)).read_to_string(&mut dylib)); + let file = Path::new(&dylib); + let filename = file.file_name().unwrap().to_str().unwrap(); + // change `librustc_trans-xxxxxx.so` to `librustc_trans-llvm.so` + let target_filename = { + let dash = filename.find("-").unwrap(); + let dot = filename.find(".").unwrap(); + format!("{}-{}{}", + &filename[..dash], + backend, + &filename[dot..]) }; - if !is_dylib(filename) || !filename.contains("rustc_trans-") { - continue - } - match copied { - None => copied = Some(file.clone()), - Some(ref s) => { - panic!("copied two codegen backends:\n{}\n{}", - s.display(), - file.display()); - } - } - copy(&file, &dst.join(filename)); + copy(&file, &dst.join(target_filename)); } - assert!(copied.is_some(), "failed to find a codegen backend to copy"); } /// Cargo's output path for the standard library in a given stage, compiled @@ -729,10 +765,12 @@ pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { - build.cargo_out(compiler, Mode::Librustc, target).join(".librustc_trans.stamp") +fn codegen_backend_stamp(build: &Build, + compiler: Compiler, + target: Interned, + backend: Interned) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target) + .join(format!(".librustc_trans-{}.stamp", backend)) } fn compiler_file(build: &Build, @@ -849,10 +887,13 @@ impl Step for Assemble { compiler: build_compiler, target: target_compiler.host, }); - builder.ensure(RustcTrans { - compiler: build_compiler, - target: target_compiler.host, - }); + for &backend in build.config.rust_codegen_backends.iter() { + builder.ensure(CodegenBackend { + compiler: build_compiler, + target: target_compiler.host, + backend, + }); + } } let stage = target_compiler.stage; @@ -922,7 +963,9 @@ fn stderr_isatty() -> bool { } } -pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool) { +pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool) + -> Vec +{ // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. cargo.arg("--message-format").arg("json") @@ -1066,8 +1109,8 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo let mut new_contents = Vec::new(); let mut max = None; let mut max_path = None; - for dep in deps { - let mtime = mtime(&dep); + for dep in deps.iter() { + let mtime = mtime(dep); if Some(mtime) > max { max = Some(mtime); max_path = Some(dep.clone()); @@ -1080,7 +1123,7 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo if stamp_contents == new_contents && max <= stamp_mtime { build.verbose(&format!("not updating {:?}; contents equal and {} <= {}", stamp, max, stamp_mtime)); - return + return deps } if max > stamp_mtime { build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); @@ -1088,4 +1131,5 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo build.verbose(&format!("updating {:?} as deps changed", stamp)); } t!(t!(File::create(stamp)).write_all(&new_contents)); + deps } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 72e75fddc19..dbeb27cbfb7 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -91,6 +91,7 @@ pub struct Config { pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, pub rust_dist_src: bool, + pub rust_codegen_backends: Vec>, pub build: Interned, pub hosts: Vec>, @@ -280,6 +281,7 @@ struct Rust { quiet_tests: Option, test_miri: Option, save_toolstates: Option, + codegen_backends: Option>, } /// TOML representation of how each build target is configured. @@ -318,6 +320,7 @@ impl Config { config.ignore_git = false; config.rust_dist_src = true; config.test_miri = false; + config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.on_fail = flags.on_fail; config.stage = flags.stage; @@ -465,6 +468,12 @@ impl Config { config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + if let Some(ref backends) = rust.codegen_backends { + config.rust_codegen_backends = backends.iter() + .map(|s| INTERNER.intern_str(s)) + .collect(); + } + match rust.codegen_units { Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32), Some(n) => config.rust_codegen_units = Some(n), diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 9a4b5e786e1..bc6f666d001 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -65,6 +65,7 @@ o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, m o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball") 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") # Optimization and debugging options. These may be overridden by the release # channel, etc. @@ -321,6 +322,8 @@ for key in known_args: set('build.host', value.split(',')) elif option.name == 'target': set('build.target', value.split(',')) + elif option.name == 'emscripten': + set('rust.codegen-backends', ['llvm', 'emscripten']) elif option.name == 'option-checking': # this was handled above pass diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8928bef9faa..aae0a4f056f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -480,6 +480,10 @@ impl Build { self.out.join(&*target).join("llvm") } + fn emscripten_llvm_out(&self, target: Interned) -> PathBuf { + self.out.join(&*target).join("llvm-emscripten") + } + /// Output directory for all documentation for a target fn doc_out(&self, target: Interned) -> PathBuf { self.out.join(&*target).join("doc") diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 442098a7afa..3f30756a568 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -22,7 +22,7 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; use std::io::{Read, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::Command; use build_helper::output; @@ -30,7 +30,7 @@ use cmake; use cc; use Build; -use util; +use util::{self, exe}; use build_helper::up_to_date; use builder::{Builder, RunConfig, ShouldRun, Step}; use cache::Interned; @@ -38,30 +38,42 @@ use cache::Interned; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Llvm { pub target: Interned, + pub emscripten: bool, } impl Step for Llvm { - type Output = (); + type Output = PathBuf; // path to llvm-config + const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/llvm") + run.path("src/llvm").path("src/llvm-emscripten") } fn make_run(run: RunConfig) { - run.builder.ensure(Llvm { target: run.target }) + let emscripten = run.path.map(|p| { + p.ends_with("llvm-emscripten") + }).unwrap_or(false); + run.builder.ensure(Llvm { + target: run.target, + emscripten, + }); } /// Compile LLVM for `target`. - fn run(self, builder: &Builder) { + fn run(self, builder: &Builder) -> PathBuf { let build = builder.build; let target = self.target; + let emscripten = self.emscripten; // If we're using a custom LLVM bail out here, but we can only use a // custom LLVM for the build triple. - if let Some(config) = build.config.target_config.get(&target) { - if let Some(ref s) = config.llvm_config { - return check_llvm_version(build, s); + if !self.emscripten { + if let Some(config) = build.config.target_config.get(&target) { + if let Some(ref s) = config.llvm_config { + check_llvm_version(build, s); + return s.to_path_buf() + } } } @@ -69,8 +81,17 @@ impl Step for Llvm { let mut rebuild_trigger_contents = String::new(); t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents)); - let out_dir = build.llvm_out(target); + let (out_dir, llvm_config_ret_dir) = if emscripten { + let dir = build.emscripten_llvm_out(target); + let config_dir = dir.join("bin"); + (dir, config_dir) + } else { + (build.llvm_out(target), + build.llvm_out(build.config.build).join("bin")) + }; let done_stamp = out_dir.join("llvm-finished-building"); + let build_llvm_config = llvm_config_ret_dir + .join(exe("llvm-config", &*build.config.build)); if done_stamp.exists() { let mut done_contents = String::new(); t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); @@ -78,17 +99,19 @@ impl Step for Llvm { // If LLVM was already built previously and contents of the rebuild-trigger file // didn't change from the previous build, then no action is required. if done_contents == rebuild_trigger_contents { - return + return build_llvm_config } } let _folder = build.fold_output(|| "llvm"); - println!("Building LLVM for {}", target); + let descriptor = if emscripten { "Emscripten " } else { "" }; + println!("Building {}LLVM for {}", descriptor, target); let _time = util::timeit(); t!(fs::create_dir_all(&out_dir)); // http://llvm.org/docs/CMake.html - let mut cfg = cmake::Config::new(build.src.join("src/llvm")); + 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"); } @@ -99,13 +122,22 @@ impl Step for Llvm { (true, true) => "RelWithDebInfo", }; - // NOTE: remember to also update `config.toml.example` when changing the defaults! - let llvm_targets = match build.config.llvm_targets { - Some(ref s) => s, - None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon", + // NOTE: remember to also update `config.toml.example` when changing the + // defaults! + let llvm_targets = if self.emscripten { + "JSBackend" + } else { + match build.config.llvm_targets { + Some(ref s) => s, + None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;MSP430;Sparc;NVPTX;Hexagon", + } }; - let llvm_exp_targets = &build.config.llvm_experimental_targets; + let llvm_exp_targets = if self.emscripten { + "" + } else { + &build.config.llvm_experimental_targets[..] + }; let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; @@ -155,7 +187,10 @@ impl Step for Llvm { // http://llvm.org/docs/HowToCrossCompileLLVM.html if target != build.build { - builder.ensure(Llvm { target: build.build }); + builder.ensure(Llvm { + target: build.build, + emscripten: false, + }); // FIXME: if the llvm root for the build triple is overridden then we // should use llvm-tblgen from there, also should verify that it // actually exists most of the time in normal installs of LLVM. @@ -241,6 +276,8 @@ impl Step for Llvm { cfg.build(); t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes())); + + build_llvm_config } } diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile index 07849a20d00..ff0708459bc 100644 --- a/src/ci/docker/asmjs/Dockerfile +++ b/src/ci/docker/asmjs/Dockerfile @@ -29,6 +29,6 @@ ENV EM_CONFIG=/emsdk-portable/.emscripten ENV TARGETS=asmjs-unknown-emscripten -ENV RUST_CONFIGURE_ARGS --target=$TARGETS +ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-emscripten ENV SCRIPT python2.7 ../x.py test --target $TARGETS diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index a5d776af19d..0fd6af6e10d 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -85,7 +85,8 @@ ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ --enable-extended \ --enable-sanitizers \ - --enable-profiler + --enable-profiler \ + --enable-emscripten 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/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 64c993860d9..c83f101d0ac 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -95,7 +95,8 @@ ENV RUST_CONFIGURE_ARGS \ --musl-root-armv7=/musl-armv7 \ --musl-root-aarch64=/musl-aarch64 \ --musl-root-mips=/musl-mips \ - --musl-root-mipsel=/musl-mipsel + --musl-root-mipsel=/musl-mipsel \ + --enable-emscripten ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index a954fd86a24..d368a00b55b 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -85,7 +85,8 @@ ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ --enable-extended \ --enable-sanitizers \ - --enable-profiler + --enable-profiler \ + --enable-emscripten 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/init_repo.sh b/src/ci/init_repo.sh index 14a1906ff42..8ab4276fa3b 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -48,7 +48,12 @@ travis_time_start # Update the cache (a pristine copy of the rust source master) retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \ git clone --depth 1 https://github.com/rust-lang/rust.git $cache_src_dir" -(cd $cache_src_dir && git rm src/llvm) +if [ -d $cache_src_dir/src/llvm ]; then + (cd $cache_src_dir && git rm src/llvm) +fi +if [ -d $cache_src_dir/src/llvm-emscripten ]; then + (cd $cache_src_dir && git rm src/llvm-emscripten) +fi retry sh -c "cd $cache_src_dir && \ git submodule deinit -f . && git submodule sync && git submodule update --init" @@ -64,14 +69,14 @@ travis_time_start # http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" for module in $modules; do - if [ "$module" = src/llvm ]; then - commit="$(git ls-tree HEAD src/llvm | awk '{print $3}')" - git rm src/llvm + if [ "$module" = src/llvm ] || [ "$module" = src/llvm-emscripten ]; then + commit="$(git ls-tree HEAD $module | awk '{print $3}')" + git rm $module retry sh -c "rm -f $commit.tar.gz && \ curl -sSL -O https://github.com/rust-lang/llvm/archive/$commit.tar.gz" tar -C src/ -xf "$commit.tar.gz" rm "$commit.tar.gz" - mv "src/llvm-$commit" src/llvm + mv "src/llvm-$commit" $module continue fi if [ ! -e "$cache_src_dir/$module/.git" ]; then diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index a54627279b0..5d9f0f6012b 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -31,6 +31,7 @@ pub fn target() -> Result { max_atomic_width: Some(32), post_link_args: args, target_family: Some("unix".to_string()), + codegen_backend: "emscripten".to_string(), .. Default::default() }; Ok(Target { diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 2e860f940a7..3c8a676dcc2 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -465,6 +465,9 @@ pub struct TargetOptions { /// Whether to lower 128-bit operations to compiler_builtins calls. Use if /// your backend only supports 64-bit and smaller math. pub i128_lowering: bool, + + /// The codegen backend to use for this target, typically "llvm" + pub codegen_backend: String, } impl Default for TargetOptions { @@ -534,6 +537,7 @@ impl Default for TargetOptions { singlethread: false, no_builtins: false, i128_lowering: false, + codegen_backend: "llvm".to_string(), } } } @@ -780,6 +784,7 @@ impl Target { key!(requires_lto, bool); key!(singlethread, bool); key!(no_builtins, bool); + key!(codegen_backend); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -976,6 +981,7 @@ impl ToJson for Target { target_option_val!(requires_lto); target_option_val!(singlethread); target_option_val!(no_builtins); + target_option_val!(codegen_backend); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs index 197c1f7a4da..4823541f226 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -35,6 +35,7 @@ pub fn target() -> Result { max_atomic_width: Some(32), post_link_args, target_family: Some("unix".to_string()), + codegen_backend: "emscripten".to_string(), .. Default::default() }; Ok(Target { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 029cceda532..6118ee94c84 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -218,19 +218,16 @@ pub fn get_trans(sess: &Session) -> Box { static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref(); - let backend = match trans_name.map(|s| &**s) { - None | - Some("llvm") => get_trans_default(), - Some("metadata_only") => { + let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref() + .unwrap_or(&sess.target.target.options.codegen_backend); + let backend = match &trans_name[..] { + "metadata_only" => { rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new } - Some(filename) if filename.contains(".") => { + filename if filename.contains(".") => { load_backend_from_dylib(filename.as_ref()) } - Some(trans_name) => { - sess.fatal(&format!("unknown codegen backend {}", trans_name)); - } + trans_name => get_trans_sysroot(trans_name), }; unsafe { @@ -242,7 +239,7 @@ pub fn get_trans(sess: &Session) -> Box { backend } -fn get_trans_default() -> fn() -> Box { +fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { // For now we only allow this function to be called once as it'll dlopen a // few things, which seems to work best if we only do that once. In // general this assertion never trips due to the once guard in `get_trans`, @@ -324,6 +321,7 @@ fn get_trans_default() -> fn() -> Box { let mut file: Option = None; + let expected_name = format!("rustc_trans-{}", backend_name); for entry in d.filter_map(|e| e.ok()) { let path = entry.path(); let filename = match path.file_name().and_then(|s| s.to_str()) { @@ -334,7 +332,7 @@ fn get_trans_default() -> fn() -> Box { continue } let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()]; - if !name.starts_with("rustc_trans") { + if name != expected_name { continue } if let Some(ref prev) = file { @@ -350,8 +348,9 @@ fn get_trans_default() -> fn() -> Box { match file { Some(ref s) => return load_backend_from_dylib(s), None => { - let err = format!("failed to load default codegen backend, no appropriate \ - codegen dylib found in `{}`", sysroot.display()); + let err = format!("failed to load default codegen backend for `{}`, \ + no appropriate codegen dylib found in `{}`", + backend_name, sysroot.display()); early_error(ErrorOutputType::default(), &err); } } @@ -1072,7 +1071,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); - get_trans_default()().print_version(); + get_trans_sysroot("llvm")().print_version(); } } @@ -1369,7 +1368,7 @@ pub fn handle_options(args: &[String]) -> Option { } if cg_flags.contains(&"passes=list".to_string()) { - get_trans_default()().print_passes(); + get_trans_sysroot("llvm")().print_passes(); return None; } diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index 45e97127ede..0978c2ceb14 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -10,6 +10,7 @@ path = "lib.rs" [features] static-libstdcpp = [] +emscripten = [] [dependencies] bitflags = "1.0" diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 14591de31ca..500c4fdf4e8 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -39,4 +39,11 @@ tempdir = "0.3" cc = "1.0.1" [features] +# Used to communicate the feature to `rustc_back` in the same manner that the +# `rustc` driver script communicate this. jemalloc = ["rustc_back/jemalloc"] + +# This is used to convince Cargo to separately cache builds of `rustc_trans` +# when this option is enabled or not. That way we can build two, cache two +# artifacts, and have nice speedy rebuilds. +emscripten = ["rustc_llvm/emscripten"] diff --git a/src/llvm-emscripten b/src/llvm-emscripten new file mode 160000 index 00000000000..27174447533 --- /dev/null +++ b/src/llvm-emscripten @@ -0,0 +1 @@ +Subproject commit 2717444753318e461e0c3b30dacd03ffbac96903 diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index eee2902bfb6..4d89008d5ca 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -54,6 +54,7 @@ fn filter_dirs(path: &Path) -> bool { "src/dlmalloc", "src/jemalloc", "src/llvm", + "src/llvm-emscripten", "src/libbacktrace", "src/libcompiler_builtins", "src/librustc_data_structures/owning_ref",