Skip to content

add glibc to static #35

add glibc to static

add glibc to static #35

Workflow file for this run

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