Emscripten: Add druntime & Phobos support - #5259
Conversation
|
@QuantumSegfault: This seems like a viable approach - basing Emscripten on your WASI work, after reading https://v8.dev/blog/emscripten-standalone-wasm and noting that they apparently try to use WASI APIs as much as possible, even in non-standalone-wasm mode. To get the druntime test runners to link, I only had to avoid a single undefined |
|
I'm not sure this makes sense to do like this. Emscripten use a more vanilla Musl, without all of the differences to the headers WASI-libc made. They opted to stub out functions, rather than remove them, and otherwise use the unmodified types, constants, etc. (other than where architecture specific differences are concerned). A lot of the
|
|
Yeah the I'd hope that Emscripten would eventually be based on wasi-libc... |
dc050c1 to
b03eb55
Compare
|
Okay, this is now based on I'm okay with depending/building on predefined |
Threading is a notable difference. Emscripten actually DOES support threading (over web workers; with some caveats). https://emscripten.org/docs/porting/pthreads.html Signals still not, other than for Though I wouldn't mind holding off on the threading discussion until I figure out WASIp3 (with Other than that I think the rest of the WASI route-arounds should be fine, if not always necessary. |
Yeah that sounds good to me. [And note that I've just started with The compiler has a special case wrt. TLS globals for wasm in general IIRC, emitting them as thread-global; so the compiler will probably have to be adapted for wasm threading too. |
I'm fairly certain that WASIp1 is the only valid option for Emscripten. They provide a subset of WASIp1 for the web (but not p2+ AFAICT) https://github.com/emscripten-core/emscripten/blob/main/src/lib/libwasi.js
Good to know. |
| enum B_NO_TRANSLATOR = (B_TRANSLATION_ERROR_BASE + 1); | ||
| enum B_ILLEGAL_DATA = (B_TRANSLATION_ERROR_BASE + 2); | ||
| } | ||
| else version (CRuntime_WASI) |
There was a problem hiding this comment.
These errno are correct, but Emscripten provides additional ones:
There was a problem hiding this comment.
Yeah here I was lazy and didn't want to duplicate the existing CRuntime_WASI block, after seeing that the Emscripten headers forward the WASI codes. [And I don't really care about the extra ones; if people relied on them, their code wouldn't work with WASI.]
At least a comment wrt. Emscripten would be good though; there's some polishing left to do, hence the draft state and WIP title. :)
There was a problem hiding this comment.
Yeah. Just the one thing that stuck out as probably somehow wrong, so I checked.
I'll wait for it to be undrafted before reviewing the changes more thoroughly.
| tool = getCC(argsBuilder->args); | ||
| } | ||
| auto argsBuilder = std::make_unique<ArgsBuilder>(); | ||
| std::string tool = getCC(argsBuilder->args); |
There was a problem hiding this comment.
This is e.g. also still to polish, causing the Alpine CI job failures (no integrated LLD, but external wasm-ld).
This all dates back to the very early wasm support, like the wasm-defaults .conf file - we used to only support bare-metal wasm, so no druntime and Phobos to link, and no need for a C compiler as linker driver, since there wasn't a wasm libc support either. So we used to invoke wasm-ld (unless we have an integrated LLD) with the ld CLI interface, for all (non-WASI) wasm targets.
We can keep this behavior for backwards-compatibility, but then only when targeting an unknown/none OS. We already do that in 55-target-wasm-naked.conf nowadays, via the -link-internally (=> use integrated lld with wasm-ld CLI interface) - but only if LLD integration was enabled at build-time.
So the compiler special case here would only be needed without LLD integration. Not sure that's worth the trouble, incl. the link_WebAssembly lit complication (looking for an external wasm-ld), which I haven't gotten rid of yet.
There was a problem hiding this comment.
In theory, using most modern system clang as link driver for bare-metal Wasm should be fine? wasm-ld is a standard part of LLVM distributions nowadays.
One notable exception is (at least) macOS 15's clang. So you'll have to have either MacPorts/Homebrew LLVM/Clang available to use as -gcc, or use wasi-sdk's (or emsdk's).
But if we use -link-internally by default, then you probably won't notice the difference most of the time.
There was a problem hiding this comment.
Oh right - I've just tested this with my system-default clang 18, and it works with an extra -Xcc=-nostdlib:
$ bin/ldc2 -mtriple=wasm32-unknown-unknown -v ../ldc/tests/codegen/wasm.d -link-internally=false -Xcc=-nostdlib -Xcc=-v
[…]
Did not find C cross-compiler: `wasm32-unknown-unknown-gcc`
Did not find C cross-compiler: `wasm32-unknown-unknown-clang`
Found C cross-compiler: `/usr/bin/clang`
/usr/bin/clang --target=wasm32-unknown-unknown wasm.o -o wasm.wasm -Xlinker -z -Xlinker stack-size=1048576 -Xlinker --stack-first -nostdlib -Wl,--gc-sections
[…]
"/usr/bin/wasm-ld-18" -m wasm32 -L/usr/lib wasm.o -z stack-size=1048576 --stack-first --gc-sections -o wasm.wasm
So yeah, that should be good enough. Noone has requested an ld CLI interface for other targets either, so...
|
The druntime unittest failure was apparently due to too simplistic pthread stubs (so I guess one has to explicitly opt into emulated pthreads support): https://github.com/emscripten-core/emscripten/blob/6313a2d67a92c3e3b449f48e2fc9882d7e45ff3c/system/lib/pthread/library_pthread_stub.c#L222-L224 The timezone stuff is a bit of a PITA; I got the testrunners to include and be able to read the host runner's So it's probably best to follow the |
30b5ac7 to
84ae082
Compare
|
Ready for review now. |
| append("-Wl,-z,stack-size=1048576 -Wl,--stack-first" LD_FLAGS) | ||
|
|
||
| if("${TARGET_SYSTEM}" MATCHES "Emscripten") | ||
| append("-sALLOW_MEMORY_GROWTH" LD_FLAGS) |
There was a problem hiding this comment.
Do we want to enable this by default in ldc2.conf?
If not maybe this block should be moved outside of
(normally inherited from... if block to be less confusing
There was a problem hiding this comment.
Yeah I'm not sure how likely this is going to be needed for user apps as well. IIRC, Emscripten defaults to something like 20 MB, which does sound really low for D with GC.
There was a problem hiding this comment.
Do you know how wasmtime/wasi-libc handles this? All dynamic by default?
There was a problem hiding this comment.
Some of these values are incorrect.
I think you based these of the _POSIX_* values. Some of these have normal values.
#define NAME_MAX 255
#define PATH_MAX 4096
#define PIPE_BUF 4096There was a problem hiding this comment.
Oh, thx for checking so thoroughly! Yeah they were all based on the POSIX_ ones; the NAME_MAX of 14 or so did sound weird. Will fix.
There was a problem hiding this comment.
Let's make importc_compare detect mismatching numerical constants for us: dlang/dmd#23618
Currently yields this for Emscripten here:
Collected 270 C types.
Collected 1333 numerical C constants.
Error: Constant core.stdc.stdint.WCHAR_MIN diverges: 0 (D) vs. -2147483648 (ImportC)
Error: Constant core.stdc.stdint.WCHAR_MAX diverges: 1114111 (D) vs. 2147483647 (ImportC)
Error: Constant core.stdc.stdint.WINT_MIN diverges: 0 (D) vs. -2147483648 (ImportC)
Error: Constant core.stdc.signal.SIG_IGN diverges: 1 (D) vs. 4294967294 (ImportC)
Error: Constant core.stdc.limits.MB_LEN_MAX diverges: 2 (D) vs. 4 (ImportC)
Error: Constant core.stdc.math.math_errhandling diverges: 3 (D) vs. 2 (ImportC)
Error: Constant core.stdc.wchar_.WEOF diverges: 65535 (D) vs. 4294967295 (ImportC)
There was a problem hiding this comment.
New changes look good.
Regarding the merging down of the changes made during WASI upstreaming, there was one issue I noticed.
The version gate for the unittest in typecons.d on line 3553 should have been deleted, as the versioning was moved inside the unittest.
There was a problem hiding this comment.
Ah alright, missed one of these (unfortunately no merge conflict for these) - thx for spotting!
…ept for generally broken MB_LEN_MAX]
Based on predefined
CRuntime_Musl,WASIandWASIp1.Also add an according CI job similar to the WASI one, incl. generating an addon package.