提交 8b003551 编写于 作者: B bors 提交者: GitHub

Auto merge of #36339 - brson:emscripten-new, r=alexcrichton

Working asmjs and wasm targets

This patch set results in a working standard library for the asmjs-unknown-emscripten and wasm32-unknown-emscripten targets. It is based on the work of @badboy and @rschulman.

It does a few things:

- Updates LLVM with the emscripten [fastcomp](https://github.com/rust-lang/llvm/pull/50) patches, which include the pnacl IR legalizer and the asm.js backend. This patch is thought not to have any significant effect on existing targets.
- Teaches rustbuild to correctly link C code with emscripten
- Updates gcc-rs to work correctly with emscripten
- Teaches rustbuild to run crate tests for emscripten with node
- Modifies Thread::new to return an error on emscripten, to facilitate debugging a common failure mode
- Modifies libtest to run in single-threaded mode for emscripten
- Ignores a host of tests that don't work yet, mostly dealing with threads and I/O
- Updates libc with wasm32 definitions (presently the same as asmjs)
- Adds a wasm32-unknown-emscripten target that feeds the output of LLVM's asmjs backend through emcc to generate wasm

Notes and caveats:

- This is only known to work with `--enable-rustbuild`.
- The wasm32 target can't be tested correctly yet because of issues in compiletest and limitations in node https://github.com/kripken/emscripten/issues/4542, but hello.rs does seem to work when run on node via the binaryen interpreter
- This requires an up to date installation of the emscripten sdk from its incoming branch
- Unwinding is very broken
- When enabling the emscripten targets jemalloc is disabled for all targets, which results in test failures for the host

Next steps are to fix the jemalloc issue, start building the two emscripten targets on the auto builders, then start producing nightlies.

https://github.com/rust-lang/rust/issues/36317 tracks work on this.

Fixes https://github.com/rust-lang/rust/issues/36515
Fixes https://github.com/rust-lang/rust/issues/36515
Fixes https://github.com/rust-lang/rust/issues/36356
# wasm32-unknown-emscripten configuration
CC_wasm32-unknown-emscripten=emcc
CXX_wasm32-unknown-emscripten=em++
CPP_wasm32-unknown-emscripten=$(CPP)
AR_wasm32-unknown-emscripten=emar
CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so
CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a
CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS)
CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten := -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 -s BINARYEN=1
CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_wasm32-unknown-emscripten :=
CFG_INSTALL_NAME_wasm32-unknown-emscripten =
CFG_EXE_SUFFIX_wasm32-unknown-emscripten =
CFG_WINDOWSY_wasm32-unknown-emscripten :=
CFG_UNIXY_wasm32-unknown-emscripten := 1
CFG_LDPATH_wasm32-unknown-emscripten :=
CFG_RUN_wasm32-unknown-emscripten=$(2)
CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2))
CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten
CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1
...@@ -300,7 +300,7 @@ endif ...@@ -300,7 +300,7 @@ endif
# LLVM macros # LLVM macros
###################################################################### ######################################################################
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \ LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
interpreter instrumentation interpreter instrumentation
......
...@@ -5,16 +5,16 @@ dependencies = [ ...@@ -5,16 +5,16 @@ dependencies = [
"build_helper 0.1.0", "build_helper 0.1.0",
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)", "gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
...@@ -34,7 +34,7 @@ name = "cmake" ...@@ -34,7 +34,7 @@ name = "cmake"
version = "0.1.17" version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
...@@ -42,17 +42,17 @@ name = "filetime" ...@@ -42,17 +42,17 @@ name = "filetime"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "gcc" name = "gcc"
version = "0.3.31" version = "0.3.35"
source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7" source = "git+https://github.com/alexcrichton/gcc-rs#8ff5360b6e0dc4f3c9d3f71036f1ff403c68469d"
[[package]] [[package]]
name = "gcc" name = "gcc"
version = "0.3.31" version = "0.3.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
...@@ -65,13 +65,13 @@ name = "kernel32-sys" ...@@ -65,13 +65,13 @@ name = "kernel32-sys"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.10" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
...@@ -84,15 +84,15 @@ name = "memchr" ...@@ -84,15 +84,15 @@ name = "memchr"
version = "0.1.11" version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "0.2.11" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
...@@ -123,7 +123,7 @@ version = "2.0.0" ...@@ -123,7 +123,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
...@@ -136,7 +136,7 @@ dependencies = [ ...@@ -136,7 +136,7 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.1.28" version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
...@@ -149,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" ...@@ -149,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.2.6" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
...@@ -161,20 +161,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" ...@@ -161,20 +161,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" "checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978" "checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>" "checksum gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07" "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0" "checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db" "checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2" "checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199" "checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" "checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6" "checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
...@@ -108,6 +108,10 @@ pub fn compiletest(build: &Build, ...@@ -108,6 +108,10 @@ pub fn compiletest(build: &Build,
cmd.arg("--host").arg(compiler.host); cmd.arg("--host").arg(compiler.host);
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build)); cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
if let Some(nodejs) = build.config.nodejs.as_ref() {
cmd.arg("--nodejs").arg(nodejs);
}
let mut flags = vec!["-Crpath".to_string()]; let mut flags = vec!["-Crpath".to_string()];
if build.config.rust_optimize_tests { if build.config.rust_optimize_tests {
flags.push("-O".to_string()); flags.push("-O".to_string());
...@@ -323,6 +327,9 @@ pub fn krate(build: &Build, ...@@ -323,6 +327,9 @@ pub fn krate(build: &Build,
if target.contains("android") { if target.contains("android") {
build.run(cargo.arg("--no-run")); build.run(cargo.arg("--no-run"));
krate_android(build, compiler, target, mode); krate_android(build, compiler, target, mode);
} else if target.contains("emscripten") {
build.run(cargo.arg("--no-run"));
krate_emscripten(build, compiler, target, mode);
} else { } else {
cargo.args(&build.flags.args); cargo.args(&build.flags.args);
build.run(&mut cargo); build.run(&mut cargo);
...@@ -371,6 +378,35 @@ fn krate_android(build: &Build, ...@@ -371,6 +378,35 @@ fn krate_android(build: &Build,
} }
} }
fn krate_emscripten(build: &Build,
compiler: &Compiler,
target: &str,
mode: Mode) {
let mut tests = Vec::new();
let out_dir = build.cargo_out(compiler, mode, target);
find_tests(&out_dir, target, &mut tests);
find_tests(&out_dir.join("deps"), target, &mut tests);
for test in tests {
let test_file_name = test.to_string_lossy().into_owned();
println!("running {}", test_file_name);
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
let status = Command::new(nodejs)
.arg(&test_file_name)
.stderr(::std::process::Stdio::inherit())
.status();
match status {
Ok(status) => {
if !status.success() {
panic!("some tests failed");
}
}
Err(e) => panic!(format!("failed to execute command: {}", e)),
};
}
}
fn find_tests(dir: &Path, fn find_tests(dir: &Path,
target: &str, target: &str,
dst: &mut Vec<PathBuf>) { dst: &mut Vec<PathBuf>) {
...@@ -381,7 +417,8 @@ fn find_tests(dir: &Path, ...@@ -381,7 +417,8 @@ fn find_tests(dir: &Path,
} }
let filename = e.file_name().into_string().unwrap(); let filename = e.file_name().into_string().unwrap();
if (target.contains("windows") && filename.ends_with(".exe")) || if (target.contains("windows") && filename.ends_with(".exe")) ||
(!target.contains("windows") && !filename.contains(".")) { (!target.contains("windows") && !filename.contains(".")) ||
(target.contains("emscripten") && filename.contains(".js")){
dst.push(e.path()); dst.push(e.path());
} }
} }
......
...@@ -975,7 +975,8 @@ fn rustc_flags(&self, target: &str) -> Vec<String> { ...@@ -975,7 +975,8 @@ fn rustc_flags(&self, target: &str) -> Vec<String> {
// than an entry here. // than an entry here.
let mut base = Vec::new(); let mut base = Vec::new();
if target != self.config.build && !target.contains("msvc") { if target != self.config.build && !target.contains("msvc") &&
!target.contains("emscripten") {
base.push(format!("-Clinker={}", self.cc(target).display())); base.push(format!("-Clinker={}", self.cc(target).display()));
} }
return base return base
......
...@@ -65,7 +65,7 @@ pub fn llvm(build: &Build, target: &str) { ...@@ -65,7 +65,7 @@ pub fn llvm(build: &Build, target: &str) {
.out_dir(&dst) .out_dir(&dst)
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"}) .profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
.define("LLVM_ENABLE_ASSERTIONS", assertions) .define("LLVM_ENABLE_ASSERTIONS", assertions)
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ") .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
.define("LLVM_INCLUDE_EXAMPLES", "OFF") .define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF")
......
...@@ -95,6 +95,13 @@ pub fn check(build: &mut Build) { ...@@ -95,6 +95,13 @@ pub fn check(build: &mut Build) {
// We're gonna build some custom C code here and there, host triples // We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler. // also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() { for target in build.config.target.iter() {
// On emscripten we don't actually need the C compiler to just
// build the target artifacts, only for testing. For the sake
// of easier bot configuration, just skip detection.
if target.contains("emscripten") {
continue;
}
need_cmd(build.cc(target).as_ref()); need_cmd(build.cc(target).as_ref());
if let Some(ar) = build.ar(target) { if let Some(ar) = build.ar(target) {
need_cmd(ar.as_ref()); need_cmd(ar.as_ref());
...@@ -104,6 +111,14 @@ pub fn check(build: &mut Build) { ...@@ -104,6 +111,14 @@ pub fn check(build: &mut Build) {
need_cmd(build.cxx(host).as_ref()); need_cmd(build.cxx(host).as_ref());
} }
// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
for host in build.config.host.iter() {
if host.contains("msvc") {
build.config.use_jemalloc = false;
}
}
// Externally configured LLVM requires FileCheck to exist // Externally configured LLVM requires FileCheck to exist
let filecheck = build.llvm_filecheck(&build.config.build); let filecheck = build.llvm_filecheck(&build.config.build);
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
...@@ -111,15 +126,6 @@ pub fn check(build: &mut Build) { ...@@ -111,15 +126,6 @@ pub fn check(build: &mut Build) {
} }
for target in build.config.target.iter() { for target in build.config.target.iter() {
// Either can't build or don't want to run jemalloc on these targets
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
target.contains("msvc") ||
target.contains("emscripten") {
build.config.use_jemalloc = false;
}
// Can't compile for iOS unless we're on OSX // Can't compile for iOS unless we're on OSX
if target.contains("apple-ios") && if target.contains("apple-ios") &&
!build.config.build.contains("apple-darwin") { !build.config.build.contains("apple-darwin") {
......
...@@ -418,7 +418,6 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> { ...@@ -418,7 +418,6 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
self.check_crate_std(compiler), self.check_crate_std(compiler),
self.check_crate_test(compiler), self.check_crate_test(compiler),
self.check_debuginfo(compiler), self.check_debuginfo(compiler),
self.dist(stage),
]; ];
// If we're testing the build triple, then we know we can // If we're testing the build triple, then we know we can
...@@ -463,6 +462,9 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> { ...@@ -463,6 +462,9 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
// misc // misc
self.check_linkcheck(stage), self.check_linkcheck(stage),
self.check_tidy(stage), self.check_tidy(stage),
// can we make the distributables?
self.dist(stage),
]); ]);
} }
return base return base
......
...@@ -1000,6 +1000,7 @@ fn drop(&mut self) { ...@@ -1000,6 +1000,7 @@ fn drop(&mut self) {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn manually_share_arc() { fn manually_share_arc() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = Arc::new(v); let arc_v = Arc::new(v);
......
...@@ -27,6 +27,24 @@ fn main() { ...@@ -27,6 +27,24 @@ fn main() {
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let src_dir = env::current_dir().unwrap(); let src_dir = env::current_dir().unwrap();
// FIXME: This is a hack to support building targets that don't
// support jemalloc alongside hosts that do. The jemalloc build is
// controlled by a feature of the std crate, and if that feature
// changes between targets, it invalidates the fingerprint of
// std's build script (this is a cargo bug); so we must ensure
// that the feature set used by std is the same across all
// targets, which means we have to build the alloc_jemalloc crate
// for targets like emscripten, even if we don't use it.
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
target.contains("msvc") ||
target.contains("emscripten")
{
println!("cargo:rustc-cfg=dummy_jemalloc");
return;
}
if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") { if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
let jemalloc = PathBuf::from(jemalloc); let jemalloc = PathBuf::from(jemalloc);
println!("cargo:rustc-link-search=native={}", println!("cargo:rustc-link-search=native={}",
......
...@@ -23,124 +23,170 @@ ...@@ -23,124 +23,170 @@
extern crate libc; extern crate libc;
use libc::{c_int, c_void, size_t}; pub use imp::*;
// Linkage directives to pull in jemalloc and its dependencies. // See comments in build.rs for why we sometimes build a crate that does nothing
// #[cfg(not(dummy_jemalloc))]
// On some platforms we need to be sure to link in `pthread` which jemalloc mod imp {
// depends on, and specifically on android we need to also link to libgcc. use libc::{c_int, c_void, size_t};
// Currently jemalloc is compiled with gcc which will generate calls to
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
#[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")),
link(name = "pthread"))]
#[cfg(not(cargobuild))]
extern "C" {}
// Note that the symbols here are prefixed by default on OSX and Windows (we
// don't explicitly request it), and on Android and DragonFly we explicitly
// request it as unprefixing cause segfaults (mismatches in allocators).
extern "C" {
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_mallocx")]
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
// The minimum alignment guaranteed by the architecture. This value is used to // Linkage directives to pull in jemalloc and its dependencies.
// add fast paths for low alignment values. In practice, the alignment is a //
// constant at the call site and the branch will be optimized out. // On some platforms we need to be sure to link in `pthread` which jemalloc
#[cfg(all(any(target_arch = "arm", // depends on, and specifically on android we need to also link to libgcc.
target_arch = "mips", // Currently jemalloc is compiled with gcc which will generate calls to
target_arch = "powerpc")))] // intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
const MIN_ALIGN: usize = 8; // libcompiler-rt), so link that in to get that support.
#[cfg(all(any(target_arch = "x86", #[link(name = "jemalloc", kind = "static")]
target_arch = "x86_64", #[cfg_attr(target_os = "android", link(name = "gcc"))]
target_arch = "aarch64", #[cfg_attr(all(not(windows),
target_arch = "powerpc64", not(target_os = "android"),
target_arch = "mips64", not(target_env = "musl")),
target_arch = "s390x")))] link(name = "pthread"))]
const MIN_ALIGN: usize = 16; #[cfg(not(cargobuild))]
extern "C" {}
// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int { // Note that the symbols here are prefixed by default on OSX and Windows (we
a.trailing_zeros() as c_int // don't explicitly request it), and on Android and DragonFly we explicitly
} // request it as unprefixing cause segfaults (mismatches in allocators).
extern "C" {
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_mallocx")]
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "mips64",
target_arch = "s390x")))]
const MIN_ALIGN: usize = 16;
// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int {
a.trailing_zeros() as c_int
}
fn align_to_flags(align: usize) -> c_int {
if align <= MIN_ALIGN {
0
} else {
mallocx_align(align)
}
}
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { mallocx(size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> *mut u8 {
let flags = align_to_flags(align);
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> usize {
let flags = align_to_flags(align);
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
fn align_to_flags(align: usize) -> c_int { #[no_mangle]
if align <= MIN_ALIGN { pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { nallocx(size as size_t, flags) as usize }
}
// These symbols are used by jemalloc on android but the really old android
// we're building on doesn't have them defined, so just make sure the symbols
// are available.
#[no_mangle]
#[cfg(target_os = "android")]
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
_postfork_parent: *mut u8,
_postfork_child: *mut u8)
-> i32 {
0 0
} else {
mallocx_align(align)
} }
} }
#[no_mangle] #[cfg(dummy_jemalloc)]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { mod imp {
let flags = align_to_flags(align); fn bogus() -> ! {
unsafe { mallocx(size as size_t, flags) as *mut u8 } panic!("jemalloc is not implemented for this platform");
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8, pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
_old_size: usize, bogus()
size: usize, }
align: usize)
-> *mut u8 {
let flags = align_to_flags(align);
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle] #[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
_old_size: usize, _old_size: usize,
size: usize, _size: usize,
align: usize) _align: usize)
-> usize { -> *mut u8 {
let flags = align_to_flags(align); bogus()
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize } }
}
#[no_mangle] #[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
let flags = align_to_flags(align); _old_size: usize,
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) } _size: usize,
} _align: usize)
-> usize {
bogus()
}
#[no_mangle] #[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize { pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
let flags = align_to_flags(align); bogus()
unsafe { nallocx(size as size_t, flags) as usize } }
}
// These symbols are used by jemalloc on android but the really old android #[no_mangle]
// we're building on doesn't have them defined, so just make sure the symbols pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
// are available. bogus()
#[no_mangle] }
#[cfg(target_os = "android")]
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
_postfork_parent: *mut u8,
_postfork_child: *mut u8)
-> i32 {
0
} }
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
target_arch = "mips", target_arch = "mips",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "powerpc64", target_arch = "powerpc64",
target_arch = "asmjs")))] target_arch = "asmjs",
target_arch = "wasm32")))]
const MIN_ALIGN: usize = 8; const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64", #[cfg(all(any(target_arch = "x86_64",
target_arch = "aarch64", target_arch = "aarch64",
......
...@@ -1294,6 +1294,7 @@ fn test_insert_prev() { ...@@ -1294,6 +1294,7 @@ fn test_insert_prev() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_send() { fn test_send() {
let n = list_from(&[1, 2, 3]); let n = list_from(&[1, 2, 3]);
thread::spawn(move || { thread::spawn(move || {
......
...@@ -1116,6 +1116,7 @@ fn test_box_slice_clone() { ...@@ -1116,6 +1116,7 @@ fn test_box_slice_clone() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_box_slice_clone_panics() { fn test_box_slice_clone_panics() {
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
......
...@@ -73,6 +73,12 @@ fn extend(&mut self, sources: &[&'static str]) { ...@@ -73,6 +73,12 @@ fn extend(&mut self, sources: &[&'static str]) {
fn main() { fn main() {
let target = env::var("TARGET").expect("TARGET was not set"); let target = env::var("TARGET").expect("TARGET was not set");
// Emscripten's runtime includes all the builtins
if target.contains("emscripten") {
return;
}
let cfg = &mut gcc::Config::new(); let cfg = &mut gcc::Config::new();
if target.contains("msvc") { if target.contains("msvc") {
......
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// FIXME https://github.com/kripken/emscripten/issues/4563
// NB we have to actually not compile this test to avoid
// an undefined symbol error
#![cfg(not(target_os = "emscripten"))]
use core::num::flt2dec::estimator::*; use core::num::flt2dec::estimator::*;
#[test] #[test]
......
...@@ -5,6 +5,7 @@ dependencies = [ ...@@ -5,6 +5,7 @@ dependencies = [
"alloc 0.0.0", "alloc 0.0.0",
"core 0.0.0", "core 0.0.0",
"libc 0.0.0", "libc 0.0.0",
"unwind 0.0.0",
] ]
[[package]] [[package]]
...@@ -25,3 +26,11 @@ dependencies = [ ...@@ -25,3 +26,11 @@ dependencies = [
"core 0.0.0", "core 0.0.0",
] ]
[[package]]
name = "unwind"
version = "0.0.0"
dependencies = [
"core 0.0.0",
"libc 0.0.0",
]
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Unwinding for emscripten
//!
//! Whereas Rust's usual unwinding implementation for Unix platforms
//! calls into the libunwind APIs directly, on emscripten we instead
//! call into the C++ unwinding APIs. This is just an expedience since
//! emscripten's runtime always implements those APIs and does not
//! implement libunwind.
#![allow(private_no_mangle_fns)]
use core::any::Any;
use core::ptr;
use alloc::boxed::Box;
use libc::{self, c_int};
use unwind as uw;
use core::mem;
pub fn payload() -> *mut u8 {
ptr::null_mut()
}
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
assert!(!ptr.is_null());
let ex = ptr::read(ptr as *mut _);
__cxa_free_exception(ptr as *mut _);
ex
}
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
let sz = mem::size_of_val(&data);
let exception = __cxa_allocate_exception(sz);
if exception == ptr::null_mut() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
}
let exception = exception as *mut Box<Any + Send>;
ptr::write(exception, data);
__cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut());
unreachable!()
}
#[lang = "eh_personality"]
#[no_mangle]
unsafe extern "C" fn rust_eh_personality(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code {
__gxx_personality_v0(version, actions,
exception_class,
exception_object,
context)
}
extern {
fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
fn __cxa_free_exception(thrown_exception: *mut libc::c_void);
fn __cxa_throw(thrown_exception: *mut libc::c_void,
tinfo: *mut libc::c_void,
dest: *mut libc::c_void);
fn __gxx_personality_v0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}
...@@ -68,10 +68,16 @@ ...@@ -68,10 +68,16 @@
mod imp; mod imp;
// i686-pc-windows-gnu and all others // i686-pc-windows-gnu and all others
#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))] #[cfg(any(all(unix, not(target_os = "emscripten")),
all(windows, target_arch = "x86", target_env = "gnu")))]
#[path = "gcc.rs"] #[path = "gcc.rs"]
mod imp; mod imp;
// emscripten
#[cfg(target_os = "emscripten")]
#[path = "emcc.rs"]
mod imp;
mod dwarf; mod dwarf;
mod windows; mod windows;
......
...@@ -22,6 +22,7 @@ pub fn target() -> Result<Target, String> { ...@@ -22,6 +22,7 @@ pub fn target() -> Result<Target, String> {
allow_asm: false, allow_asm: false,
obj_is_bitcode: true, obj_is_bitcode: true,
max_atomic_width: 32, max_atomic_width: 32,
post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
.. Default::default() .. Default::default()
}; };
Ok(Target { Ok(Target {
......
...@@ -190,7 +190,8 @@ fn $module() { ...@@ -190,7 +190,8 @@ fn $module() {
("i586-pc-windows-msvc", i586_pc_windows_msvc), ("i586-pc-windows-msvc", i586_pc_windows_msvc),
("le32-unknown-nacl", le32_unknown_nacl), ("le32-unknown-nacl", le32_unknown_nacl),
("asmjs-unknown-emscripten", asmjs_unknown_emscripten) ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
("wasm32-unknown-emscripten", wasm32_unknown_emscripten)
} }
/// Everything `rustc` knows about how to compile for a specific target. /// Everything `rustc` knows about how to compile for a specific target.
......
// Copyright 2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::{Target, TargetOptions};
pub fn target() -> Result<Target, String> {
let opts = TargetOptions {
linker: "emcc".to_string(),
ar: "emar".to_string(),
dynamic_linking: false,
executables: true,
// Today emcc emits two files - a .js file to bootstrap and
// possibly interpret the wasm, and a .wasm file
exe_suffix: ".js".to_string(),
linker_is_gnu: true,
allow_asm: false,
obj_is_bitcode: true,
max_atomic_width: 32,
post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
"-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
.. Default::default()
};
Ok(Target {
llvm_target: "asmjs-unknown-emscripten".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_os: "emscripten".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
arch: "wasm32".to_string(),
options: opts,
})
}
...@@ -1075,7 +1075,7 @@ fn flush(&mut self) -> io::Result<()> { ...@@ -1075,7 +1075,7 @@ fn flush(&mut self) -> io::Result<()> {
} }
let thread = cfg.spawn(move || { let thread = cfg.spawn(move || {
io::set_panic(box err); io::set_panic(Some(box err));
f() f()
}); });
...@@ -1121,7 +1121,7 @@ fn exit_on_err() -> ! { ...@@ -1121,7 +1121,7 @@ fn exit_on_err() -> ! {
// Panic so the process returns a failure code, but don't pollute the // Panic so the process returns a failure code, but don't pollute the
// output with some unnecessary panic messages, we've already // output with some unnecessary panic messages, we've already
// printed everything that we needed to. // printed everything that we needed to.
io::set_panic(box io::sink()); io::set_panic(Some(box io::sink()));
panic!(); panic!();
} }
......
...@@ -66,7 +66,8 @@ fn main() { ...@@ -66,7 +66,8 @@ fn main() {
let host = env::var("HOST").expect("HOST was not set"); let host = env::var("HOST").expect("HOST was not set");
let is_crossed = target != host; let is_crossed = target != host;
let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz"]; let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz",
"jsbackend"];
// FIXME: surely we don't need all these components, right? Stuff like mcjit // FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses. // or interpreter the compiler itself never uses.
......
...@@ -434,6 +434,10 @@ fn init() { } ...@@ -434,6 +434,10 @@ fn init() { }
LLVMInitializeSystemZTargetMC, LLVMInitializeSystemZTargetMC,
LLVMInitializeSystemZAsmPrinter, LLVMInitializeSystemZAsmPrinter,
LLVMInitializeSystemZAsmParser); LLVMInitializeSystemZAsmParser);
init_target!(llvm_component = "jsbackend",
LLVMInitializeJSBackendTargetInfo,
LLVMInitializeJSBackendTarget,
LLVMInitializeJSBackendTargetMC);
} }
pub fn last_error() -> Option<String> { pub fn last_error() -> Option<String> {
......
...@@ -519,6 +519,7 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self, ...@@ -519,6 +519,7 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self,
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self), "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self),
"s390x" => cabi_s390x::compute_abi_info(ccx, self), "s390x" => cabi_s390x::compute_abi_info(ccx, self),
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
"wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
} }
......
...@@ -228,7 +228,7 @@ fn drop(&mut self) { ...@@ -228,7 +228,7 @@ fn drop(&mut self) {
let codemap = Rc::new(CodeMap::new()); let codemap = Rc::new(CodeMap::new());
let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
Some(codemap.clone())); Some(codemap.clone()));
let old = io::set_panic(box Sink(data.clone())); let old = io::set_panic(Some(box Sink(data.clone())));
let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
// Compile the code // Compile the code
......
...@@ -892,7 +892,18 @@ mod os { ...@@ -892,7 +892,18 @@ mod os {
pub const EXE_EXTENSION: &'static str = "pexe"; pub const EXE_EXTENSION: &'static str = "pexe";
} }
#[cfg(target_os = "emscripten")] #[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "emscripten";
pub const DLL_PREFIX: &'static str = "lib";
pub const DLL_SUFFIX: &'static str = ".so";
pub const DLL_EXTENSION: &'static str = "so";
pub const EXE_SUFFIX: &'static str = ".js";
pub const EXE_EXTENSION: &'static str = "js";
}
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
mod os { mod os {
pub const FAMILY: &'static str = "unix"; pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "emscripten"; pub const OS: &'static str = "emscripten";
...@@ -969,6 +980,11 @@ mod arch { ...@@ -969,6 +980,11 @@ mod arch {
pub const ARCH: &'static str = "asmjs"; pub const ARCH: &'static str = "asmjs";
} }
#[cfg(target_arch = "wasm32")]
mod arch {
pub const ARCH: &'static str = "wasm32";
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
...@@ -1017,6 +1033,7 @@ fn test_set_var_overwrite() { ...@@ -1017,6 +1033,7 @@ fn test_set_var_overwrite() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_var_big() { fn test_var_big() {
let mut s = "".to_string(); let mut s = "".to_string();
let mut i = 0; let mut i = 0;
...@@ -1030,6 +1047,7 @@ fn test_var_big() { ...@@ -1030,6 +1047,7 @@ fn test_var_big() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_self_exe_path() { fn test_self_exe_path() {
let path = current_exe(); let path = current_exe();
assert!(path.is_ok()); assert!(path.is_ok());
...@@ -1040,6 +1058,7 @@ fn test_self_exe_path() { ...@@ -1040,6 +1058,7 @@ fn test_self_exe_path() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_env_set_get_huge() { fn test_env_set_get_huge() {
let n = make_rand_name(); let n = make_rand_name();
let s = repeat("x").take(10000).collect::<String>(); let s = repeat("x").take(10000).collect::<String>();
......
...@@ -1686,7 +1686,7 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder { ...@@ -1686,7 +1686,7 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use io::prelude::*; use io::prelude::*;
......
...@@ -1107,6 +1107,7 @@ fn flush(&mut self) -> io::Result<()> { ...@@ -1107,6 +1107,7 @@ fn flush(&mut self) -> io::Result<()> {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_in_write_doesnt_flush_in_drop() { fn panic_in_write_doesnt_flush_in_drop() {
static WRITES: AtomicUsize = AtomicUsize::new(0); static WRITES: AtomicUsize = AtomicUsize::new(0);
......
...@@ -1757,6 +1757,7 @@ mod tests { ...@@ -1757,6 +1757,7 @@ mod tests {
use super::repeat; use super::repeat;
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn read_until() { fn read_until() {
let mut buf = Cursor::new(&b"12"[..]); let mut buf = Cursor::new(&b"12"[..]);
let mut v = Vec::new(); let mut v = Vec::new();
...@@ -1967,6 +1968,7 @@ fn chain_zero_length_read_is_not_eof() { ...@@ -1967,6 +1968,7 @@ fn chain_zero_length_read_is_not_eof() {
} }
#[bench] #[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
fn bench_read_to_end(b: &mut test::Bencher) { fn bench_read_to_end(b: &mut test::Bencher) {
b.iter(|| { b.iter(|| {
let mut lr = repeat(1).take(10000000); let mut lr = repeat(1).take(10000000);
......
...@@ -593,11 +593,11 @@ fn flush(&mut self) -> io::Result<()> { ...@@ -593,11 +593,11 @@ fn flush(&mut self) -> io::Result<()> {
with a more general mechanism", with a more general mechanism",
issue = "0")] issue = "0")]
#[doc(hidden)] #[doc(hidden)]
pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> { pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use panicking::LOCAL_STDERR; use panicking::LOCAL_STDERR;
use mem; use mem;
LOCAL_STDERR.with(move |slot| { LOCAL_STDERR.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), Some(sink)) mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| { }).and_then(|mut s| {
let _ = s.flush(); let _ = s.flush();
Some(s) Some(s)
...@@ -617,10 +617,10 @@ pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> { ...@@ -617,10 +617,10 @@ pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
with a more general mechanism", with a more general mechanism",
issue = "0")] issue = "0")]
#[doc(hidden)] #[doc(hidden)]
pub fn set_print(sink: Box<Write + Send>) -> Option<Box<Write + Send>> { pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use mem; use mem;
LOCAL_STDOUT.with(move |slot| { LOCAL_STDOUT.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), Some(sink)) mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| { }).and_then(|mut s| {
let _ = s.flush(); let _ = s.flush();
Some(s) Some(s)
...@@ -668,6 +668,7 @@ mod tests { ...@@ -668,6 +668,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() { fn panic_doesnt_poison() {
thread::spawn(|| { thread::spawn(|| {
let _a = stdin(); let _a = stdin();
......
...@@ -519,7 +519,7 @@ fn to_socket_addrs(&self) -> io::Result<T::Iter> { ...@@ -519,7 +519,7 @@ fn to_socket_addrs(&self) -> io::Result<T::Iter> {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use net::*; use net::*;
use net::test::{tsa, sa6, sa4}; use net::test::{tsa, sa6, sa4};
......
...@@ -669,7 +669,7 @@ fn from_inner(addr: c::in6_addr) -> Ipv6Addr { ...@@ -669,7 +669,7 @@ fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
} }
// Tests for this module // Tests for this module
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use net::*; use net::*;
use net::Ipv6MulticastScope::*; use net::Ipv6MulticastScope::*;
......
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
mod tcp; mod tcp;
mod udp; mod udp;
mod parser; mod parser;
#[cfg(test)] mod test; #[cfg(all(test, not(target_os = "emscripten")))]
mod test;
/// Possible values which can be passed to the [`shutdown`] method of /// Possible values which can be passed to the [`shutdown`] method of
/// [`TcpStream`]. /// [`TcpStream`].
......
...@@ -428,7 +428,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ...@@ -428,7 +428,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use io::ErrorKind; use io::ErrorKind;
use io::prelude::*; use io::prelude::*;
......
...@@ -353,7 +353,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ...@@ -353,7 +353,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use io::ErrorKind; use io::ErrorKind;
use net::*; use net::*;
......
...@@ -34,7 +34,8 @@ ...@@ -34,7 +34,8 @@
target_arch = "le32", target_arch = "le32",
target_arch = "powerpc", target_arch = "powerpc",
target_arch = "arm", target_arch = "arm",
target_arch = "asmjs"))] target_arch = "asmjs",
target_arch = "wasm32"))]
mod arch { mod arch {
use os::raw::{c_long, c_short, c_uint}; use os::raw::{c_long, c_short, c_uint};
......
...@@ -825,7 +825,7 @@ pub fn exit(code: i32) -> ! { ...@@ -825,7 +825,7 @@ pub fn exit(code: i32) -> ! {
::sys::os::exit(code) ::sys::os::exit(code)
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use io::prelude::*; use io::prelude::*;
......
...@@ -242,6 +242,7 @@ fn test_os_rng() { ...@@ -242,6 +242,7 @@ fn test_os_rng() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_os_rng_tasks() { fn test_os_rng_tasks() {
let mut txs = vec!(); let mut txs = vec!();
......
...@@ -118,6 +118,7 @@ mod tests { ...@@ -118,6 +118,7 @@ mod tests {
use thread; use thread;
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_barrier() { fn test_barrier() {
const N: usize = 10; const N: usize = 10;
......
...@@ -270,6 +270,7 @@ fn smoke() { ...@@ -270,6 +270,7 @@ fn smoke() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_one() { fn notify_one() {
let m = Arc::new(Mutex::new(())); let m = Arc::new(Mutex::new(()));
let m2 = m.clone(); let m2 = m.clone();
...@@ -286,6 +287,7 @@ fn notify_one() { ...@@ -286,6 +287,7 @@ fn notify_one() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_all() { fn notify_all() {
const N: usize = 10; const N: usize = 10;
...@@ -322,6 +324,7 @@ fn notify_all() { ...@@ -322,6 +324,7 @@ fn notify_all() {
} }
#[test] #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_ms() { fn wait_timeout_ms() {
let m = Arc::new(Mutex::new(())); let m = Arc::new(Mutex::new(()));
let m2 = m.clone(); let m2 = m.clone();
...@@ -343,6 +346,7 @@ fn wait_timeout_ms() { ...@@ -343,6 +346,7 @@ fn wait_timeout_ms() {
#[test] #[test]
#[should_panic] #[should_panic]
#[cfg_attr(target_os = "emscripten", ignore)]
fn two_mutexes() { fn two_mutexes() {
let m = Arc::new(Mutex::new(())); let m = Arc::new(Mutex::new(()));
let m2 = m.clone(); let m2 = m.clone();
......
...@@ -1268,7 +1268,7 @@ fn cause(&self) -> Option<&error::Error> { ...@@ -1268,7 +1268,7 @@ fn cause(&self) -> Option<&error::Error> {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use env; use env;
use super::*; use super::*;
...@@ -1942,7 +1942,7 @@ fn destroy_upgraded_shared_port_when_sender_still_active() { ...@@ -1942,7 +1942,7 @@ fn destroy_upgraded_shared_port_when_sender_still_active() {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod sync_tests { mod sync_tests {
use env; use env;
use thread; use thread;
......
...@@ -146,7 +146,7 @@ fn drop(&mut self) { ...@@ -146,7 +146,7 @@ fn drop(&mut self) {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use sync::mpsc::channel; use sync::mpsc::channel;
use super::{Queue, Data, Empty, Inconsistent}; use super::{Queue, Data, Empty, Inconsistent};
......
...@@ -366,7 +366,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ...@@ -366,7 +366,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
#[allow(unused_imports)] #[allow(unused_imports)]
mod tests { mod tests {
use thread; use thread;
......
...@@ -231,7 +231,7 @@ fn drop(&mut self) { ...@@ -231,7 +231,7 @@ fn drop(&mut self) {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use sync::Arc; use sync::Arc;
use super::Queue; use super::Queue;
......
...@@ -352,7 +352,7 @@ pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Fla ...@@ -352,7 +352,7 @@ pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Fla
&guard.__lock.poison &guard.__lock.poison
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use sync::mpsc::channel; use sync::mpsc::channel;
use sync::{Arc, Mutex, Condvar}; use sync::{Arc, Mutex, Condvar};
......
...@@ -367,7 +367,7 @@ pub fn poisoned(&self) -> bool { ...@@ -367,7 +367,7 @@ pub fn poisoned(&self) -> bool {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use panic; use panic;
use sync::mpsc::channel; use sync::mpsc::channel;
......
...@@ -380,7 +380,7 @@ fn drop(&mut self) { ...@@ -380,7 +380,7 @@ fn drop(&mut self) {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
#![allow(deprecated)] // rand #![allow(deprecated)] // rand
......
...@@ -50,7 +50,7 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io:: ...@@ -50,7 +50,7 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
pub mod test { pub mod test {
use path::{Path, PathBuf}; use path::{Path, PathBuf};
use env; use env;
...@@ -165,6 +165,7 @@ fn read_to_end_uninit_good() { ...@@ -165,6 +165,7 @@ fn read_to_end_uninit_good() {
} }
#[bench] #[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
fn bench_uninitialized(b: &mut ::test::Bencher) { fn bench_uninitialized(b: &mut ::test::Bencher) {
b.iter(|| { b.iter(|| {
let mut lr = repeat(1).take(10000000); let mut lr = repeat(1).take(10000000);
......
...@@ -156,7 +156,7 @@ fn drop(&mut self) { ...@@ -156,7 +156,7 @@ fn drop(&mut self) {
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use cell::RefCell; use cell::RefCell;
......
...@@ -786,7 +786,7 @@ fn into_raw_fd(self) -> RawFd { ...@@ -786,7 +786,7 @@ fn into_raw_fd(self) -> RawFd {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod test { mod test {
use thread; use thread;
use io; use io;
......
...@@ -369,7 +369,7 @@ unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error { ...@@ -369,7 +369,7 @@ unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error {
} }
// NaCl has no signal support. // NaCl has no signal support.
if cfg!(not(target_os = "nacl")) { if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) {
// Reset signal handling so the child process starts in a // Reset signal handling so the child process starts in a
// standardized state. libstd ignores SIGPIPE, and signal-handling // standardized state. libstd ignores SIGPIPE, and signal-handling
// libraries often set a mask. Child processes inherit ignored // libraries often set a mask. Child processes inherit ignored
...@@ -589,7 +589,7 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> { ...@@ -589,7 +589,7 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use super::*; use super::*;
......
...@@ -29,6 +29,20 @@ pub struct Thread { ...@@ -29,6 +29,20 @@ pub struct Thread {
unsafe impl Send for Thread {} unsafe impl Send for Thread {}
unsafe impl Sync for Thread {} unsafe impl Sync for Thread {}
// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
#[cfg(not(target_os = "emscripten"))]
unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
stack_size: libc::size_t) -> libc::c_int {
libc::pthread_attr_setstacksize(attr, stack_size)
}
#[cfg(target_os = "emscripten")]
unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
_stack_size: libc::size_t) -> libc::c_int {
panic!()
}
impl Thread { impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
-> io::Result<Thread> { -> io::Result<Thread> {
...@@ -38,8 +52,8 @@ pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) ...@@ -38,8 +52,8 @@ pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
assert_eq!(libc::pthread_attr_init(&mut attr), 0); assert_eq!(libc::pthread_attr_init(&mut attr), 0);
let stack_size = cmp::max(stack, min_stack_size(&attr)); let stack_size = cmp::max(stack, min_stack_size(&attr));
match libc::pthread_attr_setstacksize(&mut attr, match pthread_attr_setstacksize(&mut attr,
stack_size as libc::size_t) { stack_size as libc::size_t) {
0 => {} 0 => {}
n => { n => {
assert_eq!(n, libc::EINVAL); assert_eq!(n, libc::EINVAL);
......
...@@ -524,7 +524,7 @@ pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { ...@@ -524,7 +524,7 @@ pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
} }
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use sync::mpsc::{channel, Sender}; use sync::mpsc::{channel, Sender};
use cell::{Cell, UnsafeCell}; use cell::{Cell, UnsafeCell};
......
...@@ -741,7 +741,7 @@ fn _assert_both<T: Send + Sync>() {} ...@@ -741,7 +741,7 @@ fn _assert_both<T: Send + Sync>() {}
// Tests // Tests
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#[cfg(test)] #[cfg(all(test, not(target_os = "emscripten")))]
mod tests { mod tests {
use any::Any; use any::Any;
use sync::mpsc::{channel, Sender}; use sync::mpsc::{channel, Sender};
......
...@@ -1182,26 +1182,59 @@ fn flush(&mut self) -> io::Result<()> { ...@@ -1182,26 +1182,59 @@ fn flush(&mut self) -> io::Result<()> {
} }
} }
thread::spawn(move || { // If the platform is single-threaded we're just going to run
let data = Arc::new(Mutex::new(Vec::new())); // the test synchronously, regardless of the concurrency
let data2 = data.clone(); // level.
let cfg = thread::Builder::new().name(match desc.name { let supports_threads = !cfg!(target_os = "emscripten");
DynTestName(ref name) => name.clone(),
StaticTestName(name) => name.to_owned(), // Buffer for capturing standard I/O
let data = Arc::new(Mutex::new(Vec::new()));
let data2 = data.clone();
if supports_threads {
thread::spawn(move || {
let cfg = thread::Builder::new().name(match desc.name {
DynTestName(ref name) => name.clone(),
StaticTestName(name) => name.to_owned(),
});
let result_guard = cfg.spawn(move || {
if !nocapture {
io::set_print(Some(box Sink(data2.clone())));
io::set_panic(Some(box Sink(data2)));
}
testfn()
})
.unwrap();
let test_result = calc_result(&desc, result_guard.join());
let stdout = data.lock().unwrap().to_vec();
monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
}); });
} else {
let oldio = if !nocapture {
Some((
io::set_print(Some(box Sink(data2.clone()))),
io::set_panic(Some(box Sink(data2)))
))
} else {
None
};
let result_guard = cfg.spawn(move || { use std::panic::{catch_unwind, AssertUnwindSafe};
if !nocapture {
io::set_print(box Sink(data2.clone())); let result = catch_unwind(AssertUnwindSafe(|| {
io::set_panic(box Sink(data2)); testfn()
} }));
testfn()
}) if let Some((printio, panicio)) = oldio {
.unwrap(); io::set_print(printio);
let test_result = calc_result(&desc, result_guard.join()); io::set_panic(panicio);
};
let test_result = calc_result(&desc, result);
let stdout = data.lock().unwrap().to_vec(); let stdout = data.lock().unwrap().to_vec();
monitor_ch.send((desc.clone(), test_result, stdout)).unwrap(); monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
}); }
} }
match testfn { match testfn {
...@@ -1291,7 +1324,7 @@ pub fn fmt_metrics(&self) -> String { ...@@ -1291,7 +1324,7 @@ pub fn fmt_metrics(&self) -> String {
/// ///
/// This function is a no-op, and does not even read from `dummy`. /// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(all(target_os = "nacl", target_arch = "le32"), #[cfg(not(any(all(target_os = "nacl", target_arch = "le32"),
target_arch = "asmjs")))] target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T { pub fn black_box<T>(dummy: T) -> T {
// we need to "use" the argument in some way LLVM can't // we need to "use" the argument in some way LLVM can't
// introspect. // introspect.
...@@ -1299,7 +1332,7 @@ pub fn black_box<T>(dummy: T) -> T { ...@@ -1299,7 +1332,7 @@ pub fn black_box<T>(dummy: T) -> T {
dummy dummy
} }
#[cfg(any(all(target_os = "nacl", target_arch = "le32"), #[cfg(any(all(target_os = "nacl", target_arch = "le32"),
target_arch = "asmjs"))] target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)] #[inline(never)]
pub fn black_box<T>(dummy: T) -> T { pub fn black_box<T>(dummy: T) -> T {
dummy dummy
......
...@@ -65,7 +65,7 @@ pub enum _Unwind_Reason_Code { ...@@ -65,7 +65,7 @@ pub enum _Unwind_Reason_Code {
#[cfg(target_arch = "s390x")] #[cfg(target_arch = "s390x")]
pub const unwinder_private_data_size: usize = 2; pub const unwinder_private_data_size: usize = 2;
#[cfg(target_arch = "asmjs")] #[cfg(target_os = "emscripten")]
pub const unwinder_private_data_size: usize = 20; pub const unwinder_private_data_size: usize = 20;
#[repr(C)] #[repr(C)]
......
Subproject commit 7801978ec1f3637fcda1b564048ebc732bf586af Subproject commit 3e03f7374169cd41547d75e62ac2ab8a103a913c
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the # The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime. # build bots then the contents should be changed so git updates the mtime.
2016-09-17 2016-09-25
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
// system allocator. Do this by linking in jemalloc and making sure that we get // system allocator. Do this by linking in jemalloc and making sure that we get
// an error. // an error.
// ignore-emscripten FIXME: What "other allocator" should we use for emcc?
#![feature(alloc_jemalloc)] #![feature(alloc_jemalloc)]
extern crate allocator_dylib; extern crate allocator_dylib;
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying // Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
// by linking in the system allocator here and ensuring that we get a complaint. // by linking in the system allocator here and ensuring that we get a complaint.
// ignore-emscripten FIXME: What "other allocator" is correct for emscripten?
#![feature(alloc_system)] #![feature(alloc_system)]
extern crate allocator_dylib2; extern crate allocator_dylib2;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
// error-pattern:thread '<unnamed>' panicked at 'test' // error-pattern:thread '<unnamed>' panicked at 'test'
// ignore-emscripten Needs threads
use std::thread; use std::thread;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
// error-pattern:thread 'owned name' panicked at 'test' // error-pattern:thread 'owned name' panicked at 'test'
// ignore-emscripten Needs threads.
use std::thread::Builder; use std::thread::Builder;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
// error-pattern:Ensure that the child thread runs by panicking // error-pattern:Ensure that the child thread runs by panicking
// ignore-emscripten Needs threads.
use std::thread; use std::thread;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// error-pattern:thread 'test_foo' panicked at // error-pattern:thread 'test_foo' panicked at
// compile-flags: --test // compile-flags: --test
// ignore-pretty: does not work well with `--test` // ignore-pretty: does not work well with `--test`
// ignore-emscripten
#[test] #[test]
fn test_foo() { fn test_foo() {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// error-pattern:thread 'test_foo' panicked at // error-pattern:thread 'test_foo' panicked at
// compile-flags: --test // compile-flags: --test
// ignore-pretty: does not work well with `--test` // ignore-pretty: does not work well with `--test`
// ignore-emscripten
#[test] #[test]
#[should_panic(expected = "foobar")] #[should_panic(expected = "foobar")]
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
// compile-flags: --test // compile-flags: --test
// exec-env:RUST_TEST_THREADS=foo // exec-env:RUST_TEST_THREADS=foo
// ignore-pretty: does not work well with `--test` // ignore-pretty: does not work well with `--test`
// ignore-emscripten
#[test] #[test]
fn do_nothing() {} fn do_nothing() {}
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// no-prefer-dynamic // no-prefer-dynamic
// aux-build:allocator-dummy.rs // aux-build:allocator-dummy.rs
// ignore-emscripten
#![feature(test)] #![feature(test)]
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// pretty-expanded FIXME #23616 // pretty-expanded FIXME #23616
// ignore-msvc // ignore-msvc
// ignore-emscripten
struct TwoU8s { struct TwoU8s {
one: u8, one: u8,
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// ignore-emscripten missing rust_begin_unwind
#![feature(lang_items, start, collections)] #![feature(lang_items, start, collections)]
#![no_std] #![no_std]
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// ignore-emscripten Not sure what's happening here.
use std::mem; use std::mem;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// ignore-emscripten
use std::mem; use std::mem;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
// compile-flags:-C panic=abort // compile-flags:-C panic=abort
// aux-build:exit-success-if-unwind.rs // aux-build:exit-success-if-unwind.rs
// no-prefer-dynamic // no-prefer-dynamic
// ignore-emscripten Function not implemented
extern crate exit_success_if_unwind; extern crate exit_success_if_unwind;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// compile-flags:-C panic=abort // compile-flags:-C panic=abort
// no-prefer-dynamic // no-prefer-dynamic
// ignore-emscripten Function not implemented.
use std::process::Command; use std::process::Command;
use std::env; use std::env;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// compile-flags:-C lto -C panic=abort // compile-flags:-C lto -C panic=abort
// no-prefer-dynamic // no-prefer-dynamic
// ignore-emscripten Function not implemented.
use std::process::Command; use std::process::Command;
use std::env; use std::env;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// compile-flags:-C lto -C panic=unwind // compile-flags:-C lto -C panic=unwind
// no-prefer-dynamic // no-prefer-dynamic
// ignore-emscripten Function not implemented.
use std::process::Command; use std::process::Command;
use std::env; use std::env;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// ignore-emscripten Function not implemented.
use std::env; use std::env;
use std::io; use std::io;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// ignore-emscripten linking with emcc failed
#![feature(repr_simd, platform_intrinsics, concat_idents, test)] #![feature(repr_simd, platform_intrinsics, concat_idents, test)]
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
......
...@@ -30,7 +30,7 @@ fn main() { ...@@ -30,7 +30,7 @@ fn main() {
let data = Arc::new(Mutex::new(Vec::new())); let data = Arc::new(Mutex::new(Vec::new()));
let sink = Sink(data.clone()); let sink = Sink(data.clone());
let res = thread::Builder::new().spawn(move|| -> () { let res = thread::Builder::new().spawn(move|| -> () {
io::set_panic(Box::new(sink)); io::set_panic(Some(Box::new(sink)));
panic!("Hello, world!") panic!("Hello, world!")
}).unwrap().join(); }).unwrap().join();
assert!(res.is_err()); assert!(res.is_err());
......
...@@ -183,4 +183,5 @@ pub struct Config { ...@@ -183,4 +183,5 @@ pub struct Config {
pub cflags: String, pub cflags: String,
pub llvm_components: String, pub llvm_components: String,
pub llvm_cxxflags: String, pub llvm_cxxflags: String,
pub nodejs: Option<String>,
} }
...@@ -109,6 +109,7 @@ pub fn parse_config(args: Vec<String> ) -> Config { ...@@ -109,6 +109,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
reqopt("", "cflags", "flags for the C compiler", "FLAGS"), reqopt("", "cflags", "flags for the C compiler", "FLAGS"),
reqopt("", "llvm-components", "list of LLVM components built in", "LIST"), reqopt("", "llvm-components", "list of LLVM components built in", "LIST"),
reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"), reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"),
optopt("", "nodejs", "the name of nodejs", "PATH"),
optflag("h", "help", "show this message")); optflag("h", "help", "show this message"));
let (argv0, args_) = args.split_first().unwrap(); let (argv0, args_) = args.split_first().unwrap();
...@@ -190,6 +191,7 @@ fn make_absolute(path: PathBuf) -> PathBuf { ...@@ -190,6 +191,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
cflags: matches.opt_str("cflags").unwrap(), cflags: matches.opt_str("cflags").unwrap(),
llvm_components: matches.opt_str("llvm-components").unwrap(), llvm_components: matches.opt_str("llvm-components").unwrap(),
llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(), llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
nodejs: matches.opt_str("nodejs"),
} }
} }
...@@ -431,10 +433,17 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn ...@@ -431,10 +433,17 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn
} }
}; };
// Debugging emscripten code doesn't make sense today
let mut ignore = early_props.ignore;
if (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb) &&
config.target.contains("emscripten") {
ignore = true;
}
test::TestDescAndFn { test::TestDescAndFn {
desc: test::TestDesc { desc: test::TestDesc {
name: make_test_name(config, testpaths), name: make_test_name(config, testpaths),
ignore: early_props.ignore, ignore: ignore,
should_panic: should_panic, should_panic: should_panic,
}, },
testfn: make_test_closure(config, testpaths), testfn: make_test_closure(config, testpaths),
......
...@@ -1168,7 +1168,6 @@ fn exec_compiled_test(&self) -> ProcRes { ...@@ -1168,7 +1168,6 @@ fn exec_compiled_test(&self) -> ProcRes {
"arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => { "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => {
self._arm_exec_compiled_test(env) self._arm_exec_compiled_test(env)
} }
_=> { _=> {
let aux_dir = self.aux_output_dir_name(); let aux_dir = self.aux_output_dir_name();
self.compose_and_run(self.make_run_args(), self.compose_and_run(self.make_run_args(),
...@@ -1421,7 +1420,7 @@ fn make_lib_name(&self, auxfile: &Path) -> PathBuf { ...@@ -1421,7 +1420,7 @@ fn make_lib_name(&self, auxfile: &Path) -> PathBuf {
fn make_exe_name(&self) -> PathBuf { fn make_exe_name(&self) -> PathBuf {
let mut f = self.output_base_name(); let mut f = self.output_base_name();
// FIXME: This is using the host architecture exe suffix, not target! // FIXME: This is using the host architecture exe suffix, not target!
if self.config.target == "asmjs-unknown-emscripten" { if self.config.target.contains("emscripten") {
let mut fname = f.file_name().unwrap().to_os_string(); let mut fname = f.file_name().unwrap().to_os_string();
fname.push(".js"); fname.push(".js");
f.set_file_name(&fname); f.set_file_name(&fname);
...@@ -1439,8 +1438,9 @@ fn make_run_args(&self) -> ProcArgs { ...@@ -1439,8 +1438,9 @@ fn make_run_args(&self) -> ProcArgs {
let mut args = self.split_maybe_args(&self.config.runtool); let mut args = self.split_maybe_args(&self.config.runtool);
// If this is emscripten, then run tests under nodejs // If this is emscripten, then run tests under nodejs
if self.config.target == "asmjs-unknown-emscripten" { if self.config.target.contains("emscripten") {
args.push("nodejs".to_owned()); let nodejs = self.config.nodejs.clone().unwrap_or("nodejs".to_string());
args.push(nodejs);
} }
let exe_file = self.make_exe_name(); let exe_file = self.make_exe_name();
......
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
("sparc", "sparc"), ("sparc", "sparc"),
("x86_64", "x86_64"), ("x86_64", "x86_64"),
("xcore", "xcore"), ("xcore", "xcore"),
("asmjs", "asmjs")]; ("asmjs", "asmjs"),
("wasm32", "wasm32")];
pub fn get_os(triple: &str) -> &'static str { pub fn get_os(triple: &str) -> &'static str {
for &(triple_os, os) in OS_TABLE { for &(triple_os, os) in OS_TABLE {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册