A no-op build prints nothing (rowan-new#110) (#338) #433
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| permissions: | |
| contents: read | |
| jobs: | |
| build-test: | |
| name: build & test (${{ matrix.label }}) | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-24.04 | |
| label: linux x86-64 | |
| # macOS x86-64 (Intel, macos-13) temporarily disabled — runner is slow to allocate. | |
| - os: macos-14 | |
| label: macOS arm64 (Apple Silicon) | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build & test (debug) | |
| run: | | |
| cmake -B build-debug -DCMAKE_BUILD_TYPE=Debug | |
| cmake --build build-debug -j | |
| ./bin/test | |
| ./bin/custom_packet_io_test | |
| - name: Build & test (release) | |
| run: | | |
| cmake -B build-release -DCMAKE_BUILD_TYPE=Release | |
| cmake --build build-release -j | |
| ./bin/test | |
| ./bin/custom_packet_io_test | |
| windows: | |
| name: build & test (windows MSVC x64, ${{ matrix.config }}) | |
| # Pinned to windows-2022 (Visual Studio 2022); the "Visual Studio 17 2022" CMake generator | |
| # needs a matching VS install, which windows-latest no longer guarantees. | |
| runs-on: windows-2022 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| config: [Debug, Release] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure (Visual Studio 2022, x64) | |
| run: cmake -B build -G "Visual Studio 17 2022" -A x64 | |
| - name: Build (${{ matrix.config }} x64) | |
| run: cmake --build build --config ${{ matrix.config }} -j | |
| - name: Test (${{ matrix.config }} x64) | |
| shell: pwsh | |
| run: | | |
| $exe = Get-ChildItem -Recurse -Filter test.exe | Select-Object -First 1 | |
| if (-not $exe) { Write-Error "test.exe not found"; exit 1 } | |
| Write-Host "Running $($exe.FullName)" | |
| & $exe.FullName | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| $exe = Get-ChildItem -Recurse -Filter custom_packet_io_test.exe | Select-Object -First 1 | |
| if (-not $exe) { Write-Error "custom_packet_io_test.exe not found"; exit 1 } | |
| Write-Host "Running $($exe.FullName)" | |
| & $exe.FullName | |
| exit $LASTEXITCODE | |
| system-sodium: | |
| name: build & test (linux, --sodium=system) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install libsodium | |
| run: sudo apt-get update && sudo apt-get install -y libsodium-dev | |
| - name: Build & test (system libsodium) | |
| run: | | |
| cmake -B build -DCMAKE_BUILD_TYPE=Debug -DYOJIMBO_SYSTEM_SODIUM=ON | |
| cmake --build build -j | |
| ./bin/test | |
| system-deps: | |
| name: build & test (linux, --system-deps) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Simulates the package-manager environment (e.g. homebrew): serialize, reliable and | |
| # netcode installed into a prefix from their own releases, then yojimbo built against | |
| # them with -DYOJIMBO_SYSTEM_DEPS=ON instead of the vendored copies. Versions pinned | |
| # to match the vendored ones. | |
| - name: Install serialize, reliable and netcode into a prefix | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update && sudo apt-get install -y libsodium-dev | |
| PREFIX="$HOME/deps" | |
| # Clone outside the workspace: the yojimbo checkout already has serialize/, | |
| # reliable/ and netcode/ directories (the vendored copies). | |
| DEPS_SRC="$HOME/deps-src" | |
| mkdir -p "$PREFIX/include" "$PREFIX/lib" "$DEPS_SRC" | |
| # serialize: header-only | |
| git clone --depth 1 --branch v1.4.3 https://github.com/mas-bandwidth/serialize.git "$DEPS_SRC/serialize" | |
| cp "$DEPS_SRC/serialize/serialize.h" "$PREFIX/include/" | |
| # reliable: build the library from source | |
| git clone --depth 1 --branch v1.3.3 https://github.com/mas-bandwidth/reliable.git "$DEPS_SRC/reliable" | |
| cc -O2 -c "$DEPS_SRC/reliable/reliable.c" -I"$DEPS_SRC/reliable" -o "$DEPS_SRC/reliable.o" | |
| ar rcs "$PREFIX/lib/libreliable.a" "$DEPS_SRC/reliable.o" | |
| cp "$DEPS_SRC/reliable/reliable.h" "$PREFIX/include/" | |
| # netcode: has cmake install rules (built against the system libsodium, as a | |
| # package manager would) | |
| git clone --depth 1 --branch v1.3.2 https://github.com/mas-bandwidth/netcode.git "$DEPS_SRC/netcode" | |
| cmake -B "$DEPS_SRC/netcode-build" -S "$DEPS_SRC/netcode" -DCMAKE_BUILD_TYPE=Release -DNETCODE_SYSTEM_SODIUM=ON -DCMAKE_INSTALL_PREFIX="$PREFIX" | |
| cmake --build "$DEPS_SRC/netcode-build" -j | |
| cmake --install "$DEPS_SRC/netcode-build" | |
| - name: Build & test yojimbo against the installed dependencies | |
| run: | | |
| cmake -B build -DCMAKE_BUILD_TYPE=Debug -DYOJIMBO_SYSTEM_DEPS=ON -DCMAKE_PREFIX_PATH="$HOME/deps" | |
| cmake --build build -j | |
| ./bin/test | |
| - name: Install yojimbo and verify the layout | |
| run: | | |
| cmake --install build --prefix "$HOME/yojimbo-install" | |
| test -f "$HOME/yojimbo-install/include/yojimbo.h" | |
| test -f "$HOME/yojimbo-install/lib/libyojimbo.a" | |
| sanitizers: | |
| name: sanitizers (linux, ASan+UBSan+LSan) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build (sanitized) | |
| # nonnull-attribute is excluded: netcode encrypts zero-length plaintexts, and | |
| # libsodium's AEAD then does memcpy(dst, NULL, 0) — benign UB in upstream code. | |
| run: | | |
| SAN="-fsanitize=address,undefined -fno-sanitize=nonnull-attribute -fno-sanitize-recover=all -fno-omit-frame-pointer -g" | |
| cmake -B build -DCMAKE_BUILD_TYPE=Debug \ | |
| -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ | |
| -DCMAKE_C_FLAGS="$SAN" -DCMAKE_CXX_FLAGS="$SAN" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" | |
| cmake --build build -j --target test | |
| - name: Test (sanitized) | |
| run: ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./bin/test | |
| fuzz: | |
| name: fuzz (linux libFuzzer, ASan+UBSan) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Coverage-guided libFuzzer over the untrusted-input parsers. Each target is built | |
| # without -DFUZZ_STANDALONE (libFuzzer supplies main) and time-boxed. Debug defines | |
| # stay on so the libraries' asserts and the message-factory leak check are live — | |
| # that check is what surfaces leaks in the connection deserialization error paths. | |
| # nonnull-attribute is excluded for the same reason as the sanitizers job (libsodium | |
| # memcpy(dst, NULL, 0) on zero-length AEAD plaintext). | |
| - name: Build and run fuzz targets | |
| run: | | |
| set -euo pipefail | |
| SAN="-fsanitize=fuzzer,address,undefined -fno-sanitize=nonnull-attribute -fno-sanitize-recover=all -fno-omit-frame-pointer -g" | |
| RUN="-max_total_time=60 -print_final_stats=1 -rss_limit_mb=4096" | |
| echo "::group::build fuzz_reliable" | |
| clang $SAN -DRELIABLE_DEBUG -Ireliable -Ifuzz \ | |
| fuzz/fuzz_reliable.c reliable/reliable.c -o fuzz_reliable | |
| echo "::endgroup::" | |
| echo "::group::build fuzz_netcode" | |
| clang $SAN -DNETCODE_DEBUG -Inetcode -Isodium -Ifuzz \ | |
| fuzz/fuzz_netcode.c sodium/sodium.c -o fuzz_netcode | |
| echo "::endgroup::" | |
| echo "::group::build fuzz_netcode_connect_token" | |
| clang $SAN -DNETCODE_DEBUG -Inetcode -Isodium -Ifuzz \ | |
| fuzz/fuzz_netcode_connect_token.c sodium/sodium.c -o fuzz_netcode_connect_token | |
| echo "::endgroup::" | |
| for target in fuzz_connection fuzz_connection_structured; do | |
| echo "::group::build $target" | |
| clang++ -std=c++11 $SAN -DYOJIMBO_DEBUG -DNETCODE_DEBUG -DRELIABLE_DEBUG -DSERIALIZE_DEBUG \ | |
| -I. -Iinclude -Isodium -Itlsf -Inetcode -Ireliable -Iserialize -Ifuzz \ | |
| fuzz/$target.cpp source/*.cpp netcode/netcode.c reliable/reliable.c tlsf/tlsf.c sodium/sodium.c \ | |
| -o $target | |
| echo "::endgroup::" | |
| done | |
| # Seed from the committed corpus (fuzz/corpus/<target>) so the short run starts at | |
| # inputs that already reach the post-decrypt / reassembly code. libFuzzer reads all | |
| # corpus dirs but only writes new finds to the first, so the committed seeds stay | |
| # pristine and discoveries land in the ephemeral working dir. | |
| for t in fuzz_reliable fuzz_netcode fuzz_netcode_connect_token fuzz_connection fuzz_connection_structured; do | |
| echo "::group::run $t" | |
| mkdir -p "corpus/$t" | |
| UBSAN_OPTIONS=halt_on_error=1 ./"$t" "corpus/$t" "fuzz/corpus/$t" $RUN | |
| echo "::endgroup::" | |
| done | |
| soak: | |
| name: soak (linux, sanitized, time-boxed) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build soak (sanitized) | |
| # Same sanitizer flags and nonnull-attribute carve-out as the sanitizers job. | |
| run: | | |
| SAN="-fsanitize=address,undefined -fno-sanitize=nonnull-attribute -fno-sanitize-recover=all -fno-omit-frame-pointer -g" | |
| cmake -B build -DCMAKE_BUILD_TYPE=Debug \ | |
| -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ | |
| -DCMAKE_C_FLAGS="$SAN" -DCMAKE_CXX_FLAGS="$SAN" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" | |
| cmake --build build -j --target soak | |
| - name: Run soak (time-boxed) | |
| # Bounded iteration count so the normally-endless soak exits cleanly and the | |
| # sanitizers run their end-of-process (incl. leak) checks. Output is verbose, so | |
| # keep it in a file and only surface the tail on failure. | |
| run: | | |
| set -o pipefail | |
| if ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 \ | |
| ./bin/soak 20000 > soak.log 2>&1; then | |
| echo "soak completed cleanly ($(grep -c 'received message' soak.log) messages exchanged)" | |
| else | |
| echo "soak failed (exit $?)"; tail -50 soak.log; exit 1 | |
| fi | |
| msan: | |
| name: fuzz (linux libFuzzer, MemorySanitizer) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # MemorySanitizer catches *reads of uninitialized memory* — the class of bug the | |
| # ChannelPacketData union-init crash was (Free() dereferencing a half-initialized | |
| # block.message). ASan/UBSan do not catch that. The C++ targets are built WITHOUT | |
| # -DYOJIMBO_DEBUG so the debug std::map leak trackers aren't compiled in; that leaves the | |
| # binaries free of C++ STL, so MSan needs no separately-instrumented libc++ (linking an | |
| # uninstrumented libc++ would produce false positives). Asserts and leak detection stay | |
| # covered by the sanitizers (ASan+UBSan+LSan) job. | |
| - name: Build and run fuzz targets under MSan | |
| run: | | |
| set -euo pipefail | |
| MSAN="-fsanitize=fuzzer,memory -fno-omit-frame-pointer -g" | |
| RUN="-max_total_time=45 -print_final_stats=1 -rss_limit_mb=4096" | |
| echo "::group::build C targets" | |
| clang $MSAN -DRELIABLE_DEBUG -Ireliable -Ifuzz \ | |
| fuzz/fuzz_reliable.c reliable/reliable.c -o fuzz_reliable | |
| clang $MSAN -DNETCODE_DEBUG -Inetcode -Isodium -Ifuzz \ | |
| fuzz/fuzz_netcode.c sodium/sodium.c -o fuzz_netcode | |
| clang $MSAN -DNETCODE_DEBUG -Inetcode -Isodium -Ifuzz \ | |
| fuzz/fuzz_netcode_connect_token.c sodium/sodium.c -o fuzz_netcode_connect_token | |
| echo "::endgroup::" | |
| # -DYOJIMBO_RELEASE selects the release path so the debug std::map leak trackers | |
| # (Allocator::m_alloc_map, MessageFactory::allocated_messages) are not compiled in. | |
| # That keeps the binary free of C++ STL, so MSan needs no instrumented libc++ — an | |
| # uninstrumented libstdc++ std::map traversal reports a spurious use-of-uninitialized. | |
| for target in fuzz_connection fuzz_connection_structured; do | |
| echo "::group::build $target" | |
| clang++ -std=c++11 $MSAN -DYOJIMBO_RELEASE -DNETCODE_DEBUG -DRELIABLE_DEBUG -DSERIALIZE_DEBUG \ | |
| -I. -Iinclude -Isodium -Itlsf -Inetcode -Ireliable -Iserialize -Ifuzz \ | |
| fuzz/$target.cpp source/*.cpp netcode/netcode.c reliable/reliable.c tlsf/tlsf.c sodium/sodium.c \ | |
| -o $target | |
| echo "::endgroup::" | |
| done | |
| for t in fuzz_reliable fuzz_netcode fuzz_netcode_connect_token fuzz_connection fuzz_connection_structured; do | |
| echo "::group::run $t" | |
| mkdir -p "corpus/$t" | |
| ./"$t" "corpus/$t" "fuzz/corpus/$t" $RUN | |
| echo "::endgroup::" | |
| done | |
| conformance: | |
| name: STANDARD.md + STATE-MACHINE.md conformance | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # The format checker needs no build: it decodes the committed fuzz corpus | |
| # using ONLY what STANDARD.md states, with no reference to the source. | |
| - name: Verify STANDARD.md | |
| run: python3 tools/conformance/verify_standard.py | |
| # The state-machine checker drives a real client and server over UDP, so | |
| # it needs the library built first. | |
| - name: Build | |
| run: | | |
| cmake -B build -DCMAKE_BUILD_TYPE=Release -DYOJIMBO_BUILD_TESTS=ON | |
| cmake --build build -j | |
| # A failure in either means the document and the code disagree — decide | |
| # which is wrong and fix that one. A specification nothing verifies | |
| # drifts, and a drifted spec is worse than none, because independent | |
| # implementations are built on it and the failure is silent. | |
| - name: Verify STATE-MACHINE.md | |
| run: python3 tools/conformance/verify_state_machine.py --build build |