From d2b48d2a9fd32069a44b66d24e3eafe53e8ed250 Mon Sep 17 00:00:00 2001 From: seanisom Date: Sat, 9 Sep 2023 22:32:18 -0600 Subject: [PATCH 1/7] Add initial documentation for C tooling --- component-model/src/SUMMARY.md | 1 + component-model/src/language-support/c.md | 100 ++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 component-model/src/language-support/c.md diff --git a/component-model/src/SUMMARY.md b/component-model/src/SUMMARY.md index 33991b86..1021b735 100644 --- a/component-model/src/SUMMARY.md +++ b/component-model/src/SUMMARY.md @@ -7,6 +7,7 @@ - [An Overview of WIT](./wit-overview.md) - [Language Support for Components](./language-support.md) - [Rust](./language-support/rust.md) + - [C](./language-support/c.md) - [Creating and Consuming Components](./creating-and-consuming.md) - [Authoring Components](./creating-and-consuming/authoring.md) - [Composing Components](./creating-and-consuming/composing.md) diff --git a/component-model/src/language-support/c.md b/component-model/src/language-support/c.md new file mode 100644 index 00000000..8886b12a --- /dev/null +++ b/component-model/src/language-support/c.md @@ -0,0 +1,100 @@ +## C/C++ Tooling + +### Building a Component with `wit-bindgen` and `wasm-tools` + +[`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen) is a tool to generate guest language bindings from a given `.wit` file. Although it is less integrated into language toolchains than other tools such as `cargo-component`, it can currently generate source-level bindings for `Rust`, `C`, `Java (TeaVM)`, and `TinyGo`, with the ability for more language generators to be added in the future. + +`wit-bindgen` can be used to generate C applications that can be compiled directly to Wasm modules using `clang` with a `wasm32-wasi` target. + +First, install the cli for [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen#cli-installation), [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools), and the [`WASI SDK`](https://github.com/webassembly/wasi-sdk). Note that you can also use your installed system or emscripten `clang` by building with `--target=wasm32-wasi` but you will need some artifacts from WASI SDK to enable and link that build target (more information is available in WASI SDK's docs). + +Start by generating a C skeleton from `wit-bindgen` using the [sample `add.wit` file](../../examples/add.wit): +```sh +>wit-bindgen c add.wit +Generating "example.c" +Generating "example.h" +Generating "example_component_type.o" +``` + +This has generated several files - an `example.h` (based on the name of your `world`) with the prototype of the `add` function - `int32_t example_add(int32_t x, int32_t y);`, as well as some generated code in `example.c` that interfaces with the component model ABI to call your function. Additionally, `example_component_type.o` contains object code referenced in `example.c` from an `extern` that must be linked via clang. + +Next, create an `add.c` that implements your function defined in `example.h`: +```c +#include "example.h" + +int32_t example_add(int32_t x, int32_t y) +{ + return x + y; +} +``` + +Now, you can compile the function into a Wasm module via clang: +```sh +clang add.c example.c example_component_type.o -o add-core.wasm -mexec-model=reactor +``` + +Next, you need to transform the module into a component. For this example, you can use `wasm-tools component new`: +```sh +wasm-tools component new ./add-core.wasm -o add-component.wasm +``` + +Do note this will fail if your code references any WASI APIs that must be imported. This requires an additional step as the WASI SDK still references `wasi_snapshot_preview1` APIs that are not compatible directly with components. + +For example, modifying the above to reference `printf()` would compile: +```c +#include "example.h" +#include + +int32_t example_add(int32_t x, int32_t y) +{ + int32_t result = x + y; + printf("%d", result); + return result; +} +``` + +However, the module would fail to transform to a component: +```sh +>wasm-tools component new ./add-core.wasm -o add-component.wasm +error: failed to encode a component from module + +Caused by: + 0: module requires an import interface named `wasi_snapshot_preview1` +``` + +Install the appropriate reactor adapter module [as documented here](https://github.com/bytecodealliance/wit-bindgen#creating-components-wasi) - you can either get the linked release of `wasi_snapshot_preview1.reactor.wasm` and rename it to `wasi_snapshot_preview1.wasm`, or build it directly from source in `wasmtime` following the [instructions here](https://github.com/bytecodealliance/wasmtime/tree/main/crates/wasi-preview1-component-adapter) (make sure you `git submodule update --init` first). + +Now, you can adapt preview1 to preview2 to build a component: +```sh +wasm-tools component new add-core.wasm --adapt wasi_snapshot_preview1.wasm -o add-component.wasm +``` + +Finally, you can inspect the embedded wit to see your component (including any WASI imports if necessary): +```sh +>wasm-tools component wit ./component.wasm +package root:component + +world root { + import wasi:clocks/wall-clock + import wasi:io/streams + import wasi:filesystem/types + import wasi:filesystem/preopens + import wasi:cli/stdin + import wasi:cli/stdout + import wasi:cli/stderr + import wasi:cli/terminal-input + import wasi:cli/terminal-output + import wasi:cli/terminal-stdin + import wasi:cli/terminal-stdout + import wasi:cli/terminal-stderr + + export add: func(x: s32, y: s32) -> s32 +} +``` + + +### Running a Component from C/C++ Applications + +It is not yet possible to run a Component using the `wasmtime` `c-api` - [see this issue](https://github.com/bytecodealliance/wasmtime/issues/6987). The c-api is preferred to trying to directly use the Rust crate in C++. + +However, C/C++ language guest components can be composed with components written in any other language and run by their toolchains, or even composed with a C language command component and run via the `wasmtime` CLI or any other host. \ No newline at end of file From b99ffa88f87ef6cb7971640851522206edc90118 Mon Sep 17 00:00:00 2001 From: Sean Isom Date: Sun, 10 Dec 2023 23:46:58 -0500 Subject: [PATCH 2/7] Update component-model/src/language-support/c.md Co-authored-by: Kate Goldenring --- component-model/src/language-support/c.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/component-model/src/language-support/c.md b/component-model/src/language-support/c.md index 8886b12a..3f44b9d3 100644 --- a/component-model/src/language-support/c.md +++ b/component-model/src/language-support/c.md @@ -6,7 +6,7 @@ `wit-bindgen` can be used to generate C applications that can be compiled directly to Wasm modules using `clang` with a `wasm32-wasi` target. -First, install the cli for [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen#cli-installation), [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools), and the [`WASI SDK`](https://github.com/webassembly/wasi-sdk). Note that you can also use your installed system or emscripten `clang` by building with `--target=wasm32-wasi` but you will need some artifacts from WASI SDK to enable and link that build target (more information is available in WASI SDK's docs). +First, install the CLI for [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen#cli-installation), [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools), and the [`WASI SDK`](https://github.com/webassembly/wasi-sdk). Note that you can also use your installed system or emscripten `clang` by building with `--target=wasm32-wasi` but you will need some artifacts from WASI SDK to enable and link that build target (more information is available in WASI SDK's docs). Start by generating a C skeleton from `wit-bindgen` using the [sample `add.wit` file](../../examples/add.wit): ```sh From 4964bffa1f8f1289f92c0234f362ba51266e514f Mon Sep 17 00:00:00 2001 From: Sean Isom Date: Sun, 10 Dec 2023 23:47:45 -0500 Subject: [PATCH 3/7] Update component-model/src/language-support/c.md Co-authored-by: Kate Goldenring --- component-model/src/language-support/c.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/component-model/src/language-support/c.md b/component-model/src/language-support/c.md index 3f44b9d3..ddf6e338 100644 --- a/component-model/src/language-support/c.md +++ b/component-model/src/language-support/c.md @@ -8,7 +8,7 @@ First, install the CLI for [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen#cli-installation), [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools), and the [`WASI SDK`](https://github.com/webassembly/wasi-sdk). Note that you can also use your installed system or emscripten `clang` by building with `--target=wasm32-wasi` but you will need some artifacts from WASI SDK to enable and link that build target (more information is available in WASI SDK's docs). -Start by generating a C skeleton from `wit-bindgen` using the [sample `add.wit` file](../../examples/add.wit): +Start by generating a C skeleton from `wit-bindgen` using the [sample `add.wit` file](../../examples/example-host/add.wit): ```sh >wit-bindgen c add.wit Generating "example.c" From b7b734c09f08eb6e02fd24055249837cc7a43999 Mon Sep 17 00:00:00 2001 From: Sean Isom Date: Sun, 10 Dec 2023 23:48:42 -0500 Subject: [PATCH 4/7] Update component-model/src/language-support/c.md Co-authored-by: Kate Goldenring --- component-model/src/language-support/c.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/component-model/src/language-support/c.md b/component-model/src/language-support/c.md index ddf6e338..c33ff5ec 100644 --- a/component-model/src/language-support/c.md +++ b/component-model/src/language-support/c.md @@ -71,7 +71,7 @@ wasm-tools component new add-core.wasm --adapt wasi_snapshot_preview1.wasm -o ad Finally, you can inspect the embedded wit to see your component (including any WASI imports if necessary): ```sh ->wasm-tools component wit ./component.wasm +>wasm-tools component wit add-component.wasm package root:component world root { From 73828f6f834aa72a44ae671edd9345e55c6c9af8 Mon Sep 17 00:00:00 2001 From: seanisom Date: Sat, 27 Jan 2024 22:40:41 -0500 Subject: [PATCH 5/7] Feedback on documentation --- component-model/src/language-support/c.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/component-model/src/language-support/c.md b/component-model/src/language-support/c.md index c33ff5ec..311f51a2 100644 --- a/component-model/src/language-support/c.md +++ b/component-model/src/language-support/c.md @@ -6,7 +6,9 @@ `wit-bindgen` can be used to generate C applications that can be compiled directly to Wasm modules using `clang` with a `wasm32-wasi` target. -First, install the CLI for [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen#cli-installation), [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools), and the [`WASI SDK`](https://github.com/webassembly/wasi-sdk). Note that you can also use your installed system or emscripten `clang` by building with `--target=wasm32-wasi` but you will need some artifacts from WASI SDK to enable and link that build target (more information is available in WASI SDK's docs). +First, install the CLI for [`wit-bindgen`](https://github.com/bytecodealliance/wit-bindgen#cli-installation), [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools), and the [`WASI SDK`](https://github.com/webassembly/wasi-sdk). + +The WASI SDK will install a local version of `clang` configured with a wasi-sysroot. Follow [these instructions](https://github.com/WebAssembly/wasi-sdk#use) to configure it for use. Note that you can also use your installed system or emscripten `clang` by building with `--target=wasm32-wasi` but you will need some artifacts from WASI SDK to enable and link that build target (more information is available in WASI SDK's docs). Start by generating a C skeleton from `wit-bindgen` using the [sample `add.wit` file](../../examples/example-host/add.wit): ```sh @@ -97,4 +99,6 @@ world root { It is not yet possible to run a Component using the `wasmtime` `c-api` - [see this issue](https://github.com/bytecodealliance/wasmtime/issues/6987). The c-api is preferred to trying to directly use the Rust crate in C++. -However, C/C++ language guest components can be composed with components written in any other language and run by their toolchains, or even composed with a C language command component and run via the `wasmtime` CLI or any other host. \ No newline at end of file +However, C/C++ language guest components can be composed with components written in any other language and run by their toolchains, or even composed with a C language command component and run via the `wasmtime` CLI or any other host. + +See the [Rust Tooling guide](rust.md#running-a-component-from-rust-appliacations) for instructions on how to run this component from the Rust `example-host`. \ No newline at end of file From 5adc88a2c53b5f2923b9aeb3bf79aa4e408cec30 Mon Sep 17 00:00:00 2001 From: rajsite Date: Sun, 25 Aug 2024 17:33:22 -0500 Subject: [PATCH 6/7] Update links and example cli usage --- component-model/src/SUMMARY.md | 2 +- component-model/src/introduction.md | 2 ++ component-model/src/language-support.md | 3 ++ component-model/src/language-support/c.md | 38 ++++++++++++----------- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/component-model/src/SUMMARY.md b/component-model/src/SUMMARY.md index 96e22d97..881af121 100644 --- a/component-model/src/SUMMARY.md +++ b/component-model/src/SUMMARY.md @@ -16,7 +16,7 @@ - [Language Support for Components](./language-support.md) - [Rust](./language-support/rust.md) - - [C](./language-support/c.md) + - [C/C++](./language-support/c.md) - [Javascript](./language-support/javascript.md) - [Python](./language-support/python.md) - [Go](./language-support/go.md) diff --git a/component-model/src/introduction.md b/component-model/src/introduction.md index 1d8161c2..5b5729dc 100644 --- a/component-model/src/introduction.md +++ b/component-model/src/introduction.md @@ -8,6 +8,7 @@ The WebAssembly Component Model is a broad-reaching architecture for building in | [Components] | [Python] | [Running] | | [Interfaces] | [Rust] | [Distributing] | | [Worlds] | [Go] | | +| | [C/C++][C] | | [Why Components?]: ./design/why-component-model.md [Components]: ./design/components.md @@ -18,6 +19,7 @@ The WebAssembly Component Model is a broad-reaching architecture for building in [Python]: ./language-support/python.md [Rust]: ./language-support/rust.md [Go]: ./language-support/go.md +[C]: ./language-support/c.md [Composing]: ./creating-and-consuming/composing.md [Running]: ./creating-and-consuming/running.md diff --git a/component-model/src/language-support.md b/component-model/src/language-support.md index b3e44ca7..01530216 100644 --- a/component-model/src/language-support.md +++ b/component-model/src/language-support.md @@ -30,6 +30,9 @@ components within and among toolchains. - [Python Tooling](./language-support/python.md) - [Building a Component with `componentize-py`](./language-support/python.md#building-a-component-with-componentize-py) - [Running components from Python Applications](./language-support/python.md#running-components-from-python-applications) + - [C/C++ Tooling](./language-support/c.md) + - [Building a Component with `wit-bindgen` and `wasm-tools`](./language-support/c.md#building-a-component-with-wit-bindgen-and-wasm-tools) + - [Running a Component from C/C++ Applications](./language-support/c.md#running-a-component-from-cc-applications) ## Language Agnostic Tooling diff --git a/component-model/src/language-support/c.md b/component-model/src/language-support/c.md index 311f51a2..ad2497d7 100644 --- a/component-model/src/language-support/c.md +++ b/component-model/src/language-support/c.md @@ -61,7 +61,9 @@ However, the module would fail to transform to a component: error: failed to encode a component from module Caused by: - 0: module requires an import interface named `wasi_snapshot_preview1` + 0: failed to decode world from module + 1: module was not valid + 2: module requires an import interface named `wasi_snapshot_preview1` ``` Install the appropriate reactor adapter module [as documented here](https://github.com/bytecodealliance/wit-bindgen#creating-components-wasi) - you can either get the linked release of `wasi_snapshot_preview1.reactor.wasm` and rename it to `wasi_snapshot_preview1.wasm`, or build it directly from source in `wasmtime` following the [instructions here](https://github.com/bytecodealliance/wasmtime/tree/main/crates/wasi-preview1-component-adapter) (make sure you `git submodule update --init` first). @@ -74,31 +76,31 @@ wasm-tools component new add-core.wasm --adapt wasi_snapshot_preview1.wasm -o ad Finally, you can inspect the embedded wit to see your component (including any WASI imports if necessary): ```sh >wasm-tools component wit add-component.wasm -package root:component +package root:component; world root { - import wasi:clocks/wall-clock - import wasi:io/streams - import wasi:filesystem/types - import wasi:filesystem/preopens - import wasi:cli/stdin - import wasi:cli/stdout - import wasi:cli/stderr - import wasi:cli/terminal-input - import wasi:cli/terminal-output - import wasi:cli/terminal-stdin - import wasi:cli/terminal-stdout - import wasi:cli/terminal-stderr - - export add: func(x: s32, y: s32) -> s32 + import wasi:io/error@0.2.0; + import wasi:io/streams@0.2.0; + import wasi:cli/stdin@0.2.0; + import wasi:cli/stdout@0.2.0; + import wasi:cli/stderr@0.2.0; + import wasi:cli/terminal-input@0.2.0; + import wasi:cli/terminal-output@0.2.0; + import wasi:cli/terminal-stdin@0.2.0; + import wasi:cli/terminal-stdout@0.2.0; + import wasi:cli/terminal-stderr@0.2.0; + import wasi:clocks/wall-clock@0.2.0; + import wasi:filesystem/types@0.2.0; + import wasi:filesystem/preopens@0.2.0; + + export add: func(x: s32, y: s32) -> s32; } ``` - ### Running a Component from C/C++ Applications It is not yet possible to run a Component using the `wasmtime` `c-api` - [see this issue](https://github.com/bytecodealliance/wasmtime/issues/6987). The c-api is preferred to trying to directly use the Rust crate in C++. However, C/C++ language guest components can be composed with components written in any other language and run by their toolchains, or even composed with a C language command component and run via the `wasmtime` CLI or any other host. -See the [Rust Tooling guide](rust.md#running-a-component-from-rust-appliacations) for instructions on how to run this component from the Rust `example-host`. \ No newline at end of file +See the [Rust Tooling guide](../language-support/rust.md#running-a-component-from-rust-applications) for instructions on how to run this component from the Rust `example-host`. From 9d36dc37f7196fa2a4502eeed1f6674453dfa35a Mon Sep 17 00:00:00 2001 From: rajsite Date: Tue, 27 Aug 2024 13:25:53 -0500 Subject: [PATCH 7/7] Add note to use clang from wasi-sdk --- component-model/src/language-support/c.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/component-model/src/language-support/c.md b/component-model/src/language-support/c.md index ad2497d7..9f24ffee 100644 --- a/component-model/src/language-support/c.md +++ b/component-model/src/language-support/c.md @@ -35,6 +35,8 @@ Now, you can compile the function into a Wasm module via clang: clang add.c example.c example_component_type.o -o add-core.wasm -mexec-model=reactor ``` +> Note: Use the `clang` included in the WASI SDK installation, for example at `/bin/clang`. + Next, you need to transform the module into a component. For this example, you can use `wasm-tools component new`: ```sh wasm-tools component new ./add-core.wasm -o add-component.wasm