add glibc to static #35
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: Build and Release | |
| on: | |
| push: | |
| branches: [ main, master ] | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: [ main, master ] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| # ═══════════════════════════════════════════════════════════════════ | |
| # Linux — Ubuntu, dynamic linking, bundle .so files | |
| # ═══════════════════════════════════════════════════════════════════ | |
| build-linux: | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: amd64 | |
| artifact: phira-mp-server-linux-amd64 | |
| deb_arch: amd64 | |
| triple: x86_64-linux-gnu | |
| cxx: g++ | |
| cc: gcc | |
| cross_pkg: "" | |
| is_cross: false | |
| - arch: arm64 | |
| artifact: phira-mp-server-linux-arm64 | |
| deb_arch: arm64 | |
| triple: aarch64-linux-gnu | |
| cxx: aarch64-linux-gnu-g++ | |
| cc: aarch64-linux-gnu-gcc | |
| cross_pkg: g++-aarch64-linux-gnu | |
| is_cross: true | |
| - arch: armhf | |
| artifact: phira-mp-server-linux-armhf | |
| deb_arch: armhf | |
| triple: arm-linux-gnueabihf | |
| cxx: arm-linux-gnueabihf-g++ | |
| cc: arm-linux-gnueabihf-gcc | |
| cross_pkg: g++-arm-linux-gnueabihf | |
| is_cross: true | |
| env: | |
| SYSROOT: /home/runner/sysroot | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up multiarch apt (cross-compile only) | |
| if: matrix.is_cross | |
| run: | | |
| sudo dpkg --add-architecture ${{ matrix.deb_arch }} | |
| sudo sed -i '/^URIs:/i Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources | |
| CODENAME=$(lsb_release -cs) | |
| printf 'Types: deb\nURIs: http://ports.ubuntu.com/ubuntu-ports\nSuites: %s %s-updates %s-security\nComponents: main universe\nArchitectures: %s\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\n' \ | |
| "$CODENAME" "$CODENAME" "$CODENAME" "${{ matrix.deb_arch }}" \ | |
| | sudo tee /etc/apt/sources.list.d/${{ matrix.deb_arch }}-cross.sources | |
| sudo apt-get update | |
| - name: Install tools and cross-compiler | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y build-essential make pkg-config cmake ninja-build patchelf | |
| if [ -n "${{ matrix.cross_pkg }}" ]; then | |
| sudo apt-get install -y ${{ matrix.cross_pkg }} | |
| fi | |
| - name: Install library dependencies from apt | |
| run: | | |
| S="" | |
| if [ "${{ matrix.is_cross }}" = "true" ]; then S=":${{ matrix.deb_arch }}"; fi | |
| sudo apt-get install -y libboost-dev nlohmann-json3-dev | |
| sudo apt-get install -y \ | |
| libssl-dev${S} \ | |
| libcurl4-openssl-dev${S} \ | |
| zlib1g-dev${S} \ | |
| uuid-dev${S} \ | |
| libsqlite3-dev${S} | |
| - name: Prepare sysroot | |
| run: mkdir -p $SYSROOT/lib/pkgconfig $SYSROOT/include | |
| - name: Build fmt from source | |
| run: | | |
| cd /tmp && git clone --depth 1 --branch 10.2.1 https://github.com/fmtlib/fmt.git && cd fmt | |
| cmake -B build -G Ninja \ | |
| -DCMAKE_C_COMPILER=${{ matrix.cc }} \ | |
| -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ | |
| -DCMAKE_INSTALL_PREFIX=$SYSROOT \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DBUILD_SHARED_LIBS=OFF -DFMT_TEST=OFF -DFMT_DOC=OFF | |
| cmake --build build -j$(nproc) && cmake --install build | |
| - name: Build spdlog from source | |
| run: | | |
| cd /tmp && git clone --depth 1 --branch v1.14.1 https://github.com/gabime/spdlog.git && cd spdlog | |
| cmake -B build -G Ninja \ | |
| -DCMAKE_C_COMPILER=${{ matrix.cc }} \ | |
| -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ | |
| -DCMAKE_INSTALL_PREFIX=$SYSROOT \ | |
| -DCMAKE_PREFIX_PATH=$SYSROOT \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DSPDLOG_BUILD_EXAMPLE=OFF -DSPDLOG_BUILD_TESTS=OFF \ | |
| -DSPDLOG_FMT_EXTERNAL=ON | |
| cmake --build build -j$(nproc) && cmake --install build | |
| - name: Build argon2 from source | |
| run: | | |
| cd /tmp && git clone --depth 1 https://github.com/P-H-C/phc-winner-argon2.git && cd phc-winner-argon2 | |
| ${{ matrix.cc }} -std=c89 -O2 -fPIC -c src/argon2.c -Iinclude -o argon2.o | |
| ${{ matrix.cc }} -std=c89 -O2 -fPIC -c src/core.c -Iinclude -o core.o | |
| ${{ matrix.cc }} -std=c89 -O2 -fPIC -c src/blake2/blake2b.c -Iinclude -o blake2b.o | |
| ${{ matrix.cc }} -std=c89 -O2 -fPIC -c src/thread.c -Iinclude -o thread.o | |
| ${{ matrix.cc }} -std=c89 -O2 -fPIC -c src/encoding.c -Iinclude -o encoding.o | |
| ${{ matrix.cc }} -std=c89 -O2 -fPIC -c src/ref.c -Iinclude -o ref.o | |
| ar rcs $SYSROOT/lib/libargon2.a argon2.o core.o blake2b.o thread.o encoding.o ref.o | |
| cp include/argon2.h $SYSROOT/include/ | |
| - name: Build phira-mp-server | |
| run: | | |
| LIBDIR="/usr/lib/${{ matrix.triple }}" | |
| export PKG_CONFIG_PATH="${SYSROOT}/lib/pkgconfig:${SYSROOT}/lib64/pkgconfig:${LIBDIR}/pkgconfig:/usr/share/pkgconfig" | |
| export PKG_CONFIG_LIBDIR="${PKG_CONFIG_PATH}" | |
| make -j$(nproc) \ | |
| CXX="${{ matrix.cxx }}" \ | |
| TARGET=phira-mp-server \ | |
| CXXFLAGS="-std=c++20 -Wall -Wextra -O2 -pthread \ | |
| -DLOCALES_DIR=./locales \ | |
| -DSPDLOG_FMT_EXTERNAL -DSPDLOG_COMPILED_LIB \ | |
| -I${SYSROOT}/include \ | |
| $(pkg-config --cflags openssl libcurl nlohmann_json sqlite3 2>/dev/null || true)" \ | |
| LDFLAGS="-L${SYSROOT}/lib -L${LIBDIR} \ | |
| -Wl,-rpath,'\$\$ORIGIN/lib'" \ | |
| LIBS="-lspdlog -lfmt \ | |
| -lcurl -lssl -lcrypto \ | |
| -largon2 -luuid -lz -lsqlite3 \ | |
| -lpthread -ldl" | |
| file phira-mp-server | |
| ls -lh phira-mp-server | |
| - name: Collect .so files and package | |
| run: | | |
| TRIPLE="${{ matrix.triple }}" | |
| LIBDIR="/usr/lib/${TRIPLE}" | |
| DEST="release/${{ matrix.artifact }}" | |
| mkdir -p "$DEST/lib" | |
| cp phira-mp-server "$DEST/" | |
| cp -r locales "$DEST/" | |
| # Download CA certificate bundle | |
| curl -sL -o "$DEST/cacert.pem" https://curl.se/ca/cacert.pem | |
| # ── Bundle ALL .so dependencies INCLUDING glibc ── | |
| # This makes the package fully self-contained and independent | |
| # of the target machine's glibc version. | |
| # We also bundle ld-linux (the dynamic linker) and start.sh | |
| # invokes it directly so the system ld-linux is never used. | |
| echo "=== Collecting ALL .so files (including glibc) ===" | |
| if [ "${{ matrix.is_cross }}" = "true" ]; then | |
| # Cross: use readelf NEEDED + recursive resolve | |
| collect_cross() { | |
| local binary="$1" | |
| ${{ matrix.triple }}-readelf -d "$binary" 2>/dev/null | grep NEEDED | sed 's/.*\[\(.*\)\]/\1/' | while read -r soname; do | |
| [ -f "$DEST/lib/$soname" ] && continue | |
| for dir in "$SYSROOT/lib" "$LIBDIR" "/usr/lib" "/lib/${TRIPLE}" "/usr/${{ matrix.triple }}/lib"; do | |
| real=$(find "$dir" -name "$soname" -o -name "${soname}*" 2>/dev/null | head -1) | |
| if [ -n "$real" ] && [ -e "$real" ]; then | |
| cp -L "$real" "$DEST/lib/$soname" | |
| echo " COPY: $real -> lib/$soname" | |
| # Recurse into this .so's own deps | |
| collect_cross "$DEST/lib/$soname" | |
| break | |
| fi | |
| done | |
| done | |
| } | |
| collect_cross phira-mp-server | |
| # Also copy the cross ld-linux | |
| LDSO=$(find "/usr/${{ matrix.triple }}/lib" "$LIBDIR" "/lib/${TRIPLE}" -name "ld-linux-*" -o -name "ld-*.so*" 2>/dev/null | head -1) | |
| if [ -n "$LDSO" ] && [ -e "$LDSO" ]; then | |
| LDSO_NAME=$(basename "$LDSO") | |
| cp -L "$LDSO" "$DEST/lib/$LDSO_NAME" | |
| echo " COPY ld: $LDSO -> lib/$LDSO_NAME" | |
| fi | |
| else | |
| # Native amd64: use ldd for complete recursive resolution | |
| ldd phira-mp-server 2>/dev/null | while read -r line; do | |
| soname=$(echo "$line" | awk '{print $1}') | |
| realpath=$(echo "$line" | awk '{print $3}') | |
| # Handle "not a dynamic executable" or lines without => | |
| [ -z "$realpath" ] || [ ! -f "$realpath" ] && continue | |
| [ -f "$DEST/lib/$soname" ] && continue | |
| cp -L "$realpath" "$DEST/lib/$soname" | |
| echo " COPY: $realpath -> lib/$soname" | |
| done | |
| # Copy ld-linux itself (it shows as first line without =>) | |
| LDSO=$(ldd phira-mp-server 2>/dev/null | grep 'ld-linux' | awk '{print $1}') | |
| if [ -n "$LDSO" ] && [ -f "$LDSO" ]; then | |
| LDSO_NAME=$(basename "$LDSO") | |
| cp -L "$LDSO" "$DEST/lib/$LDSO_NAME" | |
| echo " COPY ld: $LDSO -> lib/$LDSO_NAME" | |
| fi | |
| fi | |
| # ── Find the ld-linux filename for start.sh ── | |
| LDSO_FILE=$(ls "$DEST/lib"/ld-linux-* "$DEST/lib"/ld-*.so* 2>/dev/null | head -1) | |
| LDSO_BASE=$(basename "$LDSO_FILE" 2>/dev/null || echo "") | |
| # ── Create start.sh that uses the BUNDLED ld-linux ── | |
| # This is the key: by invoking ld-linux directly with --library-path, | |
| # the program uses ONLY the bundled glibc + libs, never the system's. | |
| if [ -n "$LDSO_BASE" ]; then | |
| printf '#!/bin/sh\nDIR="$(cd "$(dirname "$0")" && pwd)"\nexec "$DIR/lib/%s" --library-path "$DIR/lib" "$DIR/phira-mp-server" "$@"\n' "$LDSO_BASE" > "$DEST/start.sh" | |
| else | |
| # Fallback: LD_LIBRARY_PATH method | |
| printf '#!/bin/sh\nDIR="$(cd "$(dirname "$0")" && pwd)"\nexport LD_LIBRARY_PATH="$DIR/lib:$LD_LIBRARY_PATH"\nexec "$DIR/phira-mp-server" "$@"\n' > "$DEST/start.sh" | |
| fi | |
| chmod +x "$DEST/start.sh" | |
| echo "" | |
| echo "=== start.sh ===" | |
| cat "$DEST/start.sh" | |
| echo "" | |
| echo "=== Package contents ===" | |
| find "$DEST" -type f | sort | |
| - name: Create tarball | |
| run: cd release && tar czf ${{ matrix.artifact }}.tar.gz ${{ matrix.artifact }}/ | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: release/${{ matrix.artifact }}.tar.gz | |
| # ═══════════════════════════════════════════════════════════════════ | |
| # Windows amd64 — MSYS2 UCRT64, dynamic linking, bundle DLLs | |
| # ═══════════════════════════════════════════════════════════════════ | |
| build-windows: | |
| runs-on: windows-latest | |
| defaults: | |
| run: | |
| shell: msys2 {0} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup MSYS2 | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: UCRT64 | |
| update: true | |
| install: >- | |
| make pkgconf | |
| mingw-w64-ucrt-x86_64-gcc | |
| mingw-w64-ucrt-x86_64-boost | |
| mingw-w64-ucrt-x86_64-spdlog | |
| mingw-w64-ucrt-x86_64-fmt | |
| mingw-w64-ucrt-x86_64-nlohmann-json | |
| mingw-w64-ucrt-x86_64-curl | |
| mingw-w64-ucrt-x86_64-openssl | |
| mingw-w64-ucrt-x86_64-sqlite3 | |
| mingw-w64-ucrt-x86_64-ntldd | |
| - name: Install or build argon2 | |
| run: | | |
| pacman -S --noconfirm mingw-w64-ucrt-x86_64-argon2 2>/dev/null && exit 0 | |
| echo ">> Building argon2 from source" | |
| cd /tmp && curl -sL https://github.com/P-H-C/phc-winner-argon2/archive/refs/tags/20190702.tar.gz | tar xz | |
| cd phc-winner-argon2-20190702 | |
| gcc -std=c89 -O2 -c src/argon2.c -Iinclude -o a.o | |
| gcc -std=c89 -O2 -c src/core.c -Iinclude -o b.o | |
| gcc -std=c89 -O2 -c src/blake2/blake2b.c -Iinclude -o c.o | |
| gcc -std=c89 -O2 -c src/thread.c -Iinclude -o d.o | |
| gcc -std=c89 -O2 -c src/encoding.c -Iinclude -o e.o | |
| gcc -std=c89 -O2 -c src/ref.c -Iinclude -o f.o | |
| ar rcs libargon2.a a.o b.o c.o d.o e.o f.o | |
| cp libargon2.a /ucrt64/lib/ | |
| cp include/argon2.h /ucrt64/include/ | |
| mkdir -p /ucrt64/lib/pkgconfig | |
| printf 'prefix=/ucrt64\nlibdir=${prefix}/lib\nincludedir=${prefix}/include\n\nName: libargon2\nDescription: Argon2\nVersion: 20190702\nLibs: -L${libdir} -largon2\nCflags: -I${includedir}\n' \ | |
| > /ucrt64/lib/pkgconfig/libargon2.pc | |
| - name: Build | |
| run: | | |
| make -j$(nproc) TARGET=phira-mp-server.exe LOCALES_DIR=./locales | |
| file phira-mp-server.exe | |
| - name: Collect DLLs and package | |
| run: | | |
| DEST=release/phira-mp-server-windows-amd64 | |
| mkdir -p "$DEST" | |
| cp phira-mp-server.exe "$DEST/" | |
| echo "=== Collecting UCRT64 DLLs ===" | |
| ntldd -R phira-mp-server.exe | grep -i 'ucrt64' | awk '{print $1}' | sort -u | while IFS= read -r d | |
| do | |
| d=$(echo "$d" | tr -d '[:space:]') | |
| [ -n "$d" ] && [ -f "/ucrt64/bin/$d" ] && echo " COPY: $d" && cp "/ucrt64/bin/$d" "$DEST/" | |
| done | |
| cp -r locales "$DEST/" | |
| # Download CA certificate bundle | |
| curl -sL -o "$DEST/cacert.pem" https://curl.se/ca/cacert.pem | |
| echo "=== Package contents ===" | |
| ls -la "$DEST/" | |
| - name: Create zip | |
| shell: pwsh | |
| run: Compress-Archive -Path release/phira-mp-server-windows-amd64 -DestinationPath release/phira-mp-server-windows-amd64.zip | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: phira-mp-server-windows-amd64 | |
| path: release/phira-mp-server-windows-amd64.zip | |
| # ═══════════════════════════════════════════════════════════════════ | |
| release: | |
| needs: [build-linux, build-windows] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - run: find artifacts -type f | sort | |
| - uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| artifacts/phira-mp-server-linux-amd64/*.tar.gz | |
| artifacts/phira-mp-server-linux-arm64/*.tar.gz | |
| artifacts/phira-mp-server-linux-armhf/*.tar.gz | |
| artifacts/phira-mp-server-windows-amd64/*.zip | |
| generate_release_notes: true |