From ab9fc6ec2e2a92a0c3d6ffa95bb316dfb601a2e6 Mon Sep 17 00:00:00 2001 From: Bentley Davis <10065854+NonPolynomialTim@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:44:13 -0400 Subject: [PATCH] fix(ci): Linux AppImage on debian:11 (jsoncpp 1.9.5 from source, -pthread) Rebuilt as a single clean delta on top of main (the branch predated #107's squash, so its old pre-squash AppImage commits conflicted with main). build-linux now: debian:11 (glibc 2.31 floor) + jsoncpp 1.9.5 built from source into /usr/local (distro 1.9.4/1.7.4 makes the coop code's raw int64/uint64 -> Json::Value writes ambiguous on gcc) + -pthread (glibc 2.31 has a separate libpthread the CMake build never links). Validated green end-to-end via a branch ci-main dispatch. Mirrored into ci-validate. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci-main.yml | 51 +++++++++++++++++++++++++------ .github/workflows/ci-validate.yml | 37 +++++++++++++++++----- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index 7da76904b..b49020d73 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -512,12 +512,16 @@ jobs: build-linux: needs: meta runs-on: ubuntu-latest - # Build inside an old-glibc container (2.31) so the AppImage runs on nearly - # every current distro. An AppImage bundles its own libs but NOT glibc, so its - # portability floor is the build host's glibc - ubuntu-latest (2.39) would lock - # out older distros and reproduce the very "can't run it" bug this restores the - # AppImage to fix. Same container pattern as build-winxp. - container: ubuntu:20.04 + # Build inside a low-glibc container so the AppImage runs on nearly every + # current distro: an AppImage bundles its own libs but NOT glibc, so its + # portability floor is the build host's glibc, and ubuntu-latest (2.39) would + # lock out older distros and reproduce the very "can't run it" bug this fixes. + # debian:11 (bullseye) gives glibc 2.31 - covers Debian 11+, Ubuntu 20.04+ and + # RHEL/Rocky 9 (2.34) - with gcc 10. Its distro jsoncpp (1.9.4) makes the coop + # code's int64/uint64 -> Json::Value writes ambiguous on gcc, so we build + # jsoncpp 1.9.5 from source below (the version ubuntu-latest had when this + # compiled) rather than change the game source or raise the glibc floor. + container: debian:11 timeout-minutes: 60 defaults: run: @@ -538,7 +542,7 @@ jobs: git ca-certificates wget file pkg-config python3 \ cmake g++ make patchelf \ libsdl1.2-dev libsdl-mixer1.2-dev libsdl-gfx1.2-dev libsdl-image1.2-dev libsdl-net1.2-dev \ - libyaml-cpp-dev libjsoncpp-dev libsodium-dev zlib1g-dev + libyaml-cpp-dev libsodium-dev zlib1g-dev then ok=1; break; fi echo "apt attempt $n failed (mirror flake); retrying in $((n * 15))s" sleep $((n * 15)) @@ -548,18 +552,43 @@ jobs: - uses: actions/checkout@v4 with: { fetch-depth: 0, submodules: recursive } + - name: Build jsoncpp 1.9.5 from source + # The distro jsoncpp (bullseye 1.9.4) types Int64/UInt64 as long long, so on + # LP64 a raw int64_t/uint64_t (long) -> Json::Value write is ambiguous and + # the coop code fails to compile. 1.9.5 types them as int64_t/uint64_t, so + # those writes match exactly - this is the jsoncpp the code has always been + # built against on ubuntu-latest. Install to /usr/local; ldconfig so the + # linker/loader (and linuxdeploy's ldd) resolve it. NOT the distro package. + run: | + set -euxo pipefail + git clone --depth 1 --branch 1.9.5 https://github.com/open-source-parsers/jsoncpp.git /tmp/jsoncpp + cmake -S /tmp/jsoncpp -B /tmp/jsoncpp/build \ + -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \ + -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF \ + -DCMAKE_INSTALL_PREFIX=/usr/local + cmake --build /tmp/jsoncpp/build -j"$(nproc)" + cmake --install /tmp/jsoncpp/build + ldconfig + - name: Stamp src/version.h run: sh tools/ci/stamp_version.sh "${{ needs.meta.outputs.version }}" "${{ needs.meta.outputs.gitSuffix }}" - name: Configure + build (Linux x86_64) run: | set -euxo pipefail - # ubuntu's libjsoncpp-dev installs headers under /usr/include/jsoncpp; - # the code includes , so add jsoncpp's include dir. + # Prefer the from-source jsoncpp in /usr/local over anything else: its .pc + # for the -I flags, its lib dir for the -ljsoncpp link. + export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:${PKG_CONFIG_PATH:-}" + export LIBRARY_PATH="/usr/local/lib:${LIBRARY_PATH:-}" JSONCPP_CFLAGS=$(pkg-config --cflags jsoncpp) rm -rf build && mkdir -p build && cd build + # -pthread: the coop code spawns std::threads, but the CMake build never + # links libpthread. On glibc >= 2.34 (ubuntu-latest) pthread lives in libc + # so it links anyway; on glibc 2.31 (debian:11) libpthread is separate and + # the link fails with "undefined reference to pthread_create", so force it. cmake -DCMAKE_BUILD_TYPE=Release -DDEV_BUILD=OFF -DBUILD_PACKAGE=OFF \ - -DCMAKE_CXX_FLAGS="$JSONCPP_CFLAGS" "$GITHUB_WORKSPACE" + -DCMAKE_CXX_FLAGS="$JSONCPP_CFLAGS -pthread" \ + -DCMAKE_EXE_LINKER_FLAGS="-pthread" "$GITHUB_WORKSPACE" make -j"$(nproc)" - name: Build AppImage (linuxdeploy) @@ -578,6 +607,8 @@ jobs: # the plugin on PATH where linuxdeploy discovers it by name. export APPIMAGE_EXTRACT_AND_RUN=1 export PATH="$PWD:$PATH" + # so linuxdeploy's ldd resolves the from-source jsoncpp for bundling + export LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH:-}" base=https://github.com/linuxdeploy wget -q "$base/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage" wget -q "$base/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage" diff --git a/.github/workflows/ci-validate.yml b/.github/workflows/ci-validate.yml index e99527350..edb439579 100644 --- a/.github/workflows/ci-validate.yml +++ b/.github/workflows/ci-validate.yml @@ -353,10 +353,10 @@ jobs: # Native Linux (x86_64) build via GCC - the other platform ci-main.yml ships. build-linux: runs-on: ubuntu-latest - # Mirrors ci-main's build-linux: old-glibc container (2.31) so the AppImage the - # gate builds matches the released one. An AppImage bundles its libs but NOT - # glibc, so its portability floor is the build host's - see the ci-main comment. - container: ubuntu:20.04 + # Mirrors ci-main's build-linux: debian:11 (glibc 2.31) + jsoncpp 1.9.5 built + # from source, so the AppImage the gate builds matches the release and compiles + # - see the ci-main comment for the jsoncpp/glibc reasoning. + container: debian:11 timeout-minutes: 60 defaults: run: @@ -377,7 +377,7 @@ jobs: git ca-certificates wget file pkg-config python3 \ cmake g++ make patchelf \ libsdl1.2-dev libsdl-mixer1.2-dev libsdl-gfx1.2-dev libsdl-image1.2-dev libsdl-net1.2-dev \ - libyaml-cpp-dev libjsoncpp-dev libsodium-dev zlib1g-dev + libyaml-cpp-dev libsodium-dev zlib1g-dev then ok=1; break; fi echo "apt attempt $n failed (mirror flake); retrying in $((n * 15))s" sleep $((n * 15)) @@ -390,15 +390,34 @@ jobs: persist-credentials: false submodules: recursive + - name: Build jsoncpp 1.9.5 from source + # bullseye's jsoncpp (1.9.4) makes the coop code's int64/uint64 -> Json::Value + # writes ambiguous on gcc; 1.9.5 does not. Build the same jsoncpp the code is + # built against on ubuntu-latest, into /usr/local. See ci-main for detail. + run: | + set -euxo pipefail + git clone --depth 1 --branch 1.9.5 https://github.com/open-source-parsers/jsoncpp.git /tmp/jsoncpp + cmake -S /tmp/jsoncpp -B /tmp/jsoncpp/build \ + -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \ + -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF \ + -DCMAKE_INSTALL_PREFIX=/usr/local + cmake --build /tmp/jsoncpp/build -j"$(nproc)" + cmake --install /tmp/jsoncpp/build + ldconfig + - name: Configure + build (Linux x86_64) run: | set -euxo pipefail - # ubuntu's libjsoncpp-dev installs headers under /usr/include/jsoncpp; - # the code includes , so add jsoncpp's include dir. + # Prefer the from-source jsoncpp in /usr/local (its .pc for -I, its lib for -l). + export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:${PKG_CONFIG_PATH:-}" + export LIBRARY_PATH="/usr/local/lib:${LIBRARY_PATH:-}" JSONCPP_CFLAGS=$(pkg-config --cflags jsoncpp) rm -rf build && mkdir -p build && cd build + # -pthread: coop code uses std::threads but CMake never links libpthread; + # separate lib on glibc 2.31 (debian:11), so force it. See ci-main. cmake -DCMAKE_BUILD_TYPE=Release -DDEV_BUILD=OFF -DBUILD_PACKAGE=OFF \ - -DCMAKE_CXX_FLAGS="$JSONCPP_CFLAGS" "$GITHUB_WORKSPACE" + -DCMAKE_CXX_FLAGS="$JSONCPP_CFLAGS -pthread" \ + -DCMAKE_EXE_LINKER_FLAGS="-pthread" "$GITHUB_WORKSPACE" make -j"$(nproc)" - name: Build AppImage (linuxdeploy) @@ -408,6 +427,8 @@ jobs: set -euxo pipefail export APPIMAGE_EXTRACT_AND_RUN=1 export PATH="$PWD:$PATH" + # so linuxdeploy's ldd resolves the from-source jsoncpp for bundling + export LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH:-}" base=https://github.com/linuxdeploy wget -q "$base/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage" wget -q "$base/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"