ci: install mcpp from its release tarball, not the interactive installer #4
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
| # Build every member on BOTH toolchains, and check what a green compile would | ||
| # not: that the generator is ours, that the sonames are canonical, that the two | ||
| # libraries do not overlap, and that every module produced an interface. | ||
| name: ci | ||
| on: | ||
| push: | ||
| branches: [main] | ||
| tags: ['v*'] | ||
| pull_request: | ||
| workflow_dispatch: | ||
| env: | ||
| # The floor mcpp-index is tested against — consumers reach these packages | ||
| # through that index, so this is the version that matters, not the newest. | ||
| MCPP_VERSION: "2026.8.27.2" | ||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| # Both, because the module wrappers are where the two compilers differ | ||
| # most: a 300-entry `using ::name;` export block is exactly the shape | ||
| # that finds a disagreement about what may be named in an export. | ||
| toolchain: [default, llvm] | ||
| name: build (${{ matrix.toolchain }}) | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| # The release tarball, not the interactive installer: `curl | bash` of | ||
| # the xlings installer wants /dev/tty and exits 1 on a runner. A released | ||
| # mcpp is self-contained — it resolves its registry from beside its own | ||
| # executable — so MCPP_HOME is the tarball root rather than ~/.mcpp. | ||
| - name: Download mcpp | ||
| env: | ||
| MCPP_ARCHIVE: mcpp-2026.8.27.2-linux-x86_64.tar.gz | ||
| MCPP_ROOT: mcpp-2026.8.27.2-linux-x86_64 | ||
| run: | | ||
| curl -L -fsS -o "$MCPP_ARCHIVE" \ | ||
| "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/${MCPP_ARCHIVE}" | ||
| tar -xzf "$MCPP_ARCHIVE" | ||
| root="$PWD/$MCPP_ROOT" | ||
| echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV" | ||
| echo "MCPP_HOME=$root" >> "$GITHUB_ENV" | ||
| - name: Select toolchain | ||
| if: matrix.toolchain != 'default' | ||
| run: | | ||
| "$MCPP" toolchain install ${{ matrix.toolchain }} | ||
| "$MCPP" toolchain default ${{ matrix.toolchain }} | ||
| "$MCPP" toolchain list | ||
| - name: Build the workspace | ||
| run: | | ||
| "$MCPP" --version | ||
| "$MCPP" build --workspace | ||
| - name: The macro mappings actually run | ||
| run: "$MCPP" test -p mcpp/util | ||
| - name: wayland-scanner is ours, and is 1.26.0 | ||
| run: | | ||
| scanner=$(find mcpp/scanner/target -name wayland-scanner -type f | head -1) | ||
| test -n "$scanner" || { echo "no wayland-scanner was built"; exit 1; } | ||
| "$scanner" --version | ||
| "$scanner" --version | grep -qx 'wayland-scanner 1.26.0' | ||
| - name: the generated protocol code came from THIS scanner | ||
| run: | | ||
| scanner=$(find mcpp/scanner/target -name wayland-scanner -type f | head -1) | ||
| "$scanner" -s public-code protocol/wayland.xml /tmp/wayland-protocol.c | ||
| head -1 /tmp/wayland-protocol.c | ||
| grep -q 'Generated by wayland-scanner 1.26.0' /tmp/wayland-protocol.c | ||
| - name: both libraries carry the canonical SONAMEs | ||
| run: | | ||
| for pair in "client:libwayland-client.so.0" "server:libwayland-server.so.0"; do | ||
| member=${pair%%:*}; want=${pair#*:} | ||
| so=$(find "mcpp/$member/target" -name "${want%.0}" -type f | head -1) | ||
| test -n "$so" || { echo "$member: no library built"; exit 1; } | ||
| got=$(readelf -d "$so" | sed -n 's/.*SONAME.*\[\(.*\)\]/\1/p') | ||
| echo "$member -> $got" | ||
| test "$got" = "$want" || { echo "expected $want"; exit 1; } | ||
| done | ||
| - name: the two libraries do not overlap | ||
| run: | | ||
| # Mesa's libEGL_mesa has DT_NEEDED on both; if one carried the other's | ||
| # API the process would bind to whichever loaded first. | ||
| c=$(find mcpp/client/target -name libwayland-client.so -type f | head -1) | ||
| s=$(find mcpp/server/target -name libwayland-server.so -type f | head -1) | ||
| readelf --dyn-syms -W "$c" | grep -q ' wl_display_connect' || exit 1 | ||
| readelf --dyn-syms -W "$c" | grep -q ' wl_display_create' && { echo "client leaked the server API"; exit 1; } | ||
| readelf --dyn-syms -W "$s" | grep -q ' wl_display_create' || exit 1 | ||
| readelf --dyn-syms -W "$s" | grep -q ' wl_display_connect' && { echo "server leaked the client API"; exit 1; } | ||
| echo "client and server APIs are disjoint" | ||
| - name: every module produced an interface | ||
| run: | | ||
| for m in client server util; do | ||
| find "mcpp/$m/target" \( -name '*.gcm' -o -name '*.pcm' \) | head -1 | grep -q . \ | ||
| || { echo "$m: no module interface was produced"; exit 1; } | ||
| done | ||
| echo "wayland.client, wayland.server and wayland.util all have interfaces" | ||
| upstream: | ||
| # The fork patches no upstream file, so meson must still build this tree. | ||
| # If this breaks, something was modified that should not have been. | ||
| name: upstream meson still builds this tree | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - run: | | ||
| sudo apt-get update -qq | ||
| sudo apt-get install -y -qq meson ninja-build libffi-dev libexpat1-dev | ||
| meson setup build-meson -Ddocumentation=false -Ddtd_validation=false | ||
| ninja -C build-meson | ||