I talked with Thomas Lively about getting a new repo in the WebAssembly org. He was open to it, but pushed slightly back and asked why we can't just rename 'wasi-sdk'. I missed last weeks meeting, so I believe this was discussed more then and Alex strongly preferred not renaming it. Alex, what are your concerns again? I told Thomas I'd get back to him with more rationale.
That aside, there is the question of what to name the new repo. I wonder if it's possible to name the new repo to just 'component-sdk' and publish both new artifacts there. Then eventually when enough things are migrated, we could deprecate the 'wasi-sdk' repo. It feels like a nice goal to eventually have a single repo for all this code, and 'component' is generic enough to cover both.
I don't think 'web-sdk' would fly, it's too generic and we'd probably get pushback. 'web-component-sdk' collides with web components. So that would leave 'component-web-sdk' as a fallback.
@Alex Crichton @Ben Visness
My main worry was basically the volume of locations that refer to "wasi" or "wasi-sdk" that have to be updated to something else when the wasi-sdk repo is archived/renamed/etc. Some examples are:
#include <wasi/version.h> which is the primary vector for conditional compilation based on wasi versions (e.g. __wasip{1,2,3}__)For myself this was then all capped off with the realization that this would sort of continue to perpetuate the feeling of instability for WASI and such.
Overall though I very much agree that the long-term goal should be one place to get clang & co. I do not want a long-term solution where there's both a wasi-sdk and component-web-sdk for example.
tl;dr; I got cold feet and had second thoughts about renaming wasi-sdk
Maintenance of wasi-sdk is also pretty onerous right now insofar as every PR has like ~6 hours of CI because windows is slow and refuses to ccache correctly.
I'll definitely admit though that some of this is sort of selfish of me insofar as I suspect that a lot of the renaming work would fall on me and I'm not particularly eager to go do all that
but also I mean none of what I bring up is like a super strong objection, and it's definitely technically feasible to rename
Sure I get that, not trying to add unreasonable work here, especially with all the stuff going on.
It sounds like eventually renaming things over makes sense, but it will just take a while. I wonder if instead of renaming the wasi-sdk repo, we could just create component-sdk as a mirror that automatically follows along with wasi-sdk. We could keep issues/PRs on wasi-sdk. Eventually when things are migrated over, we could switch from component-sdk being the mirror to being the development target. Or alternatively start with wasi-sdk being a mirror that is eventually disabled.
My concern is to avoid fragmenting development here. I think the web.wit work and other things are going to need to happen in the same repo as the wasi target.
yeah IIRC that was the general conclusion, component-sdk would repackage wasi-sdk's artifacts (wasi-sdk would include wasm32-webp2) and would possibly include web.h and libweb.a or similar for a web-sdk-style-download
we should probably talk more in depth this week about web.h to hammer out a more concrete plan there
Ah okay. I had heard an idea around having component-sdk embed wasi-sdk as a submodule. I think a true git mirror would be cleaner, because I'm not sure what would actually live in the repo besides just the submodule
my rough assertion is that it's going to be best to not actually have parallel CI builds for anything since it takes so long to build everything
there's no problem adding wasm32-webp2 of course to wasi-sdk, so the actual production of things is of no concern, it's basically around the optics and where things are downloaded
that's where the thinking that (component-)web-sdk would repackage the wasi-sdk artifacts
although this also touches on distribution of web.wit/web.h b/c I was thinking that wasi-sdk wouldn't ever want to include that
another example was wasi-sdk not including bindings to wasi:http as an example
I guess it depends on how libc bootstraps some of its API's. I was imagining it'd need access to a small subset of things like console.log/etc. Definitely doesn't need many web API's. But a few
yeah building wasi-libc needs WITs for sure, but right now those bindings are internal to wasi-libc and aren't published
or, well, actually they are published, but not necessarily easily accessible
so wasi-libc would include browser.wit and bind things like performance.now or w/e for sure, but web.h is like "ok but if you actually do web development use this"
Yeah that makes sense. In that case, web.h doesn't need to live with wasi-sdk/component-sdk. We probably could hand-craft a minimal web-libc.wit that has just the basics and include that there.
partly this is where I think we should talk about web.h in more detail because personally I think it might make the most sense to not include that in a *-sdk download
but this has a large impact on developer experience though so we'll definitely want to make an actual decision about this
I would consider web.h to be the equivalent of a web-sys crate for C/C++ developers and not part of the "toolchain". It could live in the same repo as toolchain things but shouldn't be part of a toolchain release imo.
agreed yeah, although I'd be concerned about living in the toolchain repo insofar as CI for a toolchain is typically quite expensive whereas CI for web.h in theory should be pretty cheap
Depends on what triggers the CI, I guess?
it's true, and I'm perhaps biased a bit here, but most repos I work on operate on the model of everything that merges runs the full CI of the repo to ensure nothing gets out of sync
running a subset of CI checks makes sense for PRs IMO but when merging I personally don't trust filters much b/c they often miss subtle interactions
but overall what I'm thinking is we should nail down web.h distribution, and that might re-shift things to biting the bullet and renaming wasi-sdk
it also might not, iunno
I suppose development & distribution of web.h
I'm just torn between the idea of having a separate repo for browser.wit / web.h / other bindings artifacts (?) that can move at their own pace, and the idea of having a one-stop shop for the whole affair (incl. a natural place to centralize issues, since I imagine many might be cross-cutting)
Along those lines the issue trackers of wasilibc and wasisdk are quite blurred yeah and not great being separate
It might also be important to consider how interlinked web.h / web.a / etc. will be with the actual clang toolchains. If they need to remain in sync, then it might be best to release them together (sometimes releasing smaller updates to just web.h)
If web.h were a separate repo, I'd personally say that the produced artifact should be *.{h,c} files (maybe *.{hh,cc} too) rather than *.a, and that should keep compat pretty orthgonal b/c then users don't have to align targets or we have to deal with abis or anything like that, just #ifdefs in a few places
if web.h ships with the sdk though then that's all different, we'd be shipping libweb.a, but it'd also be a solved problem for clang compat then since it's only precompiled
Honestly, it would be great to precompile as little as possible and distribute all the bindings SQLite style (one header, one impl file). Is that feasible or do the modded toolchains need object files with mystery magic in them somehow?
oh that's true it'd also need the *.o that wit-bindgen generates
I thought I remembered something funny there
in theory it's it's just another "include this in your build" kind of file
what does that object file do again?
encodes the WIT in a custom section that wasm-component-ld later picks up to generate a component
WIT or component binary stuff?
elaborate on "component binary stuff"?
the object contains a custom section which is the WIT-encoded-as-wasm in wasm binary form, so sort of a wasm-component-in-a-custom-section-in-a-core-module
just was wondering if wasm-component-ld literally had to re-parse WIT or if it saw the component binary format
ah yeah, component binary in that case
Here we go!
https://github.com/WebAssembly/component-sdk
https://github.com/WebAssembly/component-web-bindings
So now that these repos exist, what are the general next steps? Presumably for component-sdk we want to add a wasm32-webp2 target (to align with the Rust name) but that work happens in wasi-sdk first, right? I doubt there's much to do in the component-sdk repo until we get that taken care of first.
And for the bindings, I assume we can just start adding some WIT and some scripts for generating language bindings?
The rough timeline in my head is:
component-web-bindings with *.wit *.wit to bootstrap the wasm32-webp2 target in wasi-libc.wasm32-webp2 to the list of targets to buildcomponent-sdk to (temporarily for now) pull artifacts from wasi-sdk, rename them/shuffle, and then republish on the component-sdk repothen later assuming everything goes well
Does it actually make sense to make wasi-libc's web target depend on an artifact from component-web-bindings? Ryan and I were thinking that something more minimal might make more sense, e.g. hand-writing bindings that do exactly what you need for printing, time, randomness, etc.
If you want, we could certainly do that in component-web-bindings and have an artifact for you to consume, but it seems like it would be nice one way or another to have some really concise bindings for that
I guess I'm also curious to know what that artifact actually needs to look like
in the long-term I'd like to manage it similar to the WASI WITs where the artifact that wasi-libc consumes is some sort of published WIT, but no need for it to depend on C/H files or such, that'll get handled by wasi-libc's own wit-bindgen steps
oh ok, so you literally only need WIT
in the meantime though if it's handwritten WIT I think that's totally fine, no need to jump to the end originally
yeah
and if it's easier to bootstrap by just copying/vendoring some files that's also fine IMO
just long-term I'd like it to be a curl-the-thing situation
well that seems like a good way for me to get my feet wet one way or another
Is there something I can build that will scream errors at me to guide me through this? Should I just take a crack at scaffolding a new target in wasi-libc somehow?
in theory the build steps should be cmake -S . -B build -DTARGET_TRIPLE=wasm32-webp2 -G Ninja && ninja -C build
and if you can get that working that's probably worth a PR heh
we shall see what happens
So...in this new world, we presumably don't have "command" or "reactor" interfaces at all anymore
but that seems to be the first thing I'm crashing into with libc-bottom-half
or would we exclusively be doing this "reactor"-style?
I'm really not clear on why libc would care about such things
yeah that'd be my hunch -- you'd basically not include crt1-command.o and would only have crt1-reactor.o in the sysroot
I'm making some progress but just slogging through cmake things. Trying to get to a point where it builds but literally everything is stubbed out to just trap.
makes sense yeah, and I figure that most functions are probably going to just return an error in the end
well, time to pivot right back to wit-bindgen
![]()
@Alex Crichton Could we cut a release of wasm-tools with getter/setter support?
I can do the wit-bindgen updates right away...hopefully pretty easy since they're mostly just sugar for functions once they're validated
awesome! thanks
What do I do with this new canonical_names parameter in wit-component? I'm having a hard time figuring out what it actually changes
but it's showing up in a lot of places
set it to false
Yan Chen will work on plumbing that orthogonally
of course now I find bugs in wasm-tools :upside_down:
well...I will hack around locally and hopefully avoid multiple minor patches
cue disney animals signing a song about the circle of life
Do we want any stdio in wasi-libc's webp2 mode? My gut says no, but then I look at all the occurrences of fprintf(stderr and just think...man, seems pretty stupid to ifdef every last one of them to console.error.
But certainly we don't have stdin and the browser console is only vaguely like stdout.
But also people will probably just want to printf.
we are making PROGRESS
![]()
through enough of the libc implementation to have linker errors for the various things I have stubbed out
this has been a very pleasant little exercise so far, figuring out how to implement all the libc stuff we care about on top of web APIs
[245/246] Generating sysroot/lib/wasm32-webp2/libc.a
mozilla@Bens-MacBook-Pro wasi-libc % echo $?
0
nice! FWIW I do think that stdio will want to get hooked up, at least stdout/stderr, as otherwise it's likely going to be a bit too overly onerous to port
So I have a big TODO comment in there about how to handle entry points, and the upshot is that I think we need something that is halfway between Reactor and Command
(eventually)
Basically, importing a module should be allowed side effects, just like top-level code in JS today. That would naturally map to some kind of "main"-ish function in a language like C. But when that function exits the program isn't done and nothing should be torn down. Also it probably would have zero args.
In my ideal world I imagine that in this reactor-plus-side-effects mode, the main function would get linked as a component-level start function with zero params and maybe at most a result<T> return value.
it might be worth seeing how Emscripten models this, and I agree that int main probably isn't the way to do this. The only thing I can think of is some sort of annotation which the toolchain slurps up, but that's not easy to implement AFAIK
Right, and also I think a main function is the natural choice for code that "just runs", especially since we're moving toward a world where you can basically put an entire app in one wasm file. Maybe we should actually just figure out how to support command-style linking (and always provide argc=0)
But also, if you are writing a game and your main function just goes into an infinite loop, idk how we're supposed to translate that to the web (something something JSPI?)
So, I think I have wasi-libc far enough along to start moving on to clang itself. What roughly do I have to do there? I imagine clone wasi-sdk and just add some patches to somehow teach it about wasm32-webp2 and the new webp2 sysroot?
(I don't think I'll actually attempt to merge my wasi-libc branch until I can validate that it works at all against a patched version of clang.)
yeah, the wasi-sdk build it split into "two cmakes" sort of where one builds clang and one builds the sysroot, so long as you're not changing clang you just need to build the sysroot where you specify your compiler as probably wasi-sdk-34
./ci/build.sh has everything combined together and you can tweak that script to run things locally
Claude is telling me a clang patch will probably be necessary in order to teach it of the existence of a webp2 "OS"
because of some jank about which paths it chooses to search
ah yeah that sounds about right
we currently model that with *.patch files which are applied to the submodule locally
it's a bit brittle
but you can just edit the submodule and make commits and worry about that at the end
ah sure, that sounds good
What is this config submodule within wasi-sdk? It's pulling from some gnu repo that isn't responding right now.
Cloning into '/Users/mozilla/Developer/WebAssembly/wasi-sdk/src/config'...
fatal: unable to access 'https://git.savannah.gnu.org/git/config.git/': Failed to connect to git.savannah.gnu.org port 443 after 4055 ms: Couldn't connect to server
fatal: clone of 'https://git.savannah.gnu.org/git/config.git' into submodule path '/Users/mozilla/Developer/WebAssembly/wasi-sdk/src/config' failed
it's... honestly I have no idea
it's some thing for ./configure or something like that i never understood
I keep forgetting to turn that into a git subtree because that remote is super unreliable
well I managed to build clang without it, so hopefully it's fine
it's not fine
I was able to do the initial set of clang updates, but I can't run the full wasi-sdk cmake unfortunately
do you have a local checkout of the config stuff that you could zip up and send my way, or something?
if you try it now does it work? that server randomly goes offline and comes back up
I have tried several times today with no success :/
maybe I'm just unlucky
no it's a bad server lol
I think that worked, thanks
thankfully adding the target triple was easy
Ben Visness said:
In my ideal world I imagine that in this reactor-plus-side-effects mode, the main function would get linked as a component-level start function with zero params and maybe at most a result<T> return value.
@Luke Wagner told me today that core wasm start functions should be sufficient for side effects, and that would probably remain compatible with the reactor approach generally. I remain a bit skeptical because what if the initialization work you want to do in some way depends on things that aren't yet instantiated in the component?
It feels like a start function should run once the entire component is instantiated, although I can't actually think of an example right now
oh that actually might be core-wasm-start vs the _initialize export -- start isn't a great fit because when you run it your module's imports aren't hooked up yet (e.g. the indirect adapters needed for components), but the _initialize function is a toolchain convention that's run as soon as everything's hooked up, and as part of instantiation
so _initialize is run by a module's start section, just not the "main module"'s start section
IIRC ctors in C/C++ go into _initialize, but I could also be misremembering
Alex Crichton said:
so
_initializeis run by a module'sstartsection, just not the "main module"'s start section
I don't quite follow, what's the difference? Is there one _initialize per core module in a component?
_initialize is a special core wasm export name recognized by wasm-tools component new (wit-component) which is handled specially by running it once the main module's imports are all hooked up
basically using start won't work b/c imports aren't hooked up (e.g. you couldn't call JS things), but using _initialize should work b/c imports are all hooked up
What do you mean imports aren't hooked up? Core wasm start functions are perfectly capable of calling imported functions, aren't they?
it can yeah, but for example if you instantiate a core wasm module on the web it's generally not helpful to call imports from start b/c you can't have access to the exported memory of the module (instantiation hasn't finished yet). So in a sense while you can call imports in start that's not super useful.
For components when I say "hooked up" I mean the thing where if you import a component function that needs memory (e.g. returns or takes a string) then you have to instantiate the main module with a trapping shim first, and then afterwards you fill in the shim such that future calls work (the call_indirect table stuff). So when the main module is instantiated it has imports and can call them, but if they're called they all trap. Only after instantiation is the "fixup" module instantiated, and that module fills in all the shims where all future calls succeed
Ah, earlier I was saying that it was possible to call imports from start that use memory in pure WAT, which is technically true, but I forgot that wasm-tools component new does the call_indirect stuff instead which happens after start. So yeah, I guess you do want the _initialize after all; but it's called at component-instantiation-time, as-if it was a start function (I'm guessing via some helper core module that imports _initialize and calls it from its own start function) right?
right yeah
Ok, that makes sense. I wasn't aware of _initialize but if that's already working for C++ constructors etc. then I don't see why it wouldn't work for general-purpose initialization too. Maybe we just need to designate how user code gets hooked up to _initialize.
double-check me on this, but I think C++ constructors in theory already "just work"
That said, would a component start function allow us to elide the helper module with a core start function?
it would not
(still need the shim/fixup module to break the import cycle)
Which import cycle is this?
canon lower needs a linear memory, the main module exports linear memory, the main module needs an import to be instantiated, the import is canon lower
That makes sense generally, but I don't think I've seen that in my experiments...maybe I need to look again
oh man you're finding all the cranks to turn aren't you
There are so many cranks
and yet Claude would turn them all faster if it could
I created a pre-push commit hook specifically to stop it from pushing on my behalf, and guess what it just did? It amended its commit to remove the Co-Authored-By line and pushed anyway
all I want is for it to rebase and then NOT push before I review it
Emscripten has support for not shutting down the program when main exits: https://emscripten.org/docs/tools_reference/settings_reference.html#exit-runtime
So, one interesting point of jankness: because I am making the web builds default to the reactor model, main doesn't get executed, so main actually gets dropped most of the time in linking if provided, which is fine except that it totally breaks CMake's own checks like check_library_exists
because apparently these functions just compile a tiny C file whose main calls a library function, and if it successfully links, it assumes the library exists
but if main gets dropped, linking can succeed by accident even if the library does not exist, which can lead to bad cmake config
I worked around this for the sysroot builds with:
-DCMAKE_EXE_LINKER_FLAGS=-Wl,--export-if-defined=main,--export-if-defined=__main_argc_argv
but it seems the same thing could affect general users of the webp2 target
And it seems quite wrong to define such flags by default for normal SDK users
...maybe this whole problem will just go away if I just hook up main to _initialize
I will say that the further the target diverges from looking like a posix-y thing the more readily issues like this are going to come up, this'll never be a fully posix-y target per se but some things will definitely be more major than others. Not that I know how to solve it per se, but we might want to brainstorm how best to keep at least the major things mostly posix-y
For those wondering, the validation bug is that Firefox is complaining about a version suffix when an external ID is present (really when any attributes are present on the import name)
we are instantiating!
![]()
and crashing headlong into the lack of stdout
all according to plan
printf!
![]()
Last updated: Oct 11 2026 at 02:20 UTC