Skip to content

chore(examples): kebab-case naming, remove loose host demo and index #71

chore(examples): kebab-case naming, remove loose host demo and index

chore(examples): kebab-case naming, remove loose host demo and index #71

Workflow file for this run

name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
# ============================================================
# Desktop: full test suites (compile + run)
# ============================================================
test-gcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Build and test (gcc, C99 strict)
run: make CC=gcc test
test-clang:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Build and test (clang, C99 strict)
run: make CC=clang test
test-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v5
- name: Build and test (Apple clang)
run: make test
test-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v5
- name: Build and test (MSVC)
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
cl /std:c11 /W4 /I src /Fe:test_msg.exe test\test_midi2_msg.c
test_msg.exe
cl /std:c11 /W4 /I src /Fe:test_proc.exe test\test_midi2_proc.c src\midi2_proc.c
test_proc.exe
cl /std:c11 /W4 /I src /Fe:test_ci.exe test\test_midi2_ci.c src\midi2_proc.c src\midi2_ci.c
test_ci.exe
cl /std:c11 /W4 /I src /Fe:test_conv.exe test\test_midi2_conv.c src\midi2_conv.c
test_conv.exe
cl /std:c11 /W4 /I src /Fe:test_dispatch.exe test\test_midi2_dispatch.c src\midi2_dispatch.c
test_dispatch.exe
cl /std:c11 /W4 /I src /Fe:test_ci_msg.exe test\test_midi2_ci_msg.c
test_ci_msg.exe
cl /std:c11 /W4 /I src /Fe:test_ci_dispatch.exe test\test_midi2_ci_dispatch.c src\midi2_ci_dispatch.c
test_ci_dispatch.exe
# ============================================================
# Embedded: cross-compilation (syntax + type check, no link)
# ============================================================
build-arm-cortex-m:
name: ARM Cortex-M (arm-none-eabi-gcc)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install ARM toolchain
run: sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi
- name: Compile all modules for Cortex-M
run: |
for f in src/*.c; do
echo " CC $f"
arm-none-eabi-gcc -std=c99 -Wall -Wextra -Wpedantic -I src \
-mcpu=cortex-m4 -mthumb -c "$f" -o /dev/null
done
echo "ARM Cortex-M4: OK"
build-arm-cortex-a:
name: ARM Cortex-A (aarch64-linux-gnu-gcc)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install AArch64 toolchain
run: sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Compile all modules for AArch64
run: |
for f in src/*.c; do
echo " CC $f"
aarch64-linux-gnu-gcc -std=c99 -Wall -Wextra -Wpedantic -I src \
-c "$f" -o /dev/null
done
echo "AArch64 (Cortex-A / RPi / Daisy): OK"
build-riscv:
name: RISC-V (riscv64-linux-gnu-gcc)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install RISC-V toolchain
run: sudo apt-get update && sudo apt-get install -y gcc-riscv64-linux-gnu
- name: Compile all modules for RISC-V
run: |
for f in src/*.c; do
echo " CC $f"
riscv64-linux-gnu-gcc -std=c99 -Wall -Wextra -Wpedantic -I src \
-c "$f" -o /dev/null
done
echo "RISC-V 64: OK"
build-esp32-idf:
name: ESP32 (ESP-IDF component check)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Compile with Xtensa GCC (via xtensa-esp-elf docker)
run: |
# Verify C99 strict compilation with a cross-compiler proxy
# ESP-IDF uses xtensa-esp-elf-gcc, but for CI we verify with
# standard gcc in C99 mode as ESP-IDF component compatibility
for f in src/*.c; do
echo " CC $f"
gcc -std=c99 -Wall -Wextra -Wpedantic -I src \
-DESP_PLATFORM -c "$f" -o /dev/null
done
echo "ESP32 (component check): OK"
build-avr:
name: AVR (avr-gcc)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install AVR toolchain
run: sudo apt-get update && sudo apt-get install -y gcc-avr avr-libc
- name: Compile header-only modules for AVR
run: |
# AVR has no stdint-compatible bool, test header-only modules
avr-gcc -std=c99 -Wall -Wextra -I src -mmcu=atmega328p \
-c -x c - -o /dev/null <<'AVRTEST'
#include "midi2_msg.h"
#include "midi2_ci_msg.h"
uint32_t test(void) {
uint32_t w[2];
midi2_msg_note_on(w, 0, 0, 60, 0xC000, 0, 0);
return w[0];
}
AVRTEST
echo "AVR ATmega328P (header-only): OK"
build-cxx-header:
name: C++ header compile (g++ c++17 / c++20)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Regenerate amalgam and fail on drift
run: |
# The amalgam is C++-compiled below. Regenerate it from src/ and fail
# if the committed dist/ is stale, so a contributor who forgot to
# re-amalgamate cannot ship a src/ change the C++ job never saw.
./tools/amalgamate.sh
git diff --exit-code dist/ \
|| (echo "dist/ is stale: run tools/amalgamate.sh and commit" && exit 1)
- name: Compile public headers as C++
run: |
# midi2.h is included directly by C++ consumers (midi2cpp,
# libDaisy, Teensy wrappers). Guards against C-only constructs
# such as designated array initializers that g++ rejects. The
# modular arm includes every header a wrapper pulls in, so a
# C++-hostile construct in any of them fails here, not downstream.
printf '#define MIDI2_IMPLEMENTATION\n#include "midi2.h"\nint main(void) { return (int)midi2_msg_word_count(0x4); }\n' > cxx_amalgam.cpp
printf '#include "midi2_msg.h"\n#include "midi2_conv.h"\n#include "midi2_proc.h"\nint main(void) { return (int)midi2_msg_word_count(0x4); }\n' > cxx_modular.cpp
for std in c++17 c++20; do
echo " amalgam $std"
g++ -std=$std -Wall -Wextra -I dist cxx_amalgam.cpp -o /dev/null
echo " modular $std"
g++ -std=$std -Wall -Wextra -I src cxx_modular.cpp -o /dev/null
done
echo "C++ header compile: OK"
# ============================================================
# Additional desktop architectures
# ============================================================
test-gcc-32bit:
name: Linux x86 32-bit (gcc -m32)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install 32-bit libraries
run: sudo apt-get update && sudo apt-get install -y gcc-multilib
- name: Build and test (gcc 32-bit)
run: make CC="gcc -m32" test
test-gcc-sanitizers:
name: Linux (gcc + ASan + UBSan)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Build and test with sanitizers
run: make CC="gcc -fsanitize=address,undefined -fno-omit-frame-pointer" test
# ============================================================
# CMake build matrix: configure -> build -> install -> downstream
# find_package(midi2) consumer compiled and run from the installed
# prefix. The synthetic consumer lives at tests/cmake-consumer/ so
# the same files are exercised across Linux / macOS / Windows.
# ============================================================
cmake-build:
name: CMake build + install + find_package (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v5
# CMAKE_BUILD_TYPE is needed by single-config generators (Make,
# Ninja on Linux/macOS) so the exported midi2-config-<cfg>.cmake
# carries IMPORTED_LOCATION_<CONFIG>. Multi-config generators
# (Visual Studio) ignore CMAKE_BUILD_TYPE and respect --config.
- name: Configure
run: cmake -S . -B build-cmake -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build build-cmake --parallel --config Release
- name: Install
run: cmake --install build-cmake --prefix ${{ runner.temp }}/midi2-install --config Release
- name: Configure downstream consumer
run: >
cmake -S tests/cmake-consumer -B build-consumer
-DCMAKE_PREFIX_PATH=${{ runner.temp }}/midi2-install
-DCMAKE_BUILD_TYPE=Release
- name: Build downstream consumer
run: cmake --build build-consumer --parallel --config Release
- name: Run downstream consumer (Unix)
if: runner.os != 'Windows'
run: ./build-consumer/midi2_consumer
- name: Run downstream consumer (Windows)
if: runner.os == 'Windows'
run: build-consumer\Release\midi2_consumer.exe
# ============================================================
# FetchContent path: synthetic project pulls midi2 from the local
# checkout via FetchContent_Declare and links midi2::midi2 without
# any install step. Documents-as-CI: the README's snippet has to
# actually work.
# ============================================================
cmake-fetchcontent:
name: CMake FetchContent (downstream pulls midi2 by source)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Stage parent project
run: |
mkdir -p ${{ runner.temp }}/parent
cat > ${{ runner.temp }}/parent/CMakeLists.txt <<'PARENT_CMAKE'
cmake_minimum_required(VERSION 3.14)
project(parent LANGUAGES C)
include(FetchContent)
FetchContent_Declare(midi2 SOURCE_DIR ${MIDI2_LOCAL_PATH})
FetchContent_MakeAvailable(midi2)
add_executable(parent_consumer main.c)
target_link_libraries(parent_consumer PRIVATE midi2::midi2)
PARENT_CMAKE
cp tests/cmake-consumer/main.c ${{ runner.temp }}/parent/main.c
- name: Configure + build + run
run: |
cmake -S ${{ runner.temp }}/parent -B ${{ runner.temp }}/parent-build \
-DMIDI2_LOCAL_PATH=${{ github.workspace }}
cmake --build ${{ runner.temp }}/parent-build --parallel
${{ runner.temp }}/parent-build/parent_consumer
# ============================================================
# CMake build with ASan + UBSan parity to the Makefile sanitizer
# job. Catches sanitizer-detectable regressions in the amalgam
# build path that the Makefile build (which compiles the modular
# src/*.c) might miss.
# ============================================================
cmake-build-sanitizers:
name: CMake (gcc + ASan + UBSan)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Configure with sanitizers
run: >
cmake -S . -B build-cmake-asan
-DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -O1 -g"
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
- name: Build
run: cmake --build build-cmake-asan --parallel
- name: Install
run: cmake --install build-cmake-asan --prefix ${{ runner.temp }}/midi2-install
- name: Configure + build + run downstream consumer with sanitizers
run: |
cmake -S tests/cmake-consumer -B build-consumer-asan \
-DCMAKE_PREFIX_PATH=${{ runner.temp }}/midi2-install \
-DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -O1 -g" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
cmake --build build-consumer-asan --parallel
./build-consumer-asan/midi2_consumer
# ============================================================
# Zephyr (west module): builds the smoke consumer at
# tests/zephyr-consumer/ on native_sim/native/64. Confirms the
# zephyr/ module manifest keeps wiring midi2 sources into a Zephyr
# application and that dispatch fires end-to-end under Zephyr's
# kernel. native_sim uses host gcc -- no Zephyr SDK toolchain
# bundle needed.
# ============================================================
build-zephyr:
name: Zephyr (native_sim/native/64)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
path: midi2
- name: Install west and host build tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends ninja-build device-tree-compiler
python3 -m pip install --user west pyelftools jsonschema PyYAML packaging \
anytree colorama docutils intelhex
echo "${HOME}/.local/bin" >> "$GITHUB_PATH"
- name: Cache Zephyr workspace
id: cache-zephyr
uses: actions/cache@v4
with:
path: zephyrproject
key: zephyrproject-v4.4.0-${{ runner.os }}
- name: Initialize Zephyr workspace (cache miss)
if: steps.cache-zephyr.outputs.cache-hit != 'true'
run: |
west init --mr v4.4.0 zephyrproject
cd zephyrproject
west update --narrow -o=--depth=1
- name: Install Zephyr Python requirements
run: |
python3 -m pip install --user -r zephyrproject/zephyr/scripts/requirements-base.txt
- name: Install Zephyr SDK minimal
run: |
cd "$HOME"
wget -q https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v1.0.1/zephyr-sdk-1.0.1_linux-x86_64_minimal.tar.xz
tar xf zephyr-sdk-1.0.1_linux-x86_64_minimal.tar.xz
echo "ZEPHYR_SDK_INSTALL_DIR=$HOME/zephyr-sdk-1.0.1" >> "$GITHUB_ENV"
- name: Configure smoke consumer
env:
ZEPHYR_BASE: ${{ github.workspace }}/zephyrproject/zephyr
run: |
cd midi2/tests/zephyr-consumer
cmake -B build -GNinja \
-DBOARD=native_sim/native/64 \
-DZEPHYR_EXTRA_MODULES="$GITHUB_WORKSPACE/midi2"
- name: Build smoke consumer
run: cmake --build midi2/tests/zephyr-consumer/build
- name: Run smoke, assert PASS
run: |
OUTPUT=$(timeout 5 midi2/tests/zephyr-consumer/build/zephyr/zephyr.exe 2>&1 || true)
echo "$OUTPUT"
echo "$OUTPUT" | grep -q "midi2 Zephyr smoke: PASS"