Stream: git-wasmtime

Topic: wasmtime / issue #6987 Add component model support to the...


view this post on Zulip Wasmtime GitHub notifications bot (Sep 10 2023 at 02:07):

seanisom opened issue #6987:

Feature

Add component model support to the c-api (particularly the ability run a component from a c-api host).

Benefit

Much of the WebAssembly world is currently (re)tooling around the component model as it approaches MVP. The ability to run components will quickly become more critical with the finalization of the wasi preview 2 abi. Currently C/C++ is the only wit-bindgen supported guest language and example in the new component-docs repo that does not have a path to run from a host in the same language.

Implementation

I'd be happy to take a go at this modeled roughly around the Rust crate with the current c-api idioms (for example wasmtime_config_wasm_component_model(conf, true);, a component aware linker (perhaps wasmtime_linker_define_component_model(linker);), etc. I haven't looked deep enough into the implementation yet to see if there is significant core functionality to enable this past the standard glue code and lifecycle management for c objects.

Alternatives

Eventually this will become necessary - it's a matter of timing. I suspect that this has just not yet been implemented due to the instability of wasmtime::component.

CC: Discussed with @sunfishcode at the BA hackathon

view this post on Zulip Wasmtime GitHub notifications bot (Sep 10 2023 at 03:12):

pchickey commented on issue #6987:

The Nginx Unit team is also interested in this

view this post on Zulip Wasmtime GitHub notifications bot (Sep 10 2023 at 08:12):

seanisom edited issue #6987:

Feature

Add component model support to the c-api (particularly the ability run a component from a c-api host).

Benefit

Much of the WebAssembly world is currently (re)tooling around the component model as it approaches MVP. The ability to run components will quickly become more critical with the finalization of the wasi preview 2 abi. Currently C/C++ is the largest fully-supported language with a clear path to producing guests (through wit-bindgen) that does not have a path to run from a host in the same language.

Implementation

I can take a first step with this modeled roughly around the Rust crate with the current c-api idioms (for example wasmtime_config_wasm_component_model(conf, true);, a component aware linker (perhaps wasmtime_linker_define_component_model(linker);), etc. I haven't looked deep enough into the implementation yet to see if there is significant core functionality to enable this past the standard glue code and lifecycle management for c objects.

Alternatives

Eventually this will become necessary - it's a matter of timing. I suspect that this has just not yet been implemented due to the instability of wasmtime::component.

CC: Discussed with @sunfishcode at the BA hackathon

view this post on Zulip Wasmtime GitHub notifications bot (Sep 10 2023 at 08:12):

seanisom edited issue #6987:

Feature

Add component model support to the c-api (particularly the ability run a component from a c-api host).

Benefit

Much of the WebAssembly world is currently (re)tooling around the component model as it approaches MVP. The ability to run components will quickly become more critical with the finalization of the wasi preview 2 abi. Currently C/C++ is the largest fully-supported language with a clear path to producing guests (through wit-bindgen) that does not have a path to run from a host in the same language.

Implementation

I can take a first pass at this modeled roughly around the Rust crate with the current c-api idioms (for example wasmtime_config_wasm_component_model(conf, true);, a component aware linker (perhaps wasmtime_linker_define_component_model(linker);), etc. I haven't looked deep enough into the implementation yet to see if there is significant core functionality to enable this past the standard glue code and lifecycle management for c objects.

Alternatives

Eventually this will become necessary - it's a matter of timing. I suspect that this has just not yet been implemented due to the instability of wasmtime::component.

CC: Discussed with @sunfishcode at the BA hackathon

view this post on Zulip Wasmtime GitHub notifications bot (Sep 10 2023 at 08:13):

seanisom edited issue #6987:

Feature

Add component model support to the c-api (particularly the ability run a component from a c-api host).

Benefit

Much of the WebAssembly world is currently (re)tooling around the component model as it approaches MVP. The ability to run components will quickly become more critical with the finalization of the wasi preview 2 abi. Currently C/C++ is the largest fully-supported language with a clear path to producing component guests (through wit-bindgen) that does not have a path to run from a host in the same language.

Implementation

I can take a first pass at this modeled roughly around the Rust crate with the current c-api idioms (for example wasmtime_config_wasm_component_model(conf, true);, a component aware linker (perhaps wasmtime_linker_define_component_model(linker);), etc. I haven't looked deep enough into the implementation yet to see if there is significant core functionality to enable this past the standard glue code and lifecycle management for c objects.

Alternatives

Eventually this will become necessary - it's a matter of timing. I suspect that this has just not yet been implemented due to the instability of wasmtime::component.

CC: Discussed with @sunfishcode at the BA hackathon

view this post on Zulip Wasmtime GitHub notifications bot (Sep 11 2023 at 19:21):

alexcrichton added the wasmtime:c-api label to Issue #6987.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 11 2023 at 19:21):

alexcrichton added the wasm-proposal:component-model label to Issue #6987.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 11 2023 at 19:22):

github-actions[bot] commented on issue #6987:

Subscribe to Label Action

cc @peterhuene

<details>
This issue or pull request has been labeled: "wasmtime:c-api"

Thus the following users have been cc'd because of the following labels:

To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.

Learn more.
</details>

view this post on Zulip Wasmtime GitHub notifications bot (Sep 11 2023 at 19:28):

alexcrichton commented on issue #6987:

Thanks for opening an issue for this! You're right in that this hasn't quite bubbled to the top of any priority list yet which is why it isn't done, but it's something that definitely should get done!

My prediction for the main difficulty of this feature will be how to transfer values back and forth. The type grammar of core wasm is quite simple which made this a non-issue for core wasm's C API support, but for components it's significantly different. The easiest route is probably going to be to mirror Val into C more-or-less. This will not be really all that efficient in terms of calls because datatypes like lists will be copied in/out and everything will be dynamically type-checked. For example I don't know how wasmtime_func_call_unchecked could get a C/C++ equivalent that skips all the type-checks. That's not a showstopper for any sort of initial support, however. Still though there's tricky questions around how exactly memory management will work with values. I'm not sure the best answer here.

More minor it might be worth bikeshedding a bit to avoid a wasmtime_component_* prefix on everything which is quite long. Not that I have much of an idea about a better name...

view this post on Zulip Wasmtime GitHub notifications bot (Sep 04 2024 at 21:03):

rajsite commented on issue #6987:

related #8036

view this post on Zulip Wasmtime GitHub notifications bot (Aug 21 2025 at 23:01):

alexcrichton closed issue #6987:

Feature

Add component model support to the c-api (particularly the ability run a component from a c-api host).

Benefit

Much of the WebAssembly world is currently (re)tooling around the component model as it approaches MVP. The ability to run components will quickly become more critical with the finalization of the wasi preview 2 abi. Currently C/C++ is the largest fully-supported language with a clear path to producing component guests (through wit-bindgen) that does not have a path to run from a host in the same language.

Implementation

I can take a first pass at this modeled roughly around the Rust crate with the current c-api idioms (for example wasmtime_config_wasm_component_model(conf, true);, a component aware linker (perhaps wasmtime_linker_define_component_model(linker);), etc. I haven't looked deep enough into the implementation yet to see if there is significant core functionality to enable this past the standard glue code and lifecycle management for c objects.

Alternatives

Eventually this will become necessary - it's a matter of timing. I suspect that this has just not yet been implemented due to the instability of wasmtime::component.

CC: Discussed with @sunfishcode at the BA hackathon

view this post on Zulip Wasmtime GitHub notifications bot (Aug 21 2025 at 23:01):

alexcrichton commented on issue #6987:

I'm going to close this issue in favor of more specific open issues since thanks to @MangoPeachGrape the component model is pretty well supported in the C API now that I think it's best to focus on specific issues rather than the general concept.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 04 2026 at 17:55):

planetbeing commented on issue #6987:

I was linked to this issue by https://github.com/bytecodealliance/component-docs/blob/4e906915e9a1020657f1cf7b193cb9fd2847d7e6/component-model/src/language-support/building-a-simple-component/c.md?plain=1#L329 but since this issue is closed, the trail is cold for me to discover how to host components with C/C++. The comment that "thanks to @MangoPeachGrape the component model is pretty well supported in the C API now" is heartening but I'm at a loss as to how to use that support or even what code changes those are referring to so I can start investigating. Where can I start looking for information on this?

view this post on Zulip Wasmtime GitHub notifications bot (Jan 04 2026 at 18:45):

seanisom commented on issue #6987:

@planetbeing - at the time I wrote those docs for C support in the component model, no progress had been made on this work here. We switched to the Rust crate a couple of years ago and I haven't kept up with it.

It looks like no examples were added to the Wasmtime C API docs for @MangoPeachGrape 's component mode work. Looking quickly through the autogenerated doxygen docs here (wasmtime_component*), the support looks fairly complete, and analogous to the Component Model API in the Rust crate.

I'd suggest following along with the Rust crate docs, substituting the C API types above and see how far that gets you.

I'd be willing to update the Component Model API docs this month, but will need to try it and build some minimal examples first.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 04 2026 at 18:46):

seanisom edited a comment on issue #6987:

@planetbeing - at the time I wrote those docs for C support in the component model, no progress had been made on this work here. We switched to the Rust crate a couple of years ago and I haven't kept up with it.

It looks like no examples were added to the Wasmtime C API docs for @MangoPeachGrape 's component model work. Looking quickly through the autogenerated doxygen docs here (wasmtime_component*), the support looks fairly complete, and analogous to the Component Model API in the Rust crate.

I'd suggest following along with the Rust crate docs, substituting the C API types above and see how far that gets you.

I'd be willing to update the Component Model API docs this month, but will need to try it and build some minimal examples first.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 27 2026 at 07:24):

ohAitch commented on issue #6987:

I'd be willing to update the Component Model API docs this month, but will need to try it and build some minimal examples first.

Here's a starting point, if you'll permit me the use of artificial intelligence technologies to wrangle boilerplate:
<details><summary><kbd>host.c</kbd></summary>

/**
 * C host for the adder WebAssembly component.
 *
 * Uses the Wasmtime C API's component model support to load and run
 * a component that exports: docs:adder/add.add(u32, u32) -> u32
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wasmtime.h>

static void exit_if_error(const char *step, wasmtime_error_t *error) {
  if (error == NULL)
    return;
  wasm_byte_vec_t error_message;
  wasmtime_error_message(error, &error_message);
  wasmtime_error_delete(error);
  fprintf(stderr, "error: failed to %s\n%.*s\n", step, (int)error_message.size,
          error_message.data);
  wasm_byte_vec_delete(&error_message);
  exit(1);
}

int main(int argc, char *argv[]) {
  if (argc != 4) {
    fprintf(stderr, "Usage: %s <x> <y> <component.wasm>\n", argv[0]);
    return 1;
  }

  uint32_t x = (uint32_t)atoi(argv[1]);
  uint32_t y = (uint32_t)atoi(argv[2]);
  const char *path = argv[3];

  // 1. Create engine with component model enabled
  wasm_config_t *config = wasm_config_new();
  wasmtime_config_wasm_component_model_set(config, true);
  wasm_engine_t *engine = wasm_engine_new_with_config(config);

  // 2. Read the component file
  FILE *f = fopen(path, "rb");
  if (!f) {
    fprintf(stderr, "error: could not open %s\n", path);
    return 1;
  }
  fseek(f, 0, SEEK_END);
  long fsize = ftell(f);
  fseek(f, 0, SEEK_SET);
  uint8_t *wasm_bytes = malloc(fsize);
  fread(wasm_bytes, 1, fsize, f);
  fclose(f);

  // 3. Compile the component
  wasmtime_component_t *component = NULL;
  exit_if_error("compile component",
      wasmtime_component_new(engine, wasm_bytes, fsize, &component));
  free(wasm_bytes);

  // 4. Create linker and add WASI P2
  wasmtime_component_linker_t *linker =
      wasmtime_component_linker_new(engine);
  exit_if_error("add WASI to linker",
      wasmtime_component_linker_add_wasip2(linker));

  // 5. Create store with WASI config
  wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
  wasmtime_context_t *context = wasmtime_store_context(store);
  exit_if_error("set WASI config",
      wasmtime_context_set_wasi(context, wasi_config_new()));

  // 6. Instantiate
  wasmtime_component_instance_t instance;
  exit_if_error("instantiate component",
      wasmtime_component_linker_instantiate(linker, context, component, &instance));

  // 7. Look up the exported "add" function.
  //    The export is nested: first find the "docs:adder/add@0.1.0" instance,
  //    then the "add" function within it.
  wasmtime_component_export_index_t *iface_idx =
      wasmtime_component_instance_get_export_index(
          &instance, context, NULL,
          "docs:adder/add@0.1.0", strlen("docs:adder/add@0.1.0"));
  if (iface_idx == NULL) {
    fprintf(stderr, "error: could not find export 'docs:adder/add@0.1.0'\n");
    return 1;
  }

  wasmtime_component_export_index_t *func_idx =
      wasmtime_component_instance_get_export_index(
          &instance, context, iface_idx,
          "add", strlen("add"));
  wasmtime_component_export_index_delete(iface_idx);
  if (func_idx == NULL) {
    fprintf(stderr, "error: could not find function 'add'\n");
    return 1;
  }

  wasmtime_component_func_t func;
  bool found = wasmtime_component_instance_get_func(
      &instance, context, func_idx, &func);
  wasmtime_component_export_index_delete(func_idx);
  if (!found) {
    fprintf(stderr, "error: could not get function handle for 'add'\n");
    return 1;
  }

  // 8. Call the function: add(x, y) -> u32
  wasmtime_component_val_t args[2] = {
      {.kind = WASMTIME_COMPONENT_U32, .of.u32 = x},
      {.kind = WASMTIME_COMPONENT_U32, .of.u32 = y},
  };
  wasmtime_component_val_t results[1] = {0};

  exit_if_error("call 'add'",
      wasmtime_component_func_call(&func, context, args, 2, results, 1));

  printf("%u + %u = %u\n", x, y, results[0].of.u32);

  // 9. Cleanup
  wasmtime_component_val_delete(&results[0]);
  wasmtime_store_delete(store);
  wasmtime_component_linker_delete(linker);
  wasmtime_component_delete(component);
  wasm_engine_delete(engine);

  return 0;
}

❋ The file ~/adder-demo/host.c is a pure C host that loads and runs the adder component using the Wasmtime v42.0.1 C API.

Key API calls used

Step C API Function
Enable component model wasmtime_config_wasm_component_model_set(config, true)
Compile component wasmtime_component_new(engine, buf, len, &component)
Link WASI P2 wasmtime_component_linker_add_wasip2(linker)
Instantiate wasmtime_component_linker_instantiate(linker, ctx, component, &instance)
Find nested export wasmtime_component_instance_get_export_index() (twice — once for the interface, once for the function)
Get function handle wasmtime_component_instance_get_func(&instance, ctx, idx, &func)
Call function wasmtime_component_func_call(&func, ctx, args, 2, results, 1)

</details>

gcc -o host host.c -lwasmtime && ./host 6 7 adder.wasm
# 6 + 7 = 13

<details><summary><kbd>Dockerfile</kbd> (optional)</summary>

FROM ubuntu:24.04 AS build

ARG WASMTIME_VERSION=42.0.1
ARG WASI_SDK_VERSION=27

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc libc6-dev curl xz-utils ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# Install wasmtime C API
RUN curl -sL https://github.com/bytecodealliance/wasmtime/releases/download/v${WASMTIME_VERSION}/wasmtime-v${WASMTIME_VERSION}-x86_64-linux-c-api.tar.xz \
    | tar xJ --strip-components=1 -C /usr/local \
    && ldconfig

# Install wasi-sdk (for building the guest component)
RUN curl -sLO https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.deb \
    && dpkg -i wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.deb \
    && rm wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.deb

# Install wit-bindgen and wasm-tools (pin versions)
ARG WIT_BINDGEN_VERSION=0.53.1
ARG WASM_TOOLS_VERSION=1.245.1
RUN curl -sL https://github.com/bytecodealliance/wit-bindgen/releases/download/v${WIT_BINDGEN_VERSION}/wit-bindgen-${WIT_BINDGEN_VERSION}-x86_64-linux.tar.gz \
    | tar xz --strip-components=1 -C /usr/local/bin --wildcards '*/wit-bindgen' \
    && curl -sL https://github.com/bytecodealliance/wasm-tools/releases/download/v${WASM_TOOLS_VERSION}/wasm-tools-${WASM_TOOLS_VERSION}-x86_64-linux.tar.gz \
    | tar xz --strip-components=1 -C /usr/local/bin --wildcards '*/wasm-tools'

WORKDIR /src

# Fetch guest source from upstream component-docs
ARG COMPONENT_DOCS_REV=7c1b5a9
RUN curl -sL -o world.wit \
      https://raw.githubusercontent.com/bytecodealliance/component-docs/${COMPONENT_DOCS_REV}/component-model/examples/tutorial/wit/adder/world.wit \
    && mkdir -p wit/adder && mv world.wit wit/adder/world.wit
RUN curl -sL -o component.c \
      https://raw.githubusercontent.com/bytecodealliance/component-docs/${COMPONENT_DOCS_REV}/component-model/examples/tutorial/c/adder/component.c

# Build the guest component
RUN wit-bindgen c wit/adder/world.wit
RUN /opt/wasi-sdk/bin/wasm32-wasip2-clang \
    -o adder.wasm \
    -mexec-model=reactor \
    component.c adder.c adder_component_type.o

# Build the host
COPY host.c .
RUN gcc -o /usr/local/bin/adder-host host.c -lwasmtime

# Runtime image
FROM ubuntu:24.04

COPY --from=build /usr/local/lib/libwasmtime.so /usr/local/lib/
RUN ldconfig
COPY --from=build /usr/local/bin/adder-host /usr/local/bin/adder-host
COPY --from=build /src/adder.wasm /opt/adder.wasm

ENTRYPOINT ["adder-host"]
CMD ["1", "2", "/opt/adder.wasm"]

</details>

docker build -t adder-host .
docker run --rm adder-host
# 1 + 2 = 3
docker run --rm -v .:/mnt adder-host 40 2 /mnt/adder.wasm
# 40 + 2 = 42

Note the docs describe the checked-in add.wasm https://github.com/bytecodealliance/component-docs/blob/main@{2026-2-26}/component-model/examples/example-host/add.wasm
which is out of date with the versioned/namespaced docs:adder/add@0.1.0 {add} expected by the example host

//wasm-tools component wit example-host/add.wasm
package root:component;

world root {
  export add: func(x: s32, y: s32) -> s32;
}

//cat tutorial/wit/adder/world.wit
package docs:adder@0.1.0;

interface add {
    add: func(x: u32, y: u32) -> u32;
}

world adder {
    export add;
}

However, tutorial/c/adder and tutorial/adder (rust) both work when built.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 28 2026 at 00:06):

ohAitch commented on issue #6987:

The bigger lift of course would be having a c wasmtime-bindgen generate host-side bindings, and other wasmtime sugar, so host.c could look somewhat more like the python version. I like the python version :slight_smile:

#python3 -m wasmtime.bindgen add.wasm --out-dir add
from add import Root
from wasmtime import Store

def main():
    store = Store()
    component = Root(store)
    print("1 + 2 =", component.add(1, 2))

if __name__ == '__main__':
    main()

Spitballing some API here

#include <stdio.h>
#include <stdlib.h>
#include <wasmtime.h>
#include <wit/adder.h>

int main(int argc, char *argv[]) {
  if (argc != 4) {
    fprintf(stderr, "Usage: %s <x> <y> <component.wasm>\n", argv[0]);
    return 1;
  }

  uint32_t x = (uint32_t)atoi(argv[1]);
  uint32_t y = (uint32_t)atoi(argv[2]);
  const char *path = argv[3];

  wasmtime_store_t *store =
    wasmtime_wasip2_engine_with_store((wasmtime_simple_cfg){});

  wit_docs_adder_t *adder = wit_docs_adder(
    (wit__instantiate){.store = store, .load_file = path}
  );

  // The sauce. `adder.add->add(adder,x,y)` if you *really* have to.
  uint32_t result = adder.add->add(x,y);

  printf("%u + %u = %u\n", x, y, result);

  wit__free_instance(adder);
  wasmtime_free_everything(store);
}

though of course retaining a imports_docs_adder_add_add(&instance, context, x, y) variant whose only runtime indirection/polymorphism is the Val stuff, which some future wasmtime could theoretically JIT away.


Last updated: Mar 23 2026 at 18:16 UTC