Skip to content

Commit 731b4cb

Browse files
committed
feat: build wasm in common wasm-builder
Refs: nodejs/security-wg#1236 Update to build in docker using wasm-builder image maintained in https://github.com/nodejs/wasm-builder. As a side effect this also updates the versions of the wasm tools to a newer version. undici and amaro have already been moved over and I plan to document in Node.js docs that this is the projects standard way to build WASM blobs. Signed-off-by: Michael Dawson <[email protected]>
1 parent b9f2c20 commit 731b4cb

File tree

6 files changed

+80
-40
lines changed

6 files changed

+80
-40
lines changed

.github/workflows/build.yml

+3-15
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ on:
77
branches: main
88

99
env:
10-
WASI_VERSION: 12
11-
WASI_VERSION_FULL: "12.0"
1210
WABT_VERSION: "1.0.24"
1311
EMCC_VERSION: "1.40.1-fastcomp"
1412

@@ -25,22 +23,12 @@ jobs:
2523
export PWD=$(pwd);
2624
echo "::set-output name=PROJ_ROOT::$PWD";
2725
26+
- name: Set up Docker
27+
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
28+
2829
- name: Install
2930
run: npm install
3031

31-
- name: Install wasi-sdk
32-
env:
33-
PROJ_ROOT: ${{ steps.preparation.outputs.PROJ_ROOT }}
34-
run: |
35-
cd $PROJ_ROOT;
36-
cd ../;
37-
export WASI_OS="linux"
38-
curl -sL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-${WASI_OS}.tar.gz -O
39-
# check if package downloaded
40-
ls -la
41-
tar xvf wasi-sdk-${WASI_VERSION_FULL}-${WASI_OS}.tar.gz
42-
# print clang version
43-
./wasi-sdk-${WASI_VERSION_FULL}/bin/clang --version
4432
- name: Install wabt
4533
env:
4634
PROJ_ROOT: ${{ steps.preparation.outputs.PROJ_ROOT }}

Makefile

+1-18
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,16 @@
1-
# These flags depend on the system and may be overridden
2-
WASM_CC := ../wasi-sdk-12.0/bin/clang
3-
WASM_CFLAGS := --sysroot=../wasi-sdk-12.0/share/wasi-sysroot
4-
WASM_LDFLAGS := -nostartfiles
5-
61
WASM2WAT := ../wabt/bin/wasm2wat
72
WASM_OPT := ../binaryen/bin/wasm-opt
83

9-
# These are project-specific and are expected to be kept intact
10-
WASM_EXTRA_CFLAGS := -I include-wasm/ -Wno-logical-op-parentheses -Wno-parentheses -Oz
11-
WASM_EXTRA_LDFLAGS := -Wl,-z,stack-size=13312,--no-entry,--compress-relocations,--strip-all
12-
WASM_EXTRA_LDFLAGS += -Wl,--export=__heap_base,--export=parseCJS,--export=sa
13-
WASM_EXTRA_LDFLAGS += -Wl,--export=e,--export=re,--export=es,--export=ee
14-
WASM_EXTRA_LDFLAGS += -Wl,--export=rre,--export=ree,--export=res,--export=ru,--export=us,--export=ue
15-
164
.PHONY: optimize clean
175

186
lib/lexer.wat: lib/lexer.wasm
197
$(WASM2WAT) lib/lexer.wasm -o lib/lexer.wat
208

219
lib/lexer.wasm: include-wasm/cjs-module-lexer.h src/lexer.c | lib/
22-
$(WASM_CC) $(WASM_CFLAGS) $(WASM_EXTRA_CFLAGS) \
23-
src/lexer.c -o lib/lexer.wasm \
24-
$(WASM_LDFLAGS) $(WASM_EXTRA_LDFLAGS)
10+
node build/wasm.js --docker
2511

2612
lib/:
2713
@mkdir -p $@
2814

29-
optimize: lib/lexer.wasm
30-
$(WASM_OPT) -Oz lib/lexer.wasm -o lib/lexer.wasm
31-
3215
clean:
3316
$(RM) lib/*

README.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -442,17 +442,19 @@ test/samples/*.js (3635 KiB)
442442

443443
### Wasm Build Steps
444444

445-
To build download the WASI SDK from https://github.com/WebAssembly/wasi-sdk/releases.
445+
The build uses docker and make, they must be installed first.
446446

447-
The Makefile assumes the existence of "wasi-sdk-11.0" and "wabt" (optional) as sibling folders to this project.
447+
To build the lexer wasm run `npm run build-wasm`.
448448

449-
The build through the Makefile is then run via `make lib/lexer.wasm`, which can also be triggered via `npm run build-wasm` to create `dist/lexer.js`.
449+
Optimization passes are run with [Binaryen](https://github.com/WebAssembly/binaryen)
450+
prior to publish to reduce the Web Assembly footprint.
450451

451-
On Windows it may be preferable to use the Linux subsystem.
452+
After building the lexer wasm, build the final distribution components
453+
(lexer.js and lexer.mjs) by running `npm run build`.
452454

453-
After the Web Assembly build, the CJS build can be triggered via `npm run build`.
454-
455-
Optimization passes are run with [Binaryen](https://github.com/WebAssembly/binaryen) prior to publish to reduce the Web Assembly footprint.
455+
If you need to build lib/lexer.wat (optional) you must first install
456+
[wabt](https://github.com/WebAssembly/wabt) as a sibling folder to this
457+
project. The wat file is then build by running `make lib/lexer.wat`
456458

457459
### License
458460

build/Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
lib/lexer.wasm: include-wasm/cjs-module-lexer.h src/lexer.c
2+
@mkdir -p lib
3+
clang --sysroot=/usr/share/wasi-sysroot -target wasm32-unknown-wasi src/lexer.c -I include-wasm -o lib/lexer.wasm -nostartfiles \
4+
-Wl,-z,stack-size=13312,--no-entry,--compress-relocations,--strip-all,--export=__heap_base,\
5+
--export=parseCJS,--export=sa,--export=e,--export=re,--export=es,--export=ee,--export=rre,--export=ree,--export=res,--export=ru,--export=us,--export=ue \
6+
-Wno-logical-op-parentheses -Wno-parentheses \
7+
-Oz
8+
9+
optimize: lib/lexer.wasm
10+
${WASM_OPT} -Oz lib/lexer.wasm -o lib/lexer.wasm
11+
12+
clean:
13+
rm lib/*

build/wasm.js

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use strict'
2+
3+
const WASM_BUILDER_CONTAINER = 'ghcr.io/nodejs/wasm-builder@sha256:975f391d907e42a75b8c72eb77c782181e941608687d4d8694c3e9df415a0970' // v0.0.9
4+
5+
const WASM_OPT = './wasm-opt'
6+
7+
const { execSync } = require('node:child_process')
8+
const { writeFileSync, readFileSync, existsSync, mkdirSync } = require('node:fs')
9+
const { join, resolve } = require('node:path')
10+
11+
const ROOT = resolve(__dirname, '../')
12+
13+
let platform = process.env.WASM_PLATFORM
14+
if (!platform && process.argv[2]) {
15+
platform = execSync('docker info -f "{{.OSType}}/{{.Architecture}}"').toString().trim()
16+
}
17+
18+
if (process.argv[2] === '--docker') {
19+
let cmd = `docker run --rm --platform=${platform.toString().trim()} `
20+
if (process.platform === 'linux') {
21+
cmd += ` --user ${process.getuid()}:${process.getegid()}`
22+
}
23+
24+
if (!existsSync(`${ROOT}/dist`)){
25+
mkdirSync(`${ROOT}/dist`);
26+
}
27+
28+
cmd += ` --mount type=bind,source=${ROOT}/lib,target=/home/node/build/lib \
29+
--mount type=bind,source=${ROOT}/src,target=/home/node/build/src \
30+
--mount type=bind,source=${ROOT}/dist,target=/home/node/build/dist \
31+
--mount type=bind,source=${ROOT}/node_modules,target=/home/node/build/node_modules \
32+
--mount type=bind,source=${ROOT}/build/wasm.js,target=/home/node/build/wasm.js \
33+
--mount type=bind,source=${ROOT}/build/Makefile,target=/home/node/build/Makefile \
34+
--mount type=bind,source=${ROOT}/build.js,target=/home/node/build/build.js \
35+
--mount type=bind,source=${ROOT}/package.json,target=/home/node/build/package.json \
36+
--mount type=bind,source=${ROOT}/include-wasm,target=/home/node/build/include-wasm \
37+
-t ${WASM_BUILDER_CONTAINER} node wasm.js`
38+
console.log(`> ${cmd}\n\n`)
39+
execSync(cmd, { stdio: 'inherit' })
40+
process.exit(0)
41+
}
42+
43+
const hasOptimizer = (function () {
44+
try { execSync(`${WASM_OPT} --version`); return true } catch (error) { return false }
45+
})()
46+
47+
// Build wasm binary
48+
console.log('Building wasm');
49+
execSync(`make lib/lexer.wasm`, { stdio: 'inherit' })
50+
if (hasOptimizer) {
51+
console.log('Optimizing wasm');
52+
execSync(`make optimize`, { stdio: 'inherit' })
53+
}
54+
execSync(`node build.js`, { stdio: 'inherit' })

lib/lexer.wasm

-1.65 KB
Binary file not shown.

0 commit comments

Comments
 (0)