diff --git a/.github/actions/install-newer-compiler/action.yml b/.github/actions/install-newer-compiler/action.yml new file mode 100644 index 0000000000..8494216c58 --- /dev/null +++ b/.github/actions/install-newer-compiler/action.yml @@ -0,0 +1,63 @@ +name: 'Install newer compiler' +description: 'Installs ${compiler}-${version} from the distro repos when available, or from apt.llvm.org for clang on apt distros. Errors out for combinations without a known install path.' +inputs: + compiler: + description: 'gcc or clang' + required: true + version: + description: 'major version to install' + required: true + available_in_distro: + description: 'true if compiler-${version} is in the distro repos (verify-compiler output)' + required: true + packageManager: + description: 'apt, dnf, pacman, or zypper' + required: true +runs: + using: composite + steps: + - shell: bash + run: | + install_apt() { + local compiler="$1" version="$2" + case "$compiler" in + gcc) apt-get -y install "gcc-${version}" "g++-${version}" ;; + clang) apt-get -y install "clang-${version}" ;; + esac + } + + install_zypper() { + local compiler="$1" version="$2" + case "$compiler" in + gcc) zypper --non-interactive in "gcc${version}" "gcc${version}-c++" ;; + clang) zypper --non-interactive in "clang${version}" ;; + esac + } + + bootstrap_apt_llvm_and_install() { + local version="$1" + apt-get update + apt-get -y install --no-install-recommends wget lsb-release gnupg ca-certificates software-properties-common + wget -q https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + ./llvm.sh "$version" + } + + fail_no_path() { + local compiler="$1" version="$2" + echo "Minimum version not readily available." >&2 + echo "An alternative installation method for ${compiler} ${version} is needed." >&2 + exit 1 + } + + compiler='${{ inputs.compiler }}' + version='${{ inputs.version }}' + available_in_distro='${{ inputs.available_in_distro }}' + package_manager='${{ inputs.packageManager }}' + + case "$package_manager:$available_in_distro:$compiler" in + apt:true:*) install_apt "$compiler" "$version" ;; + apt:false:clang) bootstrap_apt_llvm_and_install "$version" ;; + zypper:true:*) install_zypper "$compiler" "$version" ;; + *) fail_no_path "$compiler" "$version" ;; + esac diff --git a/.github/actions/install-sdl2-net/action.yml b/.github/actions/install-sdl2-net/action.yml new file mode 100644 index 0000000000..48826924d5 --- /dev/null +++ b/.github/actions/install-sdl2-net/action.yml @@ -0,0 +1,16 @@ +name: 'Install SDL2_net from source' +description: 'Build and install SDL2_net from source. Used when the distro-shipped SDL2_net is older than 2.2.0 (no cmake config file).' +runs: + using: composite + steps: + - shell: bash + run: | + if [ "$(id -u)" -ne 0 ]; then SUDO=sudo; else SUDO=""; fi + mkdir -p deps + if [ ! -d "deps/SDL2_net-2.2.0" ]; then + curl -fsSL https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz | tar xz -C deps + fi + cd deps/SDL2_net-2.2.0 + ./configure + make + $SUDO make install diff --git a/.github/actions/install-tinyxml2/action.yml b/.github/actions/install-tinyxml2/action.yml new file mode 100644 index 0000000000..0363143f33 --- /dev/null +++ b/.github/actions/install-tinyxml2/action.yml @@ -0,0 +1,18 @@ +name: 'Install tinyxml2 from source' +description: 'Build and install tinyxml2 from source. Used when the distro-shipped tinyxml2 is older than 10.0.0 (no cmake config file).' +runs: + using: composite + steps: + - shell: bash + run: | + if [ "$(id -u)" -ne 0 ]; then SUDO=sudo; else SUDO=""; fi + mkdir -p deps + if [ ! -d "deps/tinyxml2-10.0.0" ]; then + curl -fsSL https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz | tar xz -C deps + fi + cd deps/tinyxml2-10.0.0 + mkdir -p build + cd build + cmake .. + make + $SUDO make install diff --git a/.github/actions/verify-compiler/action.yml b/.github/actions/verify-compiler/action.yml new file mode 100644 index 0000000000..d92ec8bb25 --- /dev/null +++ b/.github/actions/verify-compiler/action.yml @@ -0,0 +1,72 @@ +name: 'Verify compiler version meets the project minimum' +description: 'Compares the installed compiler against the version in linux-build-deps/minimum-${compiler}-version.txt and reports whether we need to install a newer version and whether that version is available in the distro repos.' +inputs: + compiler: + description: 'gcc or clang' + required: true + packageManager: + description: 'apt, dnf, pacman, or zypper' + required: true +outputs: + needs_install: + description: 'true if default version is below the minimum' + value: ${{ steps.check.outputs.needs_install }} + available_in_distro: + description: 'true if compiler-${min} can be installed from the distro repos' + value: ${{ steps.check.outputs.available_in_distro }} + cc: + description: 'resolved C compiler binary name to use downstream' + value: ${{ steps.check.outputs.cc }} + cxx: + description: 'resolved C++ compiler binary name to use downstream' + value: ${{ steps.check.outputs.cxx }} + version: + description: 'the minimum version read from linux-build-deps/minimum-${compiler}-version.txt' + value: ${{ steps.check.outputs.version }} +runs: + using: composite + steps: + - id: check + shell: bash + run: | + get_min() { cat "linux-build-deps/minimum-$1-version.txt"; } + get_default_major() { "$1" --version 2>/dev/null | head -1 | grep -oE '[0-9]+' | head -1; } + cxx_for() { case "$1" in gcc) echo g++ ;; clang) echo clang++ ;; esac; } + + probe_distro() { + local compiler="$1" min="$2" package_manager="$3" + case "$package_manager" in + apt) apt-cache show "${compiler}-${min}" >/dev/null 2>&1 ;; + dnf) return 1 ;; # Fedora ships a single gcc/clang version, no -N packages + pacman) return 1 ;; # Arch ships a single gcc/clang version, no -N packages + zypper) zypper -n se -x "${compiler}${min}" 2>/dev/null | grep -q "${compiler}${min}" ;; + *) return 1 ;; + esac + } + + compiler='${{ inputs.compiler }}' + package_manager='${{ inputs.packageManager }}' + min=$(get_min "$compiler") + default_major=$(get_default_major "$compiler") + cc_base="$compiler" + cxx_base=$(cxx_for "$compiler") + + if [ -n "$default_major" ] && [ "$default_major" -ge "$min" ]; then + needs_install=false + cc="$cc_base"; cxx="$cxx_base" + available_in_distro=true + else + needs_install=true + cc="$cc_base-$min"; cxx="$cxx_base-$min" + probe_distro "$cc_base" "$min" "$package_manager" && available_in_distro=true || available_in_distro=false + fi + + echo "compiler=$compiler min=$min default_major=${default_major:-NONE}" + echo "needs_install=$needs_install available_in_distro=$available_in_distro cc=$cc cxx=$cxx" + { + echo "needs_install=$needs_install" + echo "available_in_distro=$available_in_distro" + echo "cc=$cc" + echo "cxx=$cxx" + echo "version=$min" + } >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/generate-builds.yml b/.github/workflows/generate-builds.yml index d91aab103a..8a582e1bcf 100644 --- a/.github/workflows/generate-builds.yml +++ b/.github/workflows/generate-builds.yml @@ -25,7 +25,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) libzip-dev zipcmp zipmerge ziptool + sudo apt-get install -y $(cat linux-build-deps/apt.txt) - name: Restore Cached deps folder uses: actions/cache/restore@v5 with: @@ -36,9 +36,12 @@ jobs: path: deps - name: Create deps folder run: mkdir -p deps + - name: Add ccache to PATH + run: | + echo "/usr/lib/ccache" >> "$GITHUB_PATH" + echo "/usr/local/opt/ccache/libexec" >> "$GITHUB_PATH" - name: Install latest SDL run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" if [ ! -d "deps/SDL2-2.30.3" ]; then wget https://github.com/libsdl-org/SDL/releases/download/release-2.30.3/SDL2-2.30.3.tar.gz tar -xzf SDL2-2.30.3.tar.gz -C deps @@ -48,35 +51,14 @@ jobs: make -j 10 sudo make install sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ - - name: Install latest SDL_net - run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - if [ ! -d "deps/SDL2_net-2.2.0" ]; then - wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz - tar -xzf SDL2_net-2.2.0.tar.gz -C deps - fi - cd deps/SDL2_net-2.2.0 - ./configure - make -j 10 - sudo make install - sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ - - name: Install latest tinyxml2 - run: | - sudo apt-get remove libtinyxml2-dev - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - if [ ! -d "deps/tinyxml2-10.0.0" ]; then - wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz - tar -xzf 10.0.0.tar.gz -C deps - fi - cd deps/tinyxml2-10.0.0 - mkdir -p build - cd build - cmake .. - make - sudo make install + - uses: ./.github/actions/install-sdl2-net + - name: Copy SDL libs to multiarch dir + run: sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ + - name: Remove distro tinyxml2 + run: sudo apt-get remove libtinyxml2-dev + - uses: ./.github/actions/install-tinyxml2 - name: Generate soh.o2r run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release cmake --build build-cmake --config Release --target GenerateSohOtr -j3 - name: Upload soh.o2r @@ -137,7 +119,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) + sudo apt-get install -y $(cat linux-build-deps/apt.txt) - name: Configure ccache uses: hendrikmuhs/ccache-action@v1.2.22 with: @@ -157,9 +139,12 @@ jobs: path: deps - name: Create deps folder run: mkdir -p deps + - name: Add ccache to PATH + run: | + echo "/usr/lib/ccache" >> "$GITHUB_PATH" + echo "/usr/local/opt/ccache/libexec" >> "$GITHUB_PATH" - name: Install latest SDL run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" if [ ! -d "deps/SDL2-2.30.3" ]; then wget https://github.com/libsdl-org/SDL/releases/download/release-2.30.3/SDL2-2.30.3.tar.gz tar -xzf SDL2-2.30.3.tar.gz -C deps @@ -169,35 +154,15 @@ jobs: make -j 10 sudo make install sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ - - name: Install latest SDL_net - run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - if [ ! -d "deps/SDL2_net-2.2.0" ]; then - wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz - tar -xzf SDL2_net-2.2.0.tar.gz -C deps - fi - cd deps/SDL2_net-2.2.0 - ./configure - make -j 10 - sudo make install - sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ - - name: Install latest tinyxml2 - run: | - sudo apt-get remove libtinyxml2-dev - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - if [ ! -d "deps/tinyxml2-10.0.0" ]; then - wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz - tar -xzf 10.0.0.tar.gz -C deps - fi - cd deps/tinyxml2-10.0.0 - mkdir -p build - cd build - cmake .. - make - sudo make install + - uses: ./.github/actions/install-sdl2-net + - name: Copy SDL libs to multiarch dir + run: sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ + - name: Remove distro tinyxml2 + run: sudo apt-get remove libtinyxml2-dev + - uses: ./.github/actions/install-tinyxml2 - name: Install libzip without crypto run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + sudo apt-get remove -y libzip-dev if [ ! -d "deps/libzip-1.10.1" ]; then wget https://github.com/nih-at/libzip/releases/download/v1.10.1/libzip-1.10.1.tar.gz tar -xzf libzip-1.10.1.tar.gz -C deps @@ -216,7 +181,6 @@ jobs: path: build-cmake/soh - name: Build SoH run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_REMOTE_CONTROL=1 cmake --build build-cmake --config Release -j3 (cd build-cmake && cpack -G External) diff --git a/.github/workflows/test-builds-on-distros.yml b/.github/workflows/test-builds-on-distros.yml index 4da692e2c5..96f9132019 100644 --- a/.github/workflows/test-builds-on-distros.yml +++ b/.github/workflows/test-builds-on-distros.yml @@ -5,68 +5,200 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: + setup: + runs-on: ubuntu-latest + outputs: + distros: ${{ steps.set-matrix.outputs.distros }} + steps: + - name: Resolve distro images + id: set-matrix + uses: actions/github-script@v9 + with: + script: | + const today = new Date().toISOString().slice(0, 10); + const fetchJson = async (url) => { + const res = await fetch(url); + if (!res.ok) throw new Error(`${url} -> ${res.status}`); + return res.json(); + }; + + // All non-EOL Ubuntu LTS releases. + const ubuntuCycles = await fetchJson('https://endoflife.date/api/ubuntu.json'); + const ubuntu = ubuntuCycles + .filter(c => c.lts === true && c.eol > today) + .map(c => ({ image: `ubuntu:${c.cycle}`, packageManager: 'apt' })); + + // All non-EOL Fedora releases. + const fedoraCycles = await fetchJson('https://endoflife.date/api/fedora.json'); + const fedora = fedoraCycles + .filter(c => c.eol > today) + .map(c => ({ image: `fedora:${c.cycle}`, packageManager: 'dnf' })); + + // Rolling. + const arch = [{ image: 'archlinux:base', packageManager: 'pacman' }]; + + // Rolling Tumbleweed and all non-EOL Leap releases. + const leapCycles = await fetchJson('https://endoflife.date/api/opensuse.json'); + const opensuse = [ + { image: 'opensuse/tumbleweed:latest', packageManager: 'zypper' }, + ...leapCycles + .filter(c => c.eol > today) + .map(c => ({ image: `opensuse/leap:${c.cycle}`, packageManager: 'zypper' })), + ]; + + // Previous, current, and next Debian releases. + const debian = ['oldstable', 'stable', 'testing'] + .map(t => ({ image: `debian:${t}`, packageManager: 'apt' })); + + const distros = [...ubuntu, ...fedora, ...arch, ...opensuse, ...debian]; + core.info(`Resolved distros: ${JSON.stringify(distros)}`); + core.setOutput('distros', JSON.stringify(distros)); build: + needs: setup + name: build (${{ matrix.distro.image }}, ${{ matrix.cc }}) strategy: + fail-fast: false matrix: - image: ["archlinux:base", "opensuse/tumbleweed:latest", "ubuntu:mantic", "debian:bookworm", "fedora:39"] - cc: ["gcc", "clang"] + distro: ${{ fromJSON(needs.setup.outputs.distros) }} + cc: ["gcc", "clang"] include: - cxx: g++ cc: gcc - cxx: clang++ cc: clang - runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }} + runs-on: ubuntu-latest container: - image: ${{ matrix.image }} + image: ${{ matrix.distro.image }} steps: - - name: Install dependencies (pacman) - if: ${{ matrix.image == 'archlinux:base' }} + - name: Bootstrap git run: | - echo arch - echo pacman -S ${{ matrix.cc }} git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net - pacman -Syu --noconfirm - pacman -S --noconfirm ${{ matrix.cc }} git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net - - name: Install dependencies (dnf) - if: ${{ matrix.image == 'fedora:39' }} - run: | - echo fedora - echo dnf install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} wget git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools tinyxml2-devel spdlog-devel - dnf -y upgrade - dnf -y install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} wget git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools tinyxml2-devel spdlog-devel - - name: Install dependencies (apt) - if: ${{ matrix.image == 'ubuntu:mantic' || matrix.image == 'debian:bookworm' }} - run: | - echo debian based - echo apt-get install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'g++') || '' }} git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libopengl-dev - apt-get update - apt-get -y full-upgrade - apt-get -y install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'g++') || '' }} git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libopengl-dev - - name: Install dependencies (zypper) - if: ${{ matrix.image == 'opensuse/tumbleweed:latest' }} - run: | - echo openSUSE - echo zypper in ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} ${{ matrix.cc == 'clang' && 'libstdc++-devel' || '' }} git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel - zypper --non-interactive dup - zypper --non-interactive in ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} ${{ matrix.cc == 'clang' && 'libstdc++-devel' || '' }} git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel - - name: Install latest nlohmann - if: ${{ matrix.image == 'fedora:39' }} - run: | - wget https://github.com/nlohmann/json/archive/refs/tags/v3.11.3.tar.gz - tar -xzvf v3.11.3.tar.gz - cd json-3.11.3 - mkdir build - cd build - cmake .. - make - sudo make install + case "${{ matrix.distro.packageManager }}" in + apt) apt-get update && apt-get -y install git ;; + dnf) dnf -y install git ;; + pacman) pacman -Sy --noconfirm git ;; + zypper) zypper --non-interactive in git ;; + esac - uses: actions/checkout@v6 with: submodules: true + - name: Install dependencies (pacman) + if: ${{ matrix.distro.packageManager == 'pacman' }} + run: | + pacman -Syu --noconfirm + pacman -S --noconfirm ${{ matrix.cc }} $(cat linux-build-deps/pacman.txt) + - name: Install dependencies (dnf) + if: ${{ matrix.distro.packageManager == 'dnf' }} + run: | + dnf -y upgrade + dnf -y install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} $(cat linux-build-deps/dnf.txt) + - name: Install dependencies (apt) + if: ${{ matrix.distro.packageManager == 'apt' }} + run: | + apt-get update + apt-get -y full-upgrade + apt-get -y install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'g++') || '' }} $(cat linux-build-deps/apt.txt) + - name: Install dependencies (zypper) + if: ${{ matrix.distro.packageManager == 'zypper' }} + run: | + zypper --non-interactive dup + zypper --non-interactive in ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} ${{ matrix.cc == 'clang' && 'libstdc++-devel' || '' }} $(cat linux-build-deps/zypper.txt) + - name: Verify compiler version + id: verify-compiler + uses: ./.github/actions/verify-compiler + with: + compiler: ${{ matrix.cc }} + packageManager: ${{ matrix.distro.packageManager }} + - name: Install newer compiler + if: ${{ steps.verify-compiler.outputs.needs_install == 'true' }} + uses: ./.github/actions/install-newer-compiler + with: + compiler: ${{ matrix.cc }} + version: ${{ steps.verify-compiler.outputs.version }} + available_in_distro: ${{ steps.verify-compiler.outputs.available_in_distro }} + packageManager: ${{ matrix.distro.packageManager }} + - name: Verify/update cmake + run: | + ver_le() { [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -1)" = "$1" ]; } + required=$(grep -m1 -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' CMakeLists.txt) + installed=$(cmake --version | grep -m1 -oE '[0-9]+\.[0-9]+(\.[0-9]+)?') + echo "cmake required: $required installed: $installed" + if ver_le "$required" "$installed"; then + echo "ok" + else + case "${{ matrix.distro.packageManager }}" in + apt) DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends pipx ;; + dnf) dnf -y install pipx ;; + pacman) pacman -S --noconfirm python-pipx ;; + zypper) zypper --non-interactive in python3-pipx ;; + esac + pipx install cmake + echo "$HOME/.local/bin" >> "$GITHUB_PATH" + fi + - name: Verify/update tinyxml2 + id: tinyxml2-check + if: ${{ matrix.distro.packageManager == 'apt' }} + run: | + if find /usr -iname 'tinyxml2*config.cmake' 2>/dev/null | grep -q .; then + echo "ok" + echo "needs_install=false" >> "$GITHUB_OUTPUT" + else + apt-get remove -y libtinyxml2-dev + apt-get install -y curl + echo "needs_install=true" >> "$GITHUB_OUTPUT" + fi + - uses: ./.github/actions/install-tinyxml2 + if: ${{ steps.tinyxml2-check.outputs.needs_install == 'true' }} + - name: Verify/update SDL2_net + id: sdl2-net-check + if: ${{ matrix.distro.packageManager == 'apt' }} + run: | + if find /usr -iname 'sdl2_net*config.cmake' 2>/dev/null | grep -q .; then + echo "ok" + echo "needs_install=false" >> "$GITHUB_OUTPUT" + else + apt-get install -y curl + echo "needs_install=true" >> "$GITHUB_OUTPUT" + fi + - uses: ./.github/actions/install-sdl2-net + if: ${{ steps.sdl2-net-check.outputs.needs_install == 'true' }} + # https://github.com/fmtlib/fmt/issues/4807 + - name: Check fmt/clang consteval compat + id: fmt-check + shell: bash + run: | + cat > /tmp/fmt-consteval-test.cpp <<'EOF' + #include + int main() { auto s = fmt::format(FMT_STRING("{}"), 42); return 0; } + EOF + if "$CXX" -std=c++20 -c /tmp/fmt-consteval-test.cpp -o /tmp/fmt-consteval-test.o; then + echo "ok — fmt/clang consteval compatible" + echo "needs_workaround=false" >> "$GITHUB_OUTPUT" + else + echo "incompatible — applying workaround" + echo "needs_workaround=true" >> "$GITHUB_OUTPUT" + fi + env: + CXX: ${{ steps.verify-compiler.outputs.cxx }} - name: Build SoH run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_REMOTE_CONTROL=1 + cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_REMOTE_CONTROL=1 ${EXTRA_CMAKE_FLAGS} cmake --build build-cmake --config Release -j3 env: - CC: ${{ matrix.cc }} - CXX: ${{ matrix.cxx }} + CC: ${{ steps.verify-compiler.outputs.cc }} + CXX: ${{ steps.verify-compiler.outputs.cxx }} + # https://github.com/fmtlib/fmt/issues/4807 + EXTRA_CMAKE_FLAGS: ${{ steps.fmt-check.outputs.needs_workaround == 'true' && '-DCMAKE_CXX_FLAGS=-DFMT_CONSTEVAL=constexpr' || '' }} + build-nix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: true + - uses: cachix/install-nix-action@v31 + - name: Build SoH in nix dev shell + run: | + nix develop ./linux-build-deps -c bash -c ' + cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_REMOTE_CONTROL=1 + cmake --build build-cmake --config Release -j3 + ' diff --git a/docs/BUILDING.md b/docs/BUILDING.md index dca45005a2..4a6ba5faec 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -86,118 +86,77 @@ C:\Program Files\CMake\bin\cmake.exe --build build-cmake --target ExtractAssetHe ``` ## Linux +### Clone the repo and enter the directory +```sh +git clone https://github.com/HarbourMasters/Shipwright.git +cd Shipwright +``` ### Install dependencies + +> [!IMPORTANT] +> Minimum compiler versions: +> - GCC: see [`linux-build-deps/minimum-gcc-version.txt`](../linux-build-deps/minimum-gcc-version.txt) +> - Clang: see [`linux-build-deps/minimum-clang-version.txt`](../linux-build-deps/minimum-clang-version.txt) + #### Debian/Ubuntu ```sh # using gcc -apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libopengl-dev libopusfile-dev libvorbis-dev +apt-get install gcc g++ $(cat linux-build-deps/apt.txt) # or using clang -apt-get install clang git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libopengl-dev libopusfile-dev libvorbis-dev +apt-get install clang $(cat linux-build-deps/apt.txt) ``` #### Arch ```sh # using gcc -pacman -S gcc git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net opusfile libvorbis +pacman -S gcc $(cat linux-build-deps/pacman.txt) # or using clang -pacman -S clang git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net opusfile libvorbis +pacman -S clang $(cat linux-build-deps/pacman.txt) ``` #### Fedora ```sh # using gcc -dnf install gcc gcc-c++ git cmake ninja-build lsb_release SDL2-devel SDL2_net-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel opusfile-devel libvorbis-devel +dnf install gcc gcc-c++ $(cat linux-build-deps/dnf.txt) # or using clang -dnf install clang git cmake ninja-build lsb_release SDL2-devel SDL2_net-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel opusfile-devel libvorbis-devel +dnf install clang $(cat linux-build-deps/dnf.txt) +``` +#### openSUSE +```sh +# using gcc +zypper in gcc gcc-c++ $(cat linux-build-deps/zypper.txt) + +# or using clang +zypper in clang libstdc++-devel $(cat linux-build-deps/zypper.txt) ``` #### Nix -You can use a `flake.nix` file to instantly setup a development environment using [Nix](https://nixos.org/). Write this `flake.nix` file in the root directory: +This repository provides a [`linux-build-deps/flake.nix`](../linux-build-deps/flake.nix) for setting up a development environment using [Nix](https://nixos.org/). -```nix -{ - description = "Shipwright development environment"; +Run - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - pinned.url = "github:NixOS/nixpkgs/e6f23dc08d3624daab7094b701aa3954923c6bbb"; - flake-utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, nixpkgs, pinned, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - pinned-pkgs = pinned.legacyPackages.${system}; - in - { - devShells.default = pkgs.mkShell { - buildInputs = with pkgs; [ - # Build tools - git - cmake - ninja - lsb-release - pkg-config - - # SDL2 libraries - SDL2 - SDL2.dev - SDL2_net - - # Assets pipeline - python3 - imagemagick - - # Other libraries - libpng - libzip - nlohmann_json - tinyxml-2 - spdlog - libGL - libGL.dev - bzip2 - - # X11 libraries - libx11 - - # Audio libraries - libogg - libogg.dev - libvorbis - libvorbis.dev - libopus - libopus.dev - opusfile - opusfile.dev - - # Runtime dependencies - zenity - ] ++ [ - # Version of clang-format used by decomp - pinned-pkgs.clang_14 - ]; - shellHook = '' - echo "Shipwright development environment loaded" - echo "Available tools: clang, git, cmake, ninja, python3" - ''; - }; - }); -} +```sh +nix develop ./linux-build-deps ``` -Now type `nix develop` and you will be dropped into a shell with all dependencies, ensuring that all build commands work. +from the repo root and you'll be dropped into a shell with all dependencies, ensuring that all build commands work. + +### Verify cmake version +Older distros may ship a cmake older than this project requires. Compare: +```sh +cmake --version # your installed version +head -1 CMakeLists.txt # the project's required minimum +``` +If your cmake is too old, you can install a newer version via: +- [pypi](https://pypi.org/project/cmake/) +- [kitware apt repo](https://apt.kitware.com/) (Ubuntu only) +- [Homebrew](https://formulae.brew.sh/formula/cmake) ### Build _Note: If you're using Visual Studio Code, the [CMake Tools plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._ ```bash -# Clone the repo and enter the directory -git clone https://github.com/HarbourMasters/Shipwright.git -cd Shipwright - # Clone the submodules git submodule update --init @@ -218,6 +177,32 @@ cmake --build build-cmake # To develop the project open the repository in VSCode (or your preferred editor) ``` +> [!TIP] +> Some older distros ship packages without the cmake config files SoH's `find_package` calls need. If cmake fails with `Could not find a package configuration file provided by ""`. +> +> Known failing package versions: +> - [tinyxml2](https://github.com/leethomason/tinyxml2) < 10.0.0 +> - [SDL2_net](https://github.com/libsdl-org/SDL_net) < 2.2.0 +> +> You can install a newer version of that package either +> +> by using [Homebrew](https://brew.sh/): +> ```sh +> brew install +> ``` +> When invoking cmake, add `-DCMAKE_PREFIX_PATH=$(brew --prefix)` so it knows to search brew's prefix for the installed package. +> +> ***OR*** +> +> by building from source: +> +> Reference examples: +> - [`.github/actions/install-tinyxml2/action.yml`](../.github/actions/install-tinyxml2/action.yml) +> - [`.github/actions/install-sdl2-net/action.yml`](../.github/actions/install-sdl2-net/action.yml) + +> [!TIP] +> There are known incompatibilities between some newer versions of `clang` and older versions of [`{fmt}`](https://github.com/fmtlib/fmt) (see https://github.com/fmtlib/fmt/issues/4807). If you see a `call to consteval function 'fmt::basic_format_string<...>' is not a constant expression` error, you can work around it by passing `-DCMAKE_CXX_FLAGS=-DFMT_CONSTEVAL=constexpr` to `cmake`. + ### Generate a distributable After compiling the project you can generate a distributable by running of the following: ```bash diff --git a/linux-build-deps/README.md b/linux-build-deps/README.md new file mode 100644 index 0000000000..bdf5d411c5 --- /dev/null +++ b/linux-build-deps/README.md @@ -0,0 +1,11 @@ +# Linux build dependencies + +This directory contains plaintext files with package lists and minimum version information for building on Linux systems. + +## `apt` vs others + +The CI workflows that run on PRs and pushes use GH actions Ubuntu runners, so it is very unlikely `apt.txt` will be missing anything. The other package list files are only verified by the `test-builds-on-distros` workflow, which is triggered manually. + +## How you can help + +If you run into a missing package issue when building please let us know! A PR updating the appropriate package list file would be wonderful, but opening a GH issue or just saying something on Discord works too! diff --git a/.github/workflows/apt-deps.txt b/linux-build-deps/apt.txt similarity index 69% rename from .github/workflows/apt-deps.txt rename to linux-build-deps/apt.txt index dba3511bf4..d90872d59f 100644 --- a/.github/workflows/apt-deps.txt +++ b/linux-build-deps/apt.txt @@ -1 +1 @@ -libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev nlohmann-json3-dev libtinyxml2-dev libspdlog-dev ninja-build libogg-dev libopus-dev opus-tools libopusfile-dev libvorbis-dev libespeak-ng-dev \ No newline at end of file +libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev nlohmann-json3-dev libtinyxml2-dev libspdlog-dev ninja-build libogg-dev libopus-dev opus-tools libopusfile-dev libvorbis-dev libespeak-ng-dev libzip-dev zipcmp zipmerge ziptool git cmake lsb-release \ No newline at end of file diff --git a/linux-build-deps/dnf.txt b/linux-build-deps/dnf.txt new file mode 100644 index 0000000000..70b3133f17 --- /dev/null +++ b/linux-build-deps/dnf.txt @@ -0,0 +1 @@ +git cmake ninja-build lsb_release SDL2-devel SDL2_net-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel opusfile-devel libvorbis-devel diff --git a/linux-build-deps/flake.nix b/linux-build-deps/flake.nix new file mode 100644 index 0000000000..3b10800fe3 --- /dev/null +++ b/linux-build-deps/flake.nix @@ -0,0 +1,70 @@ +{ + description = "Shipwright development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + pinned.url = "github:NixOS/nixpkgs/e6f23dc08d3624daab7094b701aa3954923c6bbb"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, pinned, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + pinned-pkgs = pinned.legacyPackages.${system}; + in + { + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + # Build tools + git + cmake + ninja + lsb-release + pkg-config + + # SDL2 libraries + SDL2 + SDL2.dev + SDL2_net + + # Assets pipeline + python3 + imagemagick + + # Other libraries + libpng + libzip + nlohmann_json + tinyxml-2 + spdlog + libGL + libGL.dev + bzip2 + + # X11 libraries + libx11 + + # Audio libraries + libogg + libogg.dev + libvorbis + libvorbis.dev + libopus + libopus.dev + opusfile + opusfile.dev + + # Runtime dependencies + zenity + ] ++ [ + # Version of clang-format used by decomp + pinned-pkgs.clang_14 + ]; + shellHook = '' + echo "Shipwright development environment loaded" + echo "Available tools: clang, git, cmake, ninja, python3" + ''; + }; + }); +} diff --git a/linux-build-deps/minimum-clang-version.txt b/linux-build-deps/minimum-clang-version.txt new file mode 100644 index 0000000000..b6a7d89c68 --- /dev/null +++ b/linux-build-deps/minimum-clang-version.txt @@ -0,0 +1 @@ +16 diff --git a/linux-build-deps/minimum-gcc-version.txt b/linux-build-deps/minimum-gcc-version.txt new file mode 100644 index 0000000000..f599e28b8a --- /dev/null +++ b/linux-build-deps/minimum-gcc-version.txt @@ -0,0 +1 @@ +10 diff --git a/linux-build-deps/pacman.txt b/linux-build-deps/pacman.txt new file mode 100644 index 0000000000..6c1cd5bb0f --- /dev/null +++ b/linux-build-deps/pacman.txt @@ -0,0 +1 @@ +git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net opusfile libvorbis python diff --git a/linux-build-deps/zypper.txt b/linux-build-deps/zypper.txt new file mode 100644 index 0000000000..43932667dc --- /dev/null +++ b/linux-build-deps/zypper.txt @@ -0,0 +1 @@ +git cmake ninja SDL2-devel SDL2_net-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel libogg-devel libvorbis-devel libopus-devel opusfile-devel glew-devel libglvnd-devel Mesa-libGLESv2-devel