Skip to content

Commit 164c93e

Browse files
authored
Merge pull request #1 from sysprog21/ci-wasm
Add WebAssembly CI build and GitHub Pages deployment
2 parents eda118f + b6a4943 commit 164c93e

File tree

8 files changed

+241
-98
lines changed

8 files changed

+241
-98
lines changed

.ci/build-wasm.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env bash
2+
3+
# Build WebAssembly version and prepare deployment artifacts
4+
# Usage: .ci/build-wasm.sh [build|deploy-prep]
5+
6+
set -euo pipefail
7+
8+
source "$(dirname "$0")/common.sh"
9+
10+
MODE="${1:-build}"
11+
12+
case "$MODE" in
13+
build)
14+
# Bootstrap Kconfig tools first
15+
make defconfig
16+
17+
# Apply WASM configuration using proper Kconfig flow
18+
python3 tools/kconfig/defconfig.py --kconfig configs/Kconfig configs/wasm_defconfig
19+
python3 tools/kconfig/genconfig.py --header-path src/iui_config.h configs/Kconfig
20+
21+
# Build with full Emscripten toolchain
22+
CC=emcc AR=emar RANLIB=emranlib make $PARALLEL
23+
print_success "WebAssembly build complete"
24+
;;
25+
deploy-prep)
26+
# Prepare deployment artifacts
27+
mkdir -p deploy
28+
cp assets/web/index.html deploy/
29+
cp assets/web/iui-wasm.js deploy/
30+
31+
# Copy generated files (may be in assets/web or root)
32+
if [ -f assets/web/libiui_example.js ]; then
33+
cp assets/web/libiui_example.js deploy/
34+
cp assets/web/libiui_example.wasm deploy/
35+
elif [ -f libiui_example.js ]; then
36+
cp libiui_example.js deploy/
37+
cp libiui_example.wasm deploy/
38+
else
39+
print_error "WASM artifacts not found - build may have failed"
40+
exit 1
41+
fi
42+
43+
ls -la deploy/
44+
print_success "Deployment artifacts prepared"
45+
;;
46+
*)
47+
print_error "Unknown mode: $MODE"
48+
echo "Usage: $0 [build|deploy-prep]"
49+
exit 1
50+
;;
51+
esac

.ci/common.sh

100755100644
File mode changed.

.ci/install-deps.sh

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env bash
2+
3+
# Install build dependencies for CI
4+
# Usage: .ci/install-deps.sh [sdl2|headless|format]
5+
6+
set -euo pipefail
7+
8+
source "$(dirname "$0")/common.sh"
9+
10+
MODE="${1:-sdl2}"
11+
12+
case "$MODE" in
13+
sdl2)
14+
if [ "$OS_TYPE" = "Linux" ]; then
15+
sudo apt-get update -q=2
16+
sudo apt-get install -y -q=2 --no-install-recommends libsdl2-dev python3
17+
else
18+
brew install sdl2 python3
19+
fi
20+
;;
21+
headless)
22+
if [ "$OS_TYPE" = "Linux" ]; then
23+
sudo apt-get update -q=2
24+
sudo apt-get install -y -q=2 --no-install-recommends python3
25+
else
26+
brew install python3
27+
fi
28+
;;
29+
format)
30+
if [ "$OS_TYPE" != "Linux" ]; then
31+
print_error "Formatting tools only supported on Linux"
32+
exit 1
33+
fi
34+
sudo apt-get update -q=2
35+
sudo apt-get install -y -q=2 --no-install-recommends shfmt python3-pip gnupg ca-certificates lsb-release
36+
37+
# Install clang-format-20 from LLVM repository
38+
# LLVM signing key fingerprint: 6084F3CF814B57C1CF12EFD515CF4D18AF4F7421
39+
LLVM_KEYRING=/usr/share/keyrings/llvm-archive-keyring.gpg
40+
LLVM_KEY_FP="6084F3CF814B57C1CF12EFD515CF4D18AF4F7421"
41+
TMPKEY=$(mktemp)
42+
download_to_file https://apt.llvm.org/llvm-snapshot.gpg.key "$TMPKEY"
43+
ACTUAL_FP=$(gpg --with-fingerprint --with-colons "$TMPKEY" 2>/dev/null | grep fpr | head -1 | cut -d: -f10)
44+
if [ "$ACTUAL_FP" != "$LLVM_KEY_FP" ]; then
45+
print_error "LLVM key fingerprint mismatch!"
46+
print_error "Expected: $LLVM_KEY_FP"
47+
print_error "Got: $ACTUAL_FP"
48+
rm -f "$TMPKEY"
49+
exit 1
50+
fi
51+
sudo gpg --dearmor -o "$LLVM_KEYRING" <"$TMPKEY"
52+
rm -f "$TMPKEY"
53+
54+
CODENAME=$(lsb_release -cs)
55+
echo "deb [signed-by=${LLVM_KEYRING}] https://apt.llvm.org/${CODENAME}/ llvm-toolchain-${CODENAME}-20 main" | sudo tee /etc/apt/sources.list.d/llvm-20.list
56+
sudo apt-get update -q=2
57+
sudo apt-get install -y -q=2 --no-install-recommends clang-format-20
58+
59+
# Install Python formatter (version-pinned for reproducibility)
60+
pip3 install --break-system-packages --only-binary=:all: black==25.1.0
61+
;;
62+
*)
63+
print_error "Unknown mode: $MODE"
64+
echo "Usage: $0 [sdl2|headless|format]"
65+
exit 1
66+
;;
67+
esac
68+
69+
print_success "Dependencies installed for mode: $MODE"

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Top-level EditorConfig file
2+
root = true
3+
4+
# Shell script settings - use tabs (shfmt default)
5+
[*.sh]
6+
indent_style = tab
7+
end_of_line = lf
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true

.github/workflows/main.yml

Lines changed: 72 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,7 @@ jobs:
5454
steps:
5555
- uses: actions/checkout@v6
5656
- name: Install formatting tools
57-
run: |
58-
source .ci/common.sh
59-
60-
# Install base tools
61-
sudo apt-get update -q=2
62-
sudo apt-get install -q=2 --no-install-recommends shfmt python3-pip gnupg ca-certificates
63-
64-
# Install clang-format-20 from LLVM repository with proper keyring
65-
LLVM_KEYRING=/usr/share/keyrings/llvm-archive-keyring.gpg
66-
download_to_stdout https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o "$LLVM_KEYRING"
67-
CODENAME=$(lsb_release -cs)
68-
echo "deb [signed-by=${LLVM_KEYRING}] https://apt.llvm.org/${CODENAME}/ llvm-toolchain-${CODENAME}-20 main" | sudo tee /etc/apt/sources.list.d/llvm-20.list
69-
sudo apt-get update -q=2
70-
sudo apt-get install -q=2 --no-install-recommends clang-format-20
71-
72-
# Install Python formatter
73-
pip3 install --break-system-packages black==25.1.0
57+
run: .ci/install-deps.sh format
7458
- name: Check newline at end of files
7559
run: .ci/check-newline.sh
7660
- name: Check code formatting
@@ -85,67 +69,35 @@ jobs:
8569
fail-fast: false
8670
matrix:
8771
os: [ubuntu-24.04, macos-latest]
88-
8972
steps:
90-
- name: Checkout repository
91-
uses: actions/checkout@v6
92-
93-
- name: Install dependencies (Linux)
94-
if: runner.os == 'Linux'
95-
run: |
96-
sudo apt-get update -q=2
97-
sudo apt-get install -q=2 --no-install-recommends libsdl2-dev python3
98-
99-
- name: Install dependencies (macOS)
100-
if: runner.os == 'macOS'
101-
run: |
102-
brew install sdl2 python3
103-
104-
- name: Set parallel jobs variable
73+
- uses: actions/checkout@v6
74+
- name: Install dependencies
75+
run: .ci/install-deps.sh sdl2
76+
- name: Build and test
10577
run: |
10678
source .ci/common.sh
107-
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"
108-
109-
- name: Configure and build
110-
run: |
11179
make defconfig
11280
make $PARALLEL
113-
114-
- name: Run unit tests
115-
run: make check
81+
make check
11682
11783
headless-tests:
11884
needs: [detect-code-related-file-changes, unit-tests]
11985
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
12086
timeout-minutes: 30
12187
runs-on: ubuntu-24.04
122-
12388
steps:
124-
- name: Checkout repository
125-
uses: actions/checkout@v6
126-
89+
- uses: actions/checkout@v6
12790
- name: Install dependencies
128-
run: |
129-
sudo apt-get update -q=2
130-
sudo apt-get install -q=2 --no-install-recommends python3
131-
132-
- name: Set parallel jobs variable
91+
run: .ci/install-deps.sh headless
92+
- name: Run headless tests
13393
run: |
13494
source .ci/common.sh
135-
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"
136-
137-
- name: Configure and run headless tests
138-
run: |
139-
# Generate .config file (required by Makefile)
14095
make defconfig
141-
# Uses test library built with -DIUI_MD3_RUNTIME_VALIDATION
14296
make check-headless $PARALLEL
143-
14497
- name: Save screenshots on failure
14598
if: failure()
14699
run: python3 scripts/headless-test.py --lib .build/test/libiui.a -s
147100
continue-on-error: true
148-
149101
- name: Upload test artifacts
150102
if: failure()
151103
uses: actions/upload-artifact@v6
@@ -159,25 +111,15 @@ jobs:
159111
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
160112
timeout-minutes: 30
161113
runs-on: ubuntu-24.04
162-
163114
steps:
164-
- name: Checkout repository
165-
uses: actions/checkout@v6
166-
115+
- uses: actions/checkout@v6
167116
- name: Install dependencies
168-
run: |
169-
sudo apt-get update -q=2
170-
sudo apt-get install -q=2 --no-install-recommends libsdl2-dev python3
171-
172-
- name: Set parallel jobs variable
173-
run: |
174-
source .ci/common.sh
175-
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"
176-
177-
- name: Configure and build with ASan
117+
run: .ci/install-deps.sh sdl2
118+
- name: Build and test with ASan
178119
run: |
179120
make defconfig
180-
make check SANITIZERS=1
121+
echo "CONFIG_SANITIZERS=y" >> .config
122+
make check
181123
182124
build-matrix:
183125
needs: [detect-code-related-file-changes]
@@ -194,33 +136,68 @@ jobs:
194136
modules: "CONFIG_MODULE_BASIC=y"
195137
- config: "full"
196138
modules: "CONFIG_MODULE_BASIC=y CONFIG_MODULE_INPUT=y CONFIG_MODULE_CONTAINER=y"
197-
198139
steps:
199-
- name: Checkout repository
200-
uses: actions/checkout@v6
201-
140+
- uses: actions/checkout@v6
202141
- name: Install dependencies
203-
run: |
204-
sudo apt-get update -q=2
205-
sudo apt-get install -q=2 --no-install-recommends libsdl2-dev python3
206-
207-
- name: Set parallel jobs variable
142+
run: .ci/install-deps.sh sdl2
143+
- name: Build ${{ matrix.config }}
208144
run: |
209145
source .ci/common.sh
210-
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"
211-
212-
- name: Configure ${{ matrix.config }} build
213-
run: |
214146
make defconfig
215-
# Apply module configuration
216-
for mod in ${{ matrix.modules }}; do
217-
echo "$mod" >> .config
218-
done
219-
220-
- name: Build library
221-
run: make libiui.a $PARALLEL
222-
223-
- name: Check binary size
224-
run: |
147+
for mod in ${{ matrix.modules }}; do echo "$mod" >> .config; done
148+
make libiui.a $PARALLEL
225149
size libiui.a || true
226150
ls -lh libiui.a
151+
152+
wasm-build:
153+
needs: [detect-code-related-file-changes]
154+
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
155+
timeout-minutes: 30
156+
runs-on: ubuntu-24.04
157+
steps:
158+
- uses: actions/checkout@v6
159+
- name: Cache Emscripten
160+
uses: actions/cache@v5
161+
with:
162+
path: emsdk-cache
163+
key: emsdk-4.0.3-${{ runner.os }}
164+
- name: Setup Emscripten
165+
uses: mymindstorm/setup-emsdk@v14
166+
with:
167+
version: 4.0.3
168+
actions-cache-folder: emsdk-cache
169+
- name: Build WebAssembly
170+
run: .ci/build-wasm.sh build
171+
- name: Prepare deployment
172+
run: .ci/build-wasm.sh deploy-prep
173+
- name: Upload WASM artifacts
174+
uses: actions/upload-artifact@v6
175+
with:
176+
name: wasm-build
177+
path: deploy/
178+
retention-days: 7
179+
180+
deploy-pages:
181+
needs: [wasm-build]
182+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
183+
timeout-minutes: 10
184+
runs-on: ubuntu-24.04
185+
permissions:
186+
contents: read
187+
pages: write
188+
id-token: write
189+
environment:
190+
name: github-pages
191+
url: ${{ steps.deployment.outputs.page_url }}
192+
steps:
193+
- uses: actions/download-artifact@v6
194+
with:
195+
name: wasm-build
196+
path: deploy/
197+
- uses: actions/configure-pages@v5
198+
- uses: actions/upload-pages-artifact@v3
199+
with:
200+
path: deploy/
201+
- name: Deploy to GitHub Pages
202+
id: deployment
203+
uses: actions/deploy-pages@v4

Makefile

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,14 @@ distclean: clean
272272
wasm-install:
273273
@if [ "$(CC_IS_EMCC)" = "1" ]; then \
274274
echo "Installing WebAssembly files to assets/web/..."; \
275+
if [ ! -f libiui_example ] || [ ! -f libiui_example.wasm ]; then \
276+
echo "Error: WASM build artifacts not found"; \
277+
echo "Expected: libiui_example and libiui_example.wasm"; \
278+
exit 1; \
279+
fi; \
275280
mkdir -p assets/web; \
276-
cp -f libiui_example assets/web/libiui_example.js 2>/dev/null || true; \
277-
cp -f libiui_example.wasm assets/web/ 2>/dev/null || true; \
281+
cp -f libiui_example assets/web/libiui_example.js; \
282+
cp -f libiui_example.wasm assets/web/; \
278283
echo ""; \
279284
echo "WebAssembly build installed to assets/web/"; \
280285
echo "To test, run:"; \
@@ -285,8 +290,10 @@ wasm-install:
285290
echo "Build with: make"; \
286291
fi
287292

288-
# Override all target to add post-build hook for Emscripten
293+
# Add wasm-install as post-build step for Emscripten
294+
# wasm-install depends on the actual build targets to avoid race conditions
289295
ifeq ($(CC_IS_EMCC), 1)
296+
wasm-install: $(target-y)
290297
all: wasm-install
291298
endif
292299

configs/wasm_defconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# WebAssembly (Emscripten) build configuration
2+
# Only WASM-specific overrides; other options inherited from Kconfig defaults
3+
4+
CONFIG_PORT_WASM=y
5+
CONFIG_OPTIMIZE_SIZE=y

0 commit comments

Comments
 (0)