@thi.ng/wasm-api 0.5.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2022-08-08T22:36:17Z
3
+ - **Last updated**: 2022-08-16T16:05:07Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,65 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [0.8.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.8.0) (2022-08-16)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add preliminary string handling support ([3da4efe](https://github.com/thi-ng/umbrella/commit/3da4efe))
17
+ - update/rename IWasmMemoryAccess (add string getter/setter)
18
+ - update StructField.type (add `string`)
19
+ - add CodeGenOpts.stringType option
20
+ - update codegen fns
21
+ - update TS & Zig codegen impls
22
+
23
+ ## [0.7.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.7.0) (2022-08-15)
24
+
25
+ #### 🚀 Features
26
+
27
+ - add CLI wrapper for codegens ([683a560](https://github.com/thi-ng/umbrella/commit/683a560))
28
+ - update TSOpts & TS codegen ([4f6bbbf](https://github.com/thi-ng/umbrella/commit/4f6bbbf))
29
+ - add `uppercaseEnum` option to force UC enum IDs
30
+ - update helper predicates ([65b23d4](https://github.com/thi-ng/umbrella/commit/65b23d4))
31
+
32
+ #### 🩹 Bug fixes
33
+
34
+ - allow signed ints for enum tags ([78d0822](https://github.com/thi-ng/umbrella/commit/78d0822))
35
+ - correct TS __mapArray codegen ([289b137](https://github.com/thi-ng/umbrella/commit/289b137))
36
+
37
+ ## [0.6.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.6.0) (2022-08-15)
38
+
39
+ #### 🚀 Features
40
+
41
+ - add C11 header/include file, update WasmBridge ([a67dc00](https://github.com/thi-ng/umbrella/commit/a67dc00))
42
+ - migrate headers/includes to /include
43
+ - rename "core" import section => "wasmapi"
44
+ - rename WasmBridge.core => WasmBridge.api
45
+ - update pkg file
46
+ - update codegens, add opts, fix alignments ([5c1fec5](https://github.com/thi-ng/umbrella/commit/5c1fec5))
47
+ - add global CodeGenOpts
48
+ - update generateTypes() to consider new opts
49
+ - add global USIZE type (for pointer sizes & codegens)
50
+ - add options for Zig codegen (extra debug helpers)
51
+ - simplify TS codegen
52
+ - fix sizeOf() for struct fields
53
+ - make prepareType() idempotent
54
+ - add bindings code generator framework ([17ee06f](https://github.com/thi-ng/umbrella/commit/17ee06f))
55
+ - add/update deps
56
+ - add preliminary codegens for Zig & TS
57
+ - add supporting types & utils
58
+ - add generateTypes() codegen facade fn
59
+ - update allocate/free() fns, update Zig core API ([8a55989](https://github.com/thi-ng/umbrella/commit/8a55989))
60
+ - add _wasm_free() Zig impl
61
+ - add printFmt() Zig fn
62
+ - update WasmBridge.allocate() (add clear option)
63
+ - update WasmBridge.free()
64
+ - ensure memory in WasmBridge.getString()
65
+ - add/update docstrings
66
+
67
+ #### ♻️ Refactoring
68
+
69
+ - extract WasmMemViews interface, update test WASM ([4c73e65](https://github.com/thi-ng/umbrella/commit/4c73e65))
70
+
12
71
  ## [0.5.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.5.0) (2022-08-08)
13
72
 
14
73
  #### 🚀 Features
package/README.md CHANGED
@@ -12,30 +12,53 @@ This project is part of the
12
12
  - [About](#about)
13
13
  - [Custom API modules](#custom-api-modules)
14
14
  - [Object indices & handles](#object-indices--handles)
15
+ - [Data bindings & code generators](#data-bindings--code-generators)
16
+ - [CLI generator](#cli-generator)
17
+ - [Data type definitions](#data-type-definitions)
18
+ - [Example usage](#example-usage)
19
+ - [String handling](#string-handling)
15
20
  - [Status](#status)
16
21
  - [Installation](#installation)
17
22
  - [Dependencies](#dependencies)
18
23
  - [API](#api)
24
+ - [Basic usage example](#basic-usage-example)
25
+ - [Zig version](#zig-version)
26
+ - [C11 version](#c11-version)
19
27
  - [Authors](#authors)
20
28
  - [License](#license)
21
29
 
22
30
  ## About
23
31
 
24
- Modular, extensible API bridge and generic glue code between JS & WebAssembly.
32
+ Generic, modular, extensible API bridge, glue code and bindings code generator for hybrid JS & WebAssembly projects.
25
33
 
26
- This package provides a small, generic and modular
27
- [`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html)
28
- class as interop basis and a much reduced boilerplate for hybrid JS/WebAssembly
29
- applications. At the moment only a minimal core API is provided (i.e. for debug
30
- output, string, pointer, typed array accessors [8/16/32/64 bit (u)ints, 32/64
31
- bit floats]), but in the future we aim to also supply support modules for DOM
32
- manipulation, WebGL, WebGPU, WebAudio etc.
34
+ This package provides a the following:
33
35
 
34
- In general, all languages with a WebAssembly target are supported, however
35
- currently only bindings for [Zig](https://ziglang.org) are included.
36
+ 1. A small, generic and modular
37
+ [`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html)
38
+ class as interop basis and much reduced boilerplate for hybrid JS/WebAssembly
39
+ applications.
40
+ 2. A minimal core API for debug output, string, pointer, typed array accessors
41
+ for 8/16/32/64 bit (u)ints and 32/64 bit floats. In the future we aim to also
42
+ supply support modules for DOM manipulation, WebGL, WebGPU, WebAudio etc.
43
+ 3. [Include files for C11/C++ and
44
+ Zig](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api/include),
45
+ defining WASM imports of the JS [core
46
+ API](https://docs.thi.ng/umbrella/wasm-api/interfaces/CoreAPI.html) defined
47
+ by this package
48
+ 4. Extensible shared datatype code generators for (currently)
49
+ [Zig](https://ziglang.org) & TypeScript. The latter also generates fully type
50
+ checked memory-mapped accessors of WASM-side data. In general, all languages
51
+ with a WebAssembly target are supported, however currently only bindings for
52
+ these few langs are included.
53
+ 5. [CLI frontend/utility](#cli-generator) to invoke the code generator(s)
36
54
 
37
55
  ### Custom API modules
38
56
 
57
+ The [`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html) is extensible via custom defined API modules. Such API extensions
58
+ will consist of a collection of JS/TS functions & variables, their related
59
+ counterparts (import definitions) for the WASM target and (optionally) some
60
+ shared data types ([bindings for which _can_ be generated by this package too](#data-bindings--code-generators)).
61
+
39
62
  On the JS side, custom API modules can be easily integrated via the [`IWasmAPI`
40
63
  interface](https://docs.thi.ng/umbrella/wasm-api/interfaces/IWasmAPI.html). The
41
64
  following example provides a brief overview:
@@ -113,12 +136,12 @@ export fn test_randomVec2() void {
113
136
 
114
137
  Since only numeric values can be exchanged between the WASM module and the JS
115
138
  host, any JS native objects the WASM side might want to be working with must be
116
- managed in JS. For this purpose the [`ObjectIndex`
139
+ managed manually in JS. For this purpose the [`ObjectIndex`
117
140
  class](https://docs.thi.ng/umbrella/wasm-api/classes/ObjectIndex.html) can be
118
141
  used by API modules to handle ID generation (incl. recycling, using
119
142
  [@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen))
120
- & indexing of different types of JS objects/values. Only the numeric IDs will
121
- then need to be exchanged with the WASM module...
143
+ and the indexing of different types of JS objects/values. Only the numeric IDs
144
+ (handles) will then need to be exchanged with the WASM module...
122
145
 
123
146
  ```ts
124
147
  import { ObjectIndex } from "@thi.ng/wasm-api";
@@ -156,6 +179,278 @@ canvases.delete(0);
156
179
  // true
157
180
  ```
158
181
 
182
+ ### Data bindings & code generators
183
+
184
+ The package provides an extensible codegeneration framework to simplify the
185
+ bilateral design & exchange of data structures shared between the WASM & JS host
186
+ env. Currently, code generators for TypeScript & Zig are supplied (more are
187
+ planned). A CLI wrapper is worked on too.
188
+
189
+ #### CLI generator
190
+
191
+ The package includes a [small CLI
192
+ wrapper](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/src/cli.ts)
193
+ to invoke the codegenerator(s) from JSON type definitions and to write the
194
+ generated source code(s) to different files:
195
+
196
+ ```text
197
+ $ npx @thi.ng/wasm-api
198
+
199
+ █ █ █ │
200
+ ██ █ │
201
+ █ █ █ █ █ █ █ █ │ @thi.ng/wasm-api 0.6.0
202
+ █ █ █ █ █ █ █ █ █ │ Multi-language data bindings code generator
203
+ █ │
204
+ █ █ │
205
+
206
+ usage: wasm-api [OPTS] JSON-INPUT-FILE(S) ...
207
+ wasm-api --help
208
+
209
+ Flags:
210
+
211
+ -d, --debug enable debug output
212
+ --dry-run enable dry run (don't overwrite files)
213
+
214
+ Main:
215
+
216
+ -c FILE, --config FILE JSON config file with codegen options
217
+ -l ID[,..], --lang ID[,..] [multiple] target language: "ts", "zig" (default: ["ts","zig"])
218
+ -o FILE, --out FILE [multiple] output file path
219
+ ```
220
+
221
+ By default, the CLI generates sources for both TypeScript and Zig (in this
222
+ order!). Order is important, since the output file paths must be given in the
223
+ same order as the target languages. It's recommended to be more explicit. An
224
+ example invocation looks like:
225
+
226
+ ```bash
227
+ wasm-api --config codegen-opts.json \
228
+ --lang ts -o src/generated.ts \
229
+ --lang zig -o src.zig/generated.zig \
230
+ typedefs.json
231
+ ```
232
+
233
+ The structure of the config file is as follows (all optional):
234
+
235
+ ```text
236
+ {
237
+ global: { ... },
238
+ ts: { ... },
239
+ zig: { ... },
240
+ }
241
+ ```
242
+
243
+ More details about possible
244
+ [`global`](https://docs.thi.ng/umbrella/wasm-api/interfaces/CodeGenOpts.html),
245
+ [`ts`](https://docs.thi.ng/umbrella/wasm-api/interfaces/TSOpts.html) and
246
+ [`zig`](https://docs.thi.ng/umbrella/wasm-api/interfaces/ZigOpts.html) config
247
+ options & values.
248
+
249
+ #### Data type definitions
250
+
251
+ Currently, the code generator supports structs and enums. See API docs for
252
+ further details:
253
+
254
+ - [`Enum`](https://docs.thi.ng/umbrella/wasm-api/interfaces/Enum.html)
255
+ - [`EnumValue`](https://docs.thi.ng/umbrella/wasm-api/interfaces/EnumValue.html)
256
+ - [`Struct`](https://docs.thi.ng/umbrella/wasm-api/interfaces/Struct.html)
257
+ - [`StructField`](https://docs.thi.ng/umbrella/wasm-api/interfaces/StructField.html)
258
+ - [`TopLevelType`](https://docs.thi.ng/umbrella/wasm-api/interfaces/TopLevelType.html)
259
+
260
+ #### Example usage
261
+
262
+ Below is an example file with JSON type definitions and the resulting source
263
+ codes:
264
+
265
+ **⬇︎ CLICK TO EXPAND EACH CODE BLOCK ⬇︎**
266
+
267
+ <details><summary>types.json (Type definitions)</summary>
268
+
269
+ ```json
270
+ [
271
+ {
272
+ "name": "Foo",
273
+ "type": "struct",
274
+ "doc": "Example struct",
275
+ "auto": true,
276
+ "fields": [
277
+ { "name": "id", "type": "u8", "doc": "Unique ID" },
278
+ { "name": "bars", "type": "Bar", "tag": "array", "len": 3 },
279
+ { "name": "color", "type": "f32", "tag": "vec", "len": 4 }
280
+ ]
281
+ },
282
+ {
283
+ "name": "Bar",
284
+ "type": "struct",
285
+ "fields": [
286
+ { "name": "kind", "type": "Kind" },
287
+ { "name": "flags", "type": "u32" }
288
+ ]
289
+ },
290
+ {
291
+ "name": "Kind",
292
+ "type": "enum",
293
+ "tag": "u16",
294
+ "values": [
295
+ "unknown",
296
+ { "name": "good", "value": 100 },
297
+ { "name": "best", "value": 1000 }
298
+ ]
299
+ }
300
+ ]
301
+ ```
302
+ </details>
303
+
304
+ <details><summary>generated.ts (generated TypeScript source)</summary>
305
+
306
+ ```ts
307
+ /** Generated by @thi.ng/wasm-api at 2022-08-15T22:32:21.189Z - DO NOT EDIT! */
308
+
309
+ import type { WasmTypeBase, WasmTypeConstructor } from "@thi.ng/wasm-api";
310
+
311
+ /** Example struct */
312
+ export interface Foo extends WasmTypeBase {
313
+ color: Float32Array;
314
+ bars: Bar[];
315
+ /** Unique ID */
316
+ id: number;
317
+ }
318
+
319
+ export const $Foo: WasmTypeConstructor<Foo> = (mem) => ({
320
+ get align() { return 16; },
321
+ get size() { return 48; },
322
+ instance: (base) => ({
323
+ get __base() { return base; },
324
+ get __bytes() { return mem.u8.subarray(base, base + 48); },
325
+ get color(): Float32Array {
326
+ const addr = base >>> 2;
327
+ return mem.f32.subarray(addr, addr + 4);
328
+ },
329
+ get bars(): Bar[] {
330
+ const addr = (base + 16);
331
+ const inst = $Bar(mem);
332
+ const slice: Bar[] = [];
333
+ for(let i = 0; i < 3; i++) slice.push(inst.instance(addr + i * 24));
334
+ return slice;
335
+ },
336
+ get id(): number {
337
+ return mem.u8[(base + 40)];
338
+ },
339
+ set id(x: number) {
340
+ mem.u8[(base + 40)] = x;
341
+ },
342
+ })
343
+ });
344
+
345
+ export interface Bar extends WasmTypeBase {
346
+ kind: Kind;
347
+ flags: number;
348
+ }
349
+
350
+ export const $Bar: WasmTypeConstructor<Bar> = (mem) => ({
351
+ get align() { return 4; },
352
+ get size() { return 8; },
353
+ instance: (base) => ({
354
+ get __base() { return base; },
355
+ get __bytes() { return mem.u8.subarray(base, base + 8); },
356
+ get kind(): Kind {
357
+ return mem.u16[base >>> 1];
358
+ },
359
+ set kind(x: Kind) {
360
+ mem.u16[base >>> 1] = x;
361
+ },
362
+ get flags(): number {
363
+ return mem.u32[(base + 4) >>> 2];
364
+ },
365
+ set flags(x: number) {
366
+ mem.u32[(base + 4) >>> 2] = x;
367
+ },
368
+ })
369
+ });
370
+
371
+ export enum Kind {
372
+ UNKNOWN,
373
+ GOOD = 100,
374
+ BEST = 1000,
375
+ }
376
+ ```
377
+ </details>
378
+
379
+ <details><summary>generated.zig (generated Zig source)</summary>
380
+
381
+ ```zig
382
+ //! Generated by @thi.ng/wasm-api at 2022-08-15T22:32:21.191Z - DO NOT EDIT!
383
+
384
+ /// Example struct
385
+ pub const Foo = struct {
386
+ color: @Vector(4, f32),
387
+ bars: [3]Bar,
388
+ /// Unique ID
389
+ id: u8,
390
+ };
391
+
392
+ pub const Bar = struct {
393
+ kind: Kind,
394
+ flags: u32,
395
+ };
396
+
397
+ pub const Kind = enum(u16) {
398
+ unknown,
399
+ good = 100,
400
+ best = 1000,
401
+ };
402
+ ```
403
+ </details>
404
+
405
+ On the TypeScript/JS side, the memory-mapped wrappers (e.g. `$Foo` and `$Bar`)
406
+ can be used in combination with the `WasmBridge` to obtain fully typed views
407
+ (according to the generated types) of the underlying WASM memory. Basic usage is
408
+ like:
409
+
410
+ ```ts
411
+ import { WasmBridge } from "@thi.ng/wasm-api";
412
+ import { $Foo, Kind } from "./generated.ts";
413
+
414
+ const bridge = new WasmBridge();
415
+ // bridge initialization omitted here (see other examples below)
416
+ // ...
417
+
418
+ // Create an instance using the bridge's memory views
419
+ // and mapping a `Foo` struct from given address
420
+ // (e.g. obtained from an exported WASM function/value)
421
+ const foo = $Foo(bridge).instance(0x10000);
422
+
423
+ // then use like normal JS object
424
+ foo.color
425
+ // Float32Array(4) [0.1, 0.2, 0.3, 0.4]
426
+
427
+ // this even applies to arrays using other types
428
+ foo.bars[2].kind = Kind.BEST;
429
+
430
+ // IMPORTANT: any modifications like this are directly
431
+ // applied to the underlying WASM memory...
432
+ ```
433
+
434
+ **IMPORTANT:** Struct field setters are currently only supported for single
435
+ values, incl. enums, strings, structs. The latter 2 will always be copied by
436
+ value (mem copy). Arrays or slices of strings do not currently provide write
437
+ access...
438
+
439
+ ### String handling
440
+
441
+ Most low-level languages deal with strings very differently and alas there's no
442
+ general standard. Some have UTF-8/16 support, others don't. In some languages
443
+ (incl. C & Zig), strings are stored as zero terminated, in others they aren't...
444
+ It's outside the scope of this package to provide an allround out-of-the-box
445
+ solution. However, the code generators provide the global `stringType` option to
446
+ interpret the `string` type of a struct field in different ways:
447
+
448
+ - `slice` (default): Considers strings as Zig-style slices (i.e. pointer + length)
449
+ - `ptr`: Considers strings as C-style raw `*char` pointer (without any length)
450
+
451
+ Note: If setting this global option to `ptr`, it also has to be stated for the
452
+ TypeScript code generator explicitly.
453
+
159
454
  ### Status
160
455
 
161
456
  **ALPHA** - bleeding edge / work-in-progress
@@ -185,12 +480,22 @@ node --experimental-repl-await
185
480
  > const wasmApi = await import("@thi.ng/wasm-api");
186
481
  ```
187
482
 
188
- Package sizes (gzipped, pre-treeshake): ESM: 1.61 KB
483
+ Package sizes (gzipped, pre-treeshake): ESM: 4.32 KB
484
+
485
+ **IMPORTANT:** The package includes various code generators and supporting
486
+ functions which are NOT required during runtime. Hence the actual package size
487
+ in production will be MUCH smaller!
189
488
 
190
489
  ## Dependencies
191
490
 
192
491
  - [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
492
+ - [@thi.ng/args](https://github.com/thi-ng/umbrella/tree/develop/packages/args)
493
+ - [@thi.ng/binary](https://github.com/thi-ng/umbrella/tree/develop/packages/binary)
494
+ - [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
495
+ - [@thi.ng/compare](https://github.com/thi-ng/umbrella/tree/develop/packages/compare)
496
+ - [@thi.ng/defmulti](https://github.com/thi-ng/umbrella/tree/develop/packages/defmulti)
193
497
  - [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)
498
+ - [@thi.ng/file-io](https://github.com/thi-ng/umbrella/tree/develop/packages/file-io)
194
499
  - [@thi.ng/hex](https://github.com/thi-ng/umbrella/tree/develop/packages/hex)
195
500
  - [@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen)
196
501
  - [@thi.ng/logger](https://github.com/thi-ng/umbrella/tree/develop/packages/logger)
@@ -199,6 +504,8 @@ Package sizes (gzipped, pre-treeshake): ESM: 1.61 KB
199
504
 
200
505
  [Generated API docs](https://docs.thi.ng/umbrella/wasm-api/)
201
506
 
507
+ ## Basic usage example
508
+
202
509
  ```ts
203
510
  import { WasmBridge, WasmExports } from "@thi.ng/wasm-api";
204
511
  import { readFileSync } from "fs";
@@ -223,12 +530,20 @@ interface App extends WasmExports {
223
530
  })();
224
531
  ```
225
532
 
533
+ ### Zig version
534
+
535
+ Requires [Zig](https://ziglang.org) to be installed:
536
+
226
537
  ```zig
227
538
  //! Example Zig application (hello.zig)
228
539
 
229
540
  /// import externals
230
541
  /// see build command for configuration
231
542
  const js = @import("wasmapi");
543
+ const std = @import("std");
544
+
545
+ // set custom memory allocator (here to disable)
546
+ pub const WASM_ALLOCATOR: ?std.mem.Allocator = null;
232
547
 
233
548
  export fn start() void {
234
549
  js.printStr("hello world!");
@@ -242,7 +557,7 @@ folder):
242
557
  ```bash
243
558
  # compile WASM binary
244
559
  zig build-lib \
245
- --pkg-begin wasmapi node_modules/@thi.ng/wasm-api/zig/core.zig --pkg-end \
560
+ --pkg-begin wasmapi node_modules/@thi.ng/wasm-api/include/wasmapi.zig --pkg-end \
246
561
  -target wasm32-freestanding \
247
562
  -O ReleaseSmall -dynamic --strip \
248
563
  hello.zig
@@ -257,18 +572,112 @@ The resulting WASM:
257
572
  (module
258
573
  (type $i32_i32_=>_none (func (param i32 i32)))
259
574
  (type $none_=>_none (func))
260
- (import "core" "_printStr" (func $fimport$0 (param i32 i32)))
575
+ (type $i32_=>_i32 (func (param i32) (result i32)))
576
+ (import "wasmapi" "_printStr" (func $fimport$0 (param i32 i32)))
261
577
  (global $global$0 (mut i32) (i32.const 65536))
262
578
  (memory $0 2)
263
579
  (data (i32.const 65536) "hello world!\00")
264
580
  (export "memory" (memory $0))
265
581
  (export "start" (func $0))
582
+ (export "_wasm_allocate" (func $1))
583
+ (export "_wasm_free" (func $2))
266
584
  (func $0
267
585
  (call $fimport$0
268
586
  (i32.const 65536)
269
587
  (i32.const 12)
270
588
  )
271
589
  )
590
+ (func $1 (param $0 i32) (result i32)
591
+ (i32.const 0)
592
+ )
593
+ (func $2 (param $0 i32) (param $1 i32)
594
+ )
595
+ )
596
+ ```
597
+
598
+ ### C11 version
599
+
600
+ Requires [Emscripten](https://emscripten.org/) to be installed:
601
+
602
+ ```c
603
+ #include <wasmapi.h>
604
+
605
+ void WASM_KEEP start() {
606
+ wasm_printStr0("hello world!");
607
+ }
608
+ ```
609
+
610
+ Building the WASM module:
611
+
612
+ ```bash
613
+ emcc -Os -Inode_modules/@thi.ng/wasm-api/include -DWASMAPI_NO_MALLOC \
614
+ -sERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry \
615
+ -o hello.wasm hello.c
616
+ ```
617
+
618
+ Resulting WASM:
619
+
620
+ ```wasm
621
+ (module
622
+ (type $i32_=>_none (func (param i32)))
623
+ (type $none_=>_none (func))
624
+ (type $i32_=>_i32 (func (param i32) (result i32)))
625
+ (type $none_=>_i32 (func (result i32)))
626
+ (import "wasmapi" "_printStr0" (func $fimport$0 (param i32)))
627
+ (global $global$0 (mut i32) (i32.const 5243936))
628
+ (memory $0 256 256)
629
+ (data (i32.const 1024) "hello world!")
630
+ (table $0 2 2 funcref)
631
+ (elem (i32.const 1) $0)
632
+ (export "memory" (memory $0))
633
+ (export "_wasm_allocate" (func $1))
634
+ (export "_wasm_free" (func $2))
635
+ (export "start" (func $3))
636
+ (export "__indirect_function_table" (table $0))
637
+ (export "_initialize" (func $0))
638
+ (export "__errno_location" (func $7))
639
+ (export "stackSave" (func $4))
640
+ (export "stackRestore" (func $5))
641
+ (export "stackAlloc" (func $6))
642
+ (func $0
643
+ (nop)
644
+ )
645
+ (func $1 (param $0 i32) (result i32)
646
+ (i32.const 0)
647
+ )
648
+ (func $2 (param $0 i32)
649
+ (nop)
650
+ )
651
+ (func $3
652
+ (call $fimport$0
653
+ (i32.const 1024)
654
+ )
655
+ )
656
+ (func $4 (result i32)
657
+ (global.get $global$0)
658
+ )
659
+ (func $5 (param $0 i32)
660
+ (global.set $global$0
661
+ (local.get $0)
662
+ )
663
+ )
664
+ (func $6 (param $0 i32) (result i32)
665
+ (global.set $global$0
666
+ (local.tee $0
667
+ (i32.and
668
+ (i32.sub
669
+ (global.get $global$0)
670
+ (local.get $0)
671
+ )
672
+ (i32.const -16)
673
+ )
674
+ )
675
+ )
676
+ (local.get $0)
677
+ )
678
+ (func $7 (result i32)
679
+ (i32.const 1040)
680
+ )
272
681
  )
273
682
  ```
274
683