Skip to content

Commit 8b00355

Browse files
authored
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](rust-lang/llvm#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 emscripten-core/emscripten#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. #36317 tracks work on this. Fixes #36515 Fixes #36515 Fixes #36356
2 parents bba3fca + afa72b5 commit 8b00355

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+615
-211
lines changed

mk/cfg/wasm32-unknown-emscripten.mk

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# wasm32-unknown-emscripten configuration
2+
CC_wasm32-unknown-emscripten=emcc
3+
CXX_wasm32-unknown-emscripten=em++
4+
CPP_wasm32-unknown-emscripten=$(CPP)
5+
AR_wasm32-unknown-emscripten=emar
6+
CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so
7+
CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a
8+
CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so
9+
CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM
10+
CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS)
11+
CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten := -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS)
12+
CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS)
13+
CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 -s BINARYEN=1
14+
CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
15+
CFG_LLC_FLAGS_wasm32-unknown-emscripten :=
16+
CFG_INSTALL_NAME_wasm32-unknown-emscripten =
17+
CFG_EXE_SUFFIX_wasm32-unknown-emscripten =
18+
CFG_WINDOWSY_wasm32-unknown-emscripten :=
19+
CFG_UNIXY_wasm32-unknown-emscripten := 1
20+
CFG_LDPATH_wasm32-unknown-emscripten :=
21+
CFG_RUN_wasm32-unknown-emscripten=$(2)
22+
CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2))
23+
CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten
24+
CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1

mk/main.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ endif
300300
# LLVM macros
301301
######################################################################
302302

303-
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
303+
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
304304
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
305305
interpreter instrumentation
306306

src/bootstrap/Cargo.lock

+24-24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bootstrap/check.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ pub fn compiletest(build: &Build,
108108
cmd.arg("--host").arg(compiler.host);
109109
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
110110

111+
if let Some(nodejs) = build.config.nodejs.as_ref() {
112+
cmd.arg("--nodejs").arg(nodejs);
113+
}
114+
111115
let mut flags = vec!["-Crpath".to_string()];
112116
if build.config.rust_optimize_tests {
113117
flags.push("-O".to_string());
@@ -323,6 +327,9 @@ pub fn krate(build: &Build,
323327
if target.contains("android") {
324328
build.run(cargo.arg("--no-run"));
325329
krate_android(build, compiler, target, mode);
330+
} else if target.contains("emscripten") {
331+
build.run(cargo.arg("--no-run"));
332+
krate_emscripten(build, compiler, target, mode);
326333
} else {
327334
cargo.args(&build.flags.args);
328335
build.run(&mut cargo);
@@ -371,6 +378,35 @@ fn krate_android(build: &Build,
371378
}
372379
}
373380

381+
fn krate_emscripten(build: &Build,
382+
compiler: &Compiler,
383+
target: &str,
384+
mode: Mode) {
385+
let mut tests = Vec::new();
386+
let out_dir = build.cargo_out(compiler, mode, target);
387+
find_tests(&out_dir, target, &mut tests);
388+
find_tests(&out_dir.join("deps"), target, &mut tests);
389+
390+
for test in tests {
391+
let test_file_name = test.to_string_lossy().into_owned();
392+
println!("running {}", test_file_name);
393+
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
394+
let status = Command::new(nodejs)
395+
.arg(&test_file_name)
396+
.stderr(::std::process::Stdio::inherit())
397+
.status();
398+
match status {
399+
Ok(status) => {
400+
if !status.success() {
401+
panic!("some tests failed");
402+
}
403+
}
404+
Err(e) => panic!(format!("failed to execute command: {}", e)),
405+
};
406+
}
407+
}
408+
409+
374410
fn find_tests(dir: &Path,
375411
target: &str,
376412
dst: &mut Vec<PathBuf>) {
@@ -381,7 +417,8 @@ fn find_tests(dir: &Path,
381417
}
382418
let filename = e.file_name().into_string().unwrap();
383419
if (target.contains("windows") && filename.ends_with(".exe")) ||
384-
(!target.contains("windows") && !filename.contains(".")) {
420+
(!target.contains("windows") && !filename.contains(".")) ||
421+
(target.contains("emscripten") && filename.contains(".js")){
385422
dst.push(e.path());
386423
}
387424
}

src/bootstrap/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,8 @@ impl Build {
975975
// than an entry here.
976976

977977
let mut base = Vec::new();
978-
if target != self.config.build && !target.contains("msvc") {
978+
if target != self.config.build && !target.contains("msvc") &&
979+
!target.contains("emscripten") {
979980
base.push(format!("-Clinker={}", self.cc(target).display()));
980981
}
981982
return base

src/bootstrap/native.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub fn llvm(build: &Build, target: &str) {
6565
.out_dir(&dst)
6666
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
6767
.define("LLVM_ENABLE_ASSERTIONS", assertions)
68-
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
68+
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
6969
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
7070
.define("LLVM_INCLUDE_TESTS", "OFF")
7171
.define("LLVM_INCLUDE_DOCS", "OFF")

src/bootstrap/sanity.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ pub fn check(build: &mut Build) {
9595
// We're gonna build some custom C code here and there, host triples
9696
// also build some C++ shims for LLVM so we need a C++ compiler.
9797
for target in build.config.target.iter() {
98+
// On emscripten we don't actually need the C compiler to just
99+
// build the target artifacts, only for testing. For the sake
100+
// of easier bot configuration, just skip detection.
101+
if target.contains("emscripten") {
102+
continue;
103+
}
104+
98105
need_cmd(build.cc(target).as_ref());
99106
if let Some(ar) = build.ar(target) {
100107
need_cmd(ar.as_ref());
@@ -104,22 +111,21 @@ pub fn check(build: &mut Build) {
104111
need_cmd(build.cxx(host).as_ref());
105112
}
106113

114+
// The msvc hosts don't use jemalloc, turn it off globally to
115+
// avoid packaging the dummy liballoc_jemalloc on that platform.
116+
for host in build.config.host.iter() {
117+
if host.contains("msvc") {
118+
build.config.use_jemalloc = false;
119+
}
120+
}
121+
107122
// Externally configured LLVM requires FileCheck to exist
108123
let filecheck = build.llvm_filecheck(&build.config.build);
109124
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
110125
panic!("filecheck executable {:?} does not exist", filecheck);
111126
}
112127

113128
for target in build.config.target.iter() {
114-
// Either can't build or don't want to run jemalloc on these targets
115-
if target.contains("rumprun") ||
116-
target.contains("bitrig") ||
117-
target.contains("openbsd") ||
118-
target.contains("msvc") ||
119-
target.contains("emscripten") {
120-
build.config.use_jemalloc = false;
121-
}
122-
123129
// Can't compile for iOS unless we're on OSX
124130
if target.contains("apple-ios") &&
125131
!build.config.build.contains("apple-darwin") {

src/bootstrap/step.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,6 @@ impl<'a> Step<'a> {
418418
self.check_crate_std(compiler),
419419
self.check_crate_test(compiler),
420420
self.check_debuginfo(compiler),
421-
self.dist(stage),
422421
];
423422

424423
// If we're testing the build triple, then we know we can
@@ -463,6 +462,9 @@ impl<'a> Step<'a> {
463462
// misc
464463
self.check_linkcheck(stage),
465464
self.check_tidy(stage),
465+
466+
// can we make the distributables?
467+
self.dist(stage),
466468
]);
467469
}
468470
return base

src/liballoc/arc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ mod tests {
10001000
}
10011001

10021002
#[test]
1003+
#[cfg_attr(target_os = "emscripten", ignore)]
10031004
fn manually_share_arc() {
10041005
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
10051006
let arc_v = Arc::new(v);

src/liballoc_jemalloc/build.rs

+18
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ fn main() {
2727
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
2828
let src_dir = env::current_dir().unwrap();
2929

30+
// FIXME: This is a hack to support building targets that don't
31+
// support jemalloc alongside hosts that do. The jemalloc build is
32+
// controlled by a feature of the std crate, and if that feature
33+
// changes between targets, it invalidates the fingerprint of
34+
// std's build script (this is a cargo bug); so we must ensure
35+
// that the feature set used by std is the same across all
36+
// targets, which means we have to build the alloc_jemalloc crate
37+
// for targets like emscripten, even if we don't use it.
38+
if target.contains("rumprun") ||
39+
target.contains("bitrig") ||
40+
target.contains("openbsd") ||
41+
target.contains("msvc") ||
42+
target.contains("emscripten")
43+
{
44+
println!("cargo:rustc-cfg=dummy_jemalloc");
45+
return;
46+
}
47+
3048
if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
3149
let jemalloc = PathBuf::from(jemalloc);
3250
println!("cargo:rustc-link-search=native={}",

0 commit comments

Comments
 (0)