Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .ci/build-wasm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash

# Build WebAssembly version and prepare deployment artifacts
# Usage: .ci/build-wasm.sh [build|deploy-prep]

set -euo pipefail

source "$(dirname "$0")/common.sh"

MODE="${1:-build}"

case "$MODE" in
build)
# Bootstrap Kconfig tools first
make defconfig

# Apply WASM configuration using proper Kconfig flow
python3 tools/kconfig/defconfig.py --kconfig configs/Kconfig configs/wasm_defconfig
python3 tools/kconfig/genconfig.py --header-path src/iui_config.h configs/Kconfig

# Build with full Emscripten toolchain
CC=emcc AR=emar RANLIB=emranlib make $PARALLEL
print_success "WebAssembly build complete"
;;
deploy-prep)
# Prepare deployment artifacts
mkdir -p deploy
cp assets/web/index.html deploy/
cp assets/web/iui-wasm.js deploy/

# Copy generated files (may be in assets/web or root)
if [ -f assets/web/libiui_example.js ]; then
cp assets/web/libiui_example.js deploy/
cp assets/web/libiui_example.wasm deploy/
elif [ -f libiui_example.js ]; then
cp libiui_example.js deploy/
cp libiui_example.wasm deploy/
else
print_error "WASM artifacts not found - build may have failed"
exit 1
fi

ls -la deploy/
print_success "Deployment artifacts prepared"
;;
*)
print_error "Unknown mode: $MODE"
echo "Usage: $0 [build|deploy-prep]"
exit 1
;;
esac
Empty file modified .ci/common.sh
100755 → 100644
Empty file.
69 changes: 69 additions & 0 deletions .ci/install-deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env bash

# Install build dependencies for CI
# Usage: .ci/install-deps.sh [sdl2|headless|format]

set -euo pipefail

source "$(dirname "$0")/common.sh"

MODE="${1:-sdl2}"

case "$MODE" in
sdl2)
if [ "$OS_TYPE" = "Linux" ]; then
sudo apt-get update -q=2
sudo apt-get install -y -q=2 --no-install-recommends libsdl2-dev python3
else
brew install sdl2 python3
fi
;;
headless)
if [ "$OS_TYPE" = "Linux" ]; then
sudo apt-get update -q=2
sudo apt-get install -y -q=2 --no-install-recommends python3
else
brew install python3
fi
;;
format)
if [ "$OS_TYPE" != "Linux" ]; then
print_error "Formatting tools only supported on Linux"
exit 1
fi
sudo apt-get update -q=2
sudo apt-get install -y -q=2 --no-install-recommends shfmt python3-pip gnupg ca-certificates lsb-release

# Install clang-format-20 from LLVM repository
# LLVM signing key fingerprint: 6084F3CF814B57C1CF12EFD515CF4D18AF4F7421
LLVM_KEYRING=/usr/share/keyrings/llvm-archive-keyring.gpg
LLVM_KEY_FP="6084F3CF814B57C1CF12EFD515CF4D18AF4F7421"
TMPKEY=$(mktemp)
download_to_file https://apt.llvm.org/llvm-snapshot.gpg.key "$TMPKEY"
ACTUAL_FP=$(gpg --with-fingerprint --with-colons "$TMPKEY" 2>/dev/null | grep fpr | head -1 | cut -d: -f10)
if [ "$ACTUAL_FP" != "$LLVM_KEY_FP" ]; then
print_error "LLVM key fingerprint mismatch!"
print_error "Expected: $LLVM_KEY_FP"
print_error "Got: $ACTUAL_FP"
rm -f "$TMPKEY"
exit 1
fi
sudo gpg --dearmor -o "$LLVM_KEYRING" <"$TMPKEY"
rm -f "$TMPKEY"

CODENAME=$(lsb_release -cs)
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
sudo apt-get update -q=2
sudo apt-get install -y -q=2 --no-install-recommends clang-format-20

# Install Python formatter (version-pinned for reproducibility)
pip3 install --break-system-packages --only-binary=:all: black==25.1.0
;;
*)
print_error "Unknown mode: $MODE"
echo "Usage: $0 [sdl2|headless|format]"
exit 1
;;
esac

print_success "Dependencies installed for mode: $MODE"
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Top-level EditorConfig file
root = true

# Shell script settings - use tabs (shfmt default)
[*.sh]
indent_style = tab
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
167 changes: 72 additions & 95 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Install formatting tools
run: |
source .ci/common.sh

# Install base tools
sudo apt-get update -q=2
sudo apt-get install -q=2 --no-install-recommends shfmt python3-pip gnupg ca-certificates

# Install clang-format-20 from LLVM repository with proper keyring
LLVM_KEYRING=/usr/share/keyrings/llvm-archive-keyring.gpg
download_to_stdout https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o "$LLVM_KEYRING"
CODENAME=$(lsb_release -cs)
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
sudo apt-get update -q=2
sudo apt-get install -q=2 --no-install-recommends clang-format-20

# Install Python formatter
pip3 install --break-system-packages black==25.1.0
run: .ci/install-deps.sh format
- name: Check newline at end of files
run: .ci/check-newline.sh
- name: Check code formatting
Expand All @@ -85,67 +69,35 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-24.04, macos-latest]

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update -q=2
sudo apt-get install -q=2 --no-install-recommends libsdl2-dev python3

- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install sdl2 python3

- name: Set parallel jobs variable
- uses: actions/checkout@v6
- name: Install dependencies
run: .ci/install-deps.sh sdl2
- name: Build and test
run: |
source .ci/common.sh
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"

- name: Configure and build
run: |
make defconfig
make $PARALLEL

- name: Run unit tests
run: make check
make check

headless-tests:
needs: [detect-code-related-file-changes, unit-tests]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 30
runs-on: ubuntu-24.04

steps:
- name: Checkout repository
uses: actions/checkout@v6

- uses: actions/checkout@v6
- name: Install dependencies
run: |
sudo apt-get update -q=2
sudo apt-get install -q=2 --no-install-recommends python3

- name: Set parallel jobs variable
run: .ci/install-deps.sh headless
- name: Run headless tests
run: |
source .ci/common.sh
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"

- name: Configure and run headless tests
run: |
# Generate .config file (required by Makefile)
make defconfig
# Uses test library built with -DIUI_MD3_RUNTIME_VALIDATION
make check-headless $PARALLEL

- name: Save screenshots on failure
if: failure()
run: python3 scripts/headless-test.py --lib .build/test/libiui.a -s
continue-on-error: true

- name: Upload test artifacts
if: failure()
uses: actions/upload-artifact@v6
Expand All @@ -159,25 +111,15 @@ jobs:
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 30
runs-on: ubuntu-24.04

steps:
- name: Checkout repository
uses: actions/checkout@v6

- uses: actions/checkout@v6
- name: Install dependencies
run: |
sudo apt-get update -q=2
sudo apt-get install -q=2 --no-install-recommends libsdl2-dev python3

- name: Set parallel jobs variable
run: |
source .ci/common.sh
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"

- name: Configure and build with ASan
run: .ci/install-deps.sh sdl2
- name: Build and test with ASan
run: |
make defconfig
make check SANITIZERS=1
echo "CONFIG_SANITIZERS=y" >> .config
make check

build-matrix:
needs: [detect-code-related-file-changes]
Expand All @@ -194,33 +136,68 @@ jobs:
modules: "CONFIG_MODULE_BASIC=y"
- config: "full"
modules: "CONFIG_MODULE_BASIC=y CONFIG_MODULE_INPUT=y CONFIG_MODULE_CONTAINER=y"

steps:
- name: Checkout repository
uses: actions/checkout@v6

- uses: actions/checkout@v6
- name: Install dependencies
run: |
sudo apt-get update -q=2
sudo apt-get install -q=2 --no-install-recommends libsdl2-dev python3

- name: Set parallel jobs variable
run: .ci/install-deps.sh sdl2
- name: Build ${{ matrix.config }}
run: |
source .ci/common.sh
echo "PARALLEL=$PARALLEL" >> "$GITHUB_ENV"

- name: Configure ${{ matrix.config }} build
run: |
make defconfig
# Apply module configuration
for mod in ${{ matrix.modules }}; do
echo "$mod" >> .config
done

- name: Build library
run: make libiui.a $PARALLEL

- name: Check binary size
run: |
for mod in ${{ matrix.modules }}; do echo "$mod" >> .config; done
make libiui.a $PARALLEL
size libiui.a || true
ls -lh libiui.a

wasm-build:
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 30
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Cache Emscripten
uses: actions/cache@v5
with:
path: emsdk-cache
key: emsdk-4.0.3-${{ runner.os }}
- name: Setup Emscripten
uses: mymindstorm/setup-emsdk@v14
with:
version: 4.0.3
actions-cache-folder: emsdk-cache
- name: Build WebAssembly
run: .ci/build-wasm.sh build
- name: Prepare deployment
run: .ci/build-wasm.sh deploy-prep
- name: Upload WASM artifacts
uses: actions/upload-artifact@v6
with:
name: wasm-build
path: deploy/
retention-days: 7

deploy-pages:
needs: [wasm-build]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
timeout-minutes: 10
runs-on: ubuntu-24.04
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/download-artifact@v6
with:
name: wasm-build
path: deploy/
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: deploy/
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,14 @@ distclean: clean
wasm-install:
@if [ "$(CC_IS_EMCC)" = "1" ]; then \
echo "Installing WebAssembly files to assets/web/..."; \
if [ ! -f libiui_example ] || [ ! -f libiui_example.wasm ]; then \
echo "Error: WASM build artifacts not found"; \
echo "Expected: libiui_example and libiui_example.wasm"; \
exit 1; \
fi; \
mkdir -p assets/web; \
cp -f libiui_example assets/web/libiui_example.js 2>/dev/null || true; \
cp -f libiui_example.wasm assets/web/ 2>/dev/null || true; \
cp -f libiui_example assets/web/libiui_example.js; \
cp -f libiui_example.wasm assets/web/; \
echo ""; \
echo "WebAssembly build installed to assets/web/"; \
echo "To test, run:"; \
Expand All @@ -285,8 +290,10 @@ wasm-install:
echo "Build with: make"; \
fi

# Override all target to add post-build hook for Emscripten
# Add wasm-install as post-build step for Emscripten
# wasm-install depends on the actual build targets to avoid race conditions
ifeq ($(CC_IS_EMCC), 1)
wasm-install: $(target-y)
all: wasm-install
endif

Expand Down
5 changes: 5 additions & 0 deletions configs/wasm_defconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# WebAssembly (Emscripten) build configuration
# Only WASM-specific overrides; other options inherited from Kconfig defaults

CONFIG_PORT_WASM=y
CONFIG_OPTIMIZE_SIZE=y
Loading
Loading