hotfix for offline build deps

(cherry picked from commit 986de03fcf)
This commit is contained in:
Alex Vanderveen
2026-08-25 09:47:15 -04:00
parent b1c3967b15
commit db2c03e109
10 changed files with 487 additions and 22 deletions
+16
View File
@@ -13,6 +13,22 @@ Normal runtime builds stage it automatically so players supply only a disc;
`bios/OpenBIOS.LICENSE` always rides alongside the shipped image.
## libchdr — CHD disc-image decompressor
[libchdr](https://github.com/rtissera/libchdr) by Romain Tisserand and
contributors, licensed **BSD-3-Clause** (notice: `LICENSE.txt` inside the
archive). Vendored as the pinned source archive
`third_party/libchdr-<commit>.tar.gz`; the commit, digest, and upstream URL are
recorded in `third_party/deps.manifest`, and `runtime/chd_dependency.cmake`
verifies the archive against that digest before building it. It is compiled
into the runtime as a static library, so the BSD notice must ship with any
binary that links it.
The archive also carries libchdr's own bundled decompressors — Zstandard
(BSD-3-Clause / GPL-2.0 dual), LZMA SDK (public domain), and miniz (MIT) —
built from the same pinned tree; `WITH_SYSTEM_ZLIB`/`WITH_SYSTEM_ZSTD` are
forced OFF so the disc decoder cannot change with the host's packages.
## TinyCC (TCC) — toolchain-free overlay compiler shipped to players
[TinyCC](https://bellard.org/tcc/) by Fabrice Bellard and contributors, licensed
+166
View File
@@ -0,0 +1,166 @@
include_guard(GLOBAL)
# ---------------------------------------------------------------------------
# Offline-capable resolution of the FetchContent dependencies this tree pulls.
#
# A shipped game is configured and built on the *player's* machine, and that
# machine frequently cannot reach github.com: corporate proxy, TLS-inspecting
# firewall, or no network at all. A dependency fetched unconditionally turns
# that into a failed setup with a CMake stack trace nobody can act on, so every
# URL dependency here resolves in three steps:
#
# 1. a pre-extracted source tree — FETCHCONTENT_SOURCE_DIR_<NAME>, or the
# dependency's documented env override — and nothing is downloaded;
# 2. a vendored archive in third_party/, verified against the same SHA256 the
# upstream pin carries;
# 3. the upstream URL.
#
# third_party/deps.manifest is THE pin record. Both this file and
# tools/ci/vendor_deps.sh read it, so a vendored archive cannot drift from the
# URL/hash the build would otherwise have downloaded.
#
# -DPSX_DEPS_OFFLINE=ON (or PSX_DEPS_OFFLINE=1 in the environment) turns step 3
# into a hard error that names the missing archive, instead of a download that
# stalls behind a firewall and then fails deep inside a FetchContent subbuild
# where the real cause is three stack frames up.
# ---------------------------------------------------------------------------
if(NOT DEFINED PSX_THIRD_PARTY_DIR)
get_filename_component(_psx_third_party_default
"${CMAKE_CURRENT_LIST_DIR}/../third_party" ABSOLUTE)
set(PSX_THIRD_PARTY_DIR "${_psx_third_party_default}" CACHE PATH
"Directory holding vendored dependency archives (third_party/)")
unset(_psx_third_party_default)
endif()
set(_psx_deps_offline_default OFF)
if(NOT "$ENV{PSX_DEPS_OFFLINE}" STREQUAL "" AND
NOT "$ENV{PSX_DEPS_OFFLINE}" STREQUAL "0")
set(_psx_deps_offline_default ON)
endif()
set(PSX_DEPS_OFFLINE "${_psx_deps_offline_default}" CACHE BOOL
"Never download a dependency: require a vendored archive or a pre-extracted source tree")
unset(_psx_deps_offline_default)
# Look up one row of third_party/deps.manifest.
function(_psx_dependency_pin name out_file out_sha out_url)
set(_manifest "${PSX_THIRD_PARTY_DIR}/deps.manifest")
if(NOT EXISTS "${_manifest}")
message(FATAL_ERROR
"psxrecomp: dependency manifest not found: ${_manifest}\n"
" Point -DPSX_THIRD_PARTY_DIR=… at the framework's third_party/ "
"directory.")
endif()
file(STRINGS "${_manifest}" _lines)
foreach(_line IN LISTS _lines)
string(STRIP "${_line}" _line)
if(_line STREQUAL "" OR _line MATCHES "^#")
continue()
endif()
string(REGEX MATCHALL "[^ \t]+" _fields "${_line}")
list(LENGTH _fields _field_count)
if(NOT _field_count EQUAL 4)
message(FATAL_ERROR
"psxrecomp: malformed row in ${_manifest} "
"(want 'name file sha256 url'): ${_line}")
endif()
list(GET _fields 0 _row_name)
if(_row_name STREQUAL "${name}")
list(GET _fields 1 _row_file)
list(GET _fields 2 _row_sha)
list(GET _fields 3 _row_url)
set(${out_file} "${_row_file}" PARENT_SCOPE)
set(${out_sha} "${_row_sha}" PARENT_SCOPE)
set(${out_url} "${_row_url}" PARENT_SCOPE)
return()
endif()
endforeach()
message(FATAL_ERROR "psxrecomp: no '${name}' row in ${_manifest}")
endfunction()
# psxrecomp_dependency_archive(<name> OUT_URL <var> OUT_HASH <var>
# [SOURCE_DIR <dir>])
#
# Sets OUT_URL to the vendored archive when third_party/ holds it, else to the
# upstream URL (fatal under PSX_DEPS_OFFLINE). OUT_HASH is the URL_HASH string
# for FetchContent_Declare and is the same either way — a vendored archive is
# verified exactly as strictly as a downloaded one.
#
# Pass the result of psxrecomp_dependency_source_dir() as SOURCE_DIR. When it is
# non-empty FetchContent uses that tree and ignores the URL, so the declaration
# still needs to be well-formed but reports nothing about a download that will
# not happen.
function(psxrecomp_dependency_archive name)
cmake_parse_arguments(_psx_dep "" "OUT_URL;OUT_HASH;SOURCE_DIR" "" ${ARGN})
if(NOT _psx_dep_OUT_URL OR NOT _psx_dep_OUT_HASH)
message(FATAL_ERROR
"psxrecomp_dependency_archive(${name}): OUT_URL and OUT_HASH are required")
endif()
set(_psx_dep_SILENT OFF)
if(NOT "${_psx_dep_SOURCE_DIR}" STREQUAL "")
set(_psx_dep_SILENT ON)
endif()
_psx_dependency_pin("${name}" _file _sha _url)
set(${_psx_dep_OUT_HASH} "SHA256=${_sha}" PARENT_SCOPE)
set(_vendored "${PSX_THIRD_PARTY_DIR}/${_file}")
if(EXISTS "${_vendored}")
if(NOT _psx_dep_SILENT)
message(STATUS
"psxrecomp: ${name} from vendored archive third_party/${_file}")
endif()
set(${_psx_dep_OUT_URL} "${_vendored}" PARENT_SCOPE)
return()
endif()
string(TOUPPER "${name}" _uc_name)
if(PSX_DEPS_OFFLINE)
message(FATAL_ERROR
"psxrecomp: PSX_DEPS_OFFLINE is ON but ${name} is not vendored.\n"
" expected archive: ${_vendored}\n"
" stage it with: tools/ci/vendor_deps.sh ${name}\n"
" or point the build at an already-extracted tree with "
"-DFETCHCONTENT_SOURCE_DIR_${_uc_name}=<dir>")
endif()
if(NOT _psx_dep_SILENT)
message(STATUS
"psxrecomp: ${name} not vendored — will download ${_url} "
"(tools/ci/vendor_deps.sh ${name} makes this build offline-capable)")
endif()
set(${_psx_dep_OUT_URL} "${_url}" PARENT_SCOPE)
endfunction()
# psxrecomp_dependency_source_dir(<name> OUT <var> [ENV <var>] [MARKER <file>])
#
# Honours an already-extracted source tree, from -DFETCHCONTENT_SOURCE_DIR_<NAME>
# or from the named environment variable (which is promoted into the cache var so
# FetchContent picks it up). OUT is set to the directory, or "" when none applies.
function(psxrecomp_dependency_source_dir name)
cmake_parse_arguments(_psx_src "" "OUT;ENV;MARKER" "" ${ARGN})
if(NOT _psx_src_OUT)
message(FATAL_ERROR
"psxrecomp_dependency_source_dir(${name}): OUT is required")
endif()
if(NOT _psx_src_MARKER)
set(_psx_src_MARKER "CMakeLists.txt")
endif()
string(TOUPPER "${name}" _uc_name)
set(_dir "")
if(NOT "${FETCHCONTENT_SOURCE_DIR_${_uc_name}}" STREQUAL "" AND
EXISTS "${FETCHCONTENT_SOURCE_DIR_${_uc_name}}/${_psx_src_MARKER}")
set(_dir "${FETCHCONTENT_SOURCE_DIR_${_uc_name}}")
elseif(_psx_src_ENV AND NOT "$ENV{${_psx_src_ENV}}" STREQUAL "" AND
EXISTS "$ENV{${_psx_src_ENV}}/${_psx_src_MARKER}")
set(_dir "$ENV{${_psx_src_ENV}}")
set(FETCHCONTENT_SOURCE_DIR_${_uc_name} "${_dir}" CACHE PATH
"Pre-fetched ${name} source (skip download)" FORCE)
endif()
if(_dir)
message(STATUS "psxrecomp: using pre-fetched ${name} source ${_dir}")
endif()
set(${_psx_src_OUT} "${_dir}" PARENT_SCOPE)
endfunction()
+23
View File
@@ -153,6 +153,8 @@ On Windows with MSVC or plain MinGW makefiles, swap `-G Ninja` for your generato
| `PSX_DEBUG_TOOLS` | ON for Debug/RelWithDebInfo, OFF for Release | TCP debug server + heartbeat + per-block recording |
| `PSX_SDL_BACKEND` | `SDL3` | Host backend. Set `SDL2` explicitly for compatibility or A/B testing. |
| `PSX_SDL3_FETCH` | ON | Fetch the pinned SDL3 release when a compatible system SDL3 package is unavailable. Set OFF for offline/system-only builds. |
| `PSX_DEPS_OFFLINE` | OFF (env `PSX_DEPS_OFFLINE=1` flips it) | Never download a dependency. A dependency that is not vendored in `third_party/` and has no pre-extracted source tree becomes a hard error naming the missing archive, instead of a fetch that stalls behind a proxy. |
| `PSX_THIRD_PARTY_DIR` | `<framework>/third_party` | Where vendored dependency archives are looked up (`deps.manifest` lives there). |
| `PSX_STATIC_RUNTIME` | ON for MinGW Release | Self-contained exe (statically links SDL + libgcc/libstdc++) |
| `PSX_RECOMP_UI` | ON | Wire a downstream game's pinned recomp-ui launcher; set OFF for headless/generated builds |
| `PSX_ENABLE_VULKAN` | **ON** | Build the experimental Vulkan renderer when the SDK tools are present (skipped if not). Pass `OFF` to exclude it outright. |
@@ -232,6 +234,27 @@ these files without it). If you hit this on a framework source file, please open
an issue with your `gcc -v` / `as --version` — the build should apply the flag
for you.
**`Build step for psx_libchdr failed: 1`, or any `FetchContent` populate
failure.** The build could not download a pinned dependency archive — no
network, a corporate proxy, or a TLS-inspecting firewall between you and
github.com. libchdr is the first dependency the runtime resolves, so it is
usually the one that reports the problem.
The pinned libchdr archive is vendored at `third_party/`, so an up-to-date
framework checkout does not download it at all. If you are on an older
checkout, or you need SDL3/zlib offline too, stage them once from a machine
with access and copy `third_party/` across:
```sh
psxrecomp/tools/ci/vendor_deps.sh # stage every pinned archive
psxrecomp/tools/ci/vendor_deps.sh --check # verify; never downloads
```
Then configure with `-DPSX_DEPS_OFFLINE=ON` so any remaining download attempt
fails immediately with the name of the archive to stage, rather than deep
inside a FetchContent subbuild. An already-extracted tree works too:
`-DFETCHCONTENT_SOURCE_DIR_PSX_LIBCHDR=<dir>`.
**`SDL3 3.4+ was not found`.** The default build normally downloads the pinned
release. Check network access, install a system SDL3 package and provide
`SDL3_DIR`, or re-enable `-DPSX_SDL3_FETCH=ON`.
+19 -2
View File
@@ -1,6 +1,7 @@
include_guard(GLOBAL)
include(FetchContent)
include("${CMAKE_CURRENT_LIST_DIR}/../cmake/psx_dependency_archive.cmake")
# libchdr is the small, BSD-licensed decompressor used by MAME-compatible CHD
# images. Pin the exact source archive (and its digest) so generated games do
@@ -21,10 +22,26 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
endif()
# This include is unconditional — there is no find_package path and no
# toolchain pack that ships libchdr — so a player building a released game with
# no route to github.com used to fail here, in a FetchContent subbuild, with no
# usable diagnosis. The pinned archive is vendored at third_party/ for exactly
# that reason; the upstream URL stays as the fallback for a stripped checkout.
psxrecomp_dependency_source_dir(psx_libchdr
ENV PSX_LIBCHDR_SOURCE_DIR
OUT _psx_libchdr_src)
psxrecomp_dependency_archive(psx_libchdr
SOURCE_DIR "${_psx_libchdr_src}"
OUT_URL _psx_libchdr_url OUT_HASH _psx_libchdr_hash)
FetchContent_Declare(psx_libchdr
URL
"https://github.com/rtissera/libchdr/archive/6cde5348eb118da3baf94f75a69577a005a484fd.tar.gz"
"${_psx_libchdr_url}"
URL_HASH
"SHA256=a222b1f1c842f988c2aad51e5f56ba94a423ed87ccab71f1abdb757caa7444f5"
"${_psx_libchdr_hash}"
${_psx_libchdr_timestamp_args})
FetchContent_MakeAvailable(psx_libchdr)
unset(_psx_libchdr_src)
unset(_psx_libchdr_url)
unset(_psx_libchdr_hash)
+21 -20
View File
@@ -8,6 +8,7 @@ if(NOT DEFINED PSXRECOMP_ROOT)
get_filename_component(PSXRECOMP_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
endif()
include("${PSXRECOMP_ROOT}/cmake/psx_dependency_archive.cmake")
include("${PSXRECOMP_ROOT}/runtime/chd_dependency.cmake")
# Default to an optimized build. The recompiled game is a huge (~270 MB) block of
@@ -166,30 +167,24 @@ if(_psx_sdl_backend STREQUAL "SDL3")
# CI (tools/ci/prefetch_sdl3.sh) pre-extracts with curl --http1.1 to
# avoid intermittent GitHub HTTP/2 REFUSED_STREAM failures from
# CMake's file(DOWNLOAD). Prefer that tree when present.
set(_psx_sdl3_src "")
if(DEFINED FETCHCONTENT_SOURCE_DIR_SDL3 AND
NOT FETCHCONTENT_SOURCE_DIR_SDL3 STREQUAL "" AND
EXISTS "${FETCHCONTENT_SOURCE_DIR_SDL3}/CMakeLists.txt")
set(_psx_sdl3_src "${FETCHCONTENT_SOURCE_DIR_SDL3}")
elseif(DEFINED ENV{PSX_SDL3_SOURCE_DIR} AND
NOT "$ENV{PSX_SDL3_SOURCE_DIR}" STREQUAL "" AND
EXISTS "$ENV{PSX_SDL3_SOURCE_DIR}/CMakeLists.txt")
set(_psx_sdl3_src "$ENV{PSX_SDL3_SOURCE_DIR}")
set(FETCHCONTENT_SOURCE_DIR_SDL3 "${_psx_sdl3_src}" CACHE PATH
"Pre-fetched SDL3 source (skip download)" FORCE)
endif()
if(_psx_sdl3_src)
message(STATUS
"psxrecomp: using pre-fetched SDL3 source ${_psx_sdl3_src}")
endif()
psxrecomp_dependency_source_dir(SDL3
ENV PSX_SDL3_SOURCE_DIR
OUT _psx_sdl3_src)
# Pin (and any vendored archive) come from third_party/deps.manifest, so
# an air-gapped tree staged by tools/ci/vendor_deps.sh needs no download.
psxrecomp_dependency_archive(SDL3
SOURCE_DIR "${_psx_sdl3_src}"
OUT_URL _psx_sdl3_url OUT_HASH _psx_sdl3_hash)
FetchContent_Declare(SDL3
URL
"https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz"
"${_psx_sdl3_url}"
URL_HASH
"SHA256=12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785"
"${_psx_sdl3_hash}"
${_psx_sdl3_timestamp_args})
FetchContent_MakeAvailable(SDL3)
unset(_psx_sdl3_src)
unset(_psx_sdl3_url)
unset(_psx_sdl3_hash)
endif()
if(NOT TARGET SDL3::SDL3)
message(FATAL_ERROR
@@ -729,11 +724,17 @@ function(psxrecomp_ensure_zlib)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
list(APPEND _psx_zlib_timestamp_args DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
endif()
psxrecomp_dependency_source_dir(psx_zlib
ENV PSX_ZLIB_SOURCE_DIR
OUT _psx_zlib_src)
psxrecomp_dependency_archive(psx_zlib
SOURCE_DIR "${_psx_zlib_src}"
OUT_URL _psx_zlib_url OUT_HASH _psx_zlib_hash)
FetchContent_Declare(psx_zlib
URL
"https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.gz"
"${_psx_zlib_url}"
URL_HASH
"SHA256=9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23"
"${_psx_zlib_hash}"
${_psx_zlib_timestamp_args})
FetchContent_MakeAvailable(psx_zlib)
# madler/zlib builds zlibstatic even when a shared zlib target exists.
+9
View File
@@ -0,0 +1,9 @@
# Vendored archives are opt-in. Only libchdr — the one dependency the build
# cannot satisfy locally — is committed; tools/ci/vendor_deps.sh stages the
# rest here on demand for air-gapped builds, and those must not be committed
# (SDL3 alone is ~15 MB).
*.tar.gz
*.tar.xz
*.tar.bz2
*.zip
!libchdr-*.tar.gz
+42
View File
@@ -0,0 +1,42 @@
# third_party/ — vendored dependency archives
Source archives the build would otherwise download, staged here so a checkout
can configure with no network at all.
`deps.manifest` is the single pin record — name, archive file, SHA256, upstream
URL. Both `cmake/psx_dependency_archive.cmake` and `tools/ci/vendor_deps.sh`
read it, so a vendored archive can never drift from the pin the build would
have fetched. A vendored archive is verified against the same `URL_HASH` as a
downloaded one; nothing here is trusted because it is local.
## What is committed, and why only that
Only **libchdr** (`libchdr-<sha>.tar.gz`, ~520 KB, BSD-3-Clause — see
`../THIRD_PARTY_ATTRIBUTION.md`).
`runtime/runtime.cmake` includes `chd_dependency.cmake` unconditionally, and
libchdr has no `find_package` path and ships in no toolchain pack — so it is
both the *first* network access a build makes and the only one with no local
fallback. A player building a released game behind a firewall used to fail
there, inside a FetchContent subbuild, before reaching any other dependency.
SDL3 (~15 MB) and zlib resolve from a system package or a toolchain pack first
and are **not** committed; `.gitignore` keeps them out. Stage them on demand:
```sh
tools/ci/vendor_deps.sh # every dependency in the manifest
tools/ci/vendor_deps.sh SDL3 # just one
tools/ci/vendor_deps.sh --check # verify what is staged; never downloads
```
Then configure with `-DPSX_DEPS_OFFLINE=ON` to turn any remaining download
attempt into a hard error that names the missing archive, instead of a fetch
that stalls behind a proxy and fails three CMake frames deep.
## Adding a dependency
Add the row to `deps.manifest`, run `tools/ci/vendor_deps.sh <name>` to stage
and verify the archive, and resolve it in CMake through
`psxrecomp_dependency_archive()` / `psxrecomp_dependency_source_dir()` rather
than a literal `URL` — a literal URL is a build that cannot go offline. Commit
the archive only if the dependency has no local fallback and is small.
+23
View File
@@ -0,0 +1,23 @@
# psxrecomp vendored-dependency pins.
#
# THE single record of every source archive the build may fetch. Both
# cmake/psx_dependency_archive.cmake and tools/ci/vendor_deps.sh read this
# file, so a vendored archive under third_party/ can never drift from the
# URL/hash the build would otherwise download.
#
# Columns, whitespace-separated:
# name FetchContent name used in the CMake files
# file archive name under third_party/ (vendored form)
# sha256 digest of that archive; also the URL_HASH of the upstream pin
# url upstream download location
#
# Only psx_libchdr is committed: it is the one dependency with no local
# fallback (no find_package path, no toolchain-pack copy), so a build with no
# network dies at it. SDL3 and zlib resolve from a system package or a
# cmake-clang-v1 toolchain pack first; run tools/ci/vendor_deps.sh to stage
# them here as well for a fully air-gapped tree.
#
# name file sha256 url
psx_libchdr libchdr-6cde5348eb118da3baf94f75a69577a005a484fd.tar.gz a222b1f1c842f988c2aad51e5f56ba94a423ed87ccab71f1abdb757caa7444f5 https://github.com/rtissera/libchdr/archive/6cde5348eb118da3baf94f75a69577a005a484fd.tar.gz
SDL3 SDL3-3.4.10.tar.gz 12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785 https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz
psx_zlib zlib-1.3.1.tar.gz 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23 https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.gz
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env bash
# Stage the pinned dependency archives into third_party/ so a build needs no
# network. Reads third_party/deps.manifest — the same pin record
# cmake/psx_dependency_archive.cmake reads — so what lands here is byte-identical
# to what the build would otherwise have downloaded.
#
# Usage:
# tools/ci/vendor_deps.sh # stage every dependency
# tools/ci/vendor_deps.sh SDL3 psx_zlib # stage only these
# tools/ci/vendor_deps.sh --check # verify what is staged; never download
# tools/ci/vendor_deps.sh --force # re-download even if present
#
# After a full run, configure with -DPSX_DEPS_OFFLINE=ON to make any remaining
# download attempt a hard error rather than a silent trip to github.com.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
THIRD_PARTY="${ROOT}/third_party"
MANIFEST="${THIRD_PARTY}/deps.manifest"
CHECK_ONLY=0
FORCE=0
WANTED=()
while [[ $# -gt 0 ]]; do
case "$1" in
--check) CHECK_ONLY=1; shift ;;
--force) FORCE=1; shift ;;
-h|--help)
sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
-*)
echo "error: unknown option: $1" >&2
exit 2
;;
*) WANTED+=("$1"); shift ;;
esac
done
if [[ ! -f "${MANIFEST}" ]]; then
echo "error: missing manifest: ${MANIFEST}" >&2
exit 1
fi
sha256_of() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | awk '{print $1}'
else
echo "error: need sha256sum or shasum to verify archives" >&2
exit 1
fi
}
wanted() {
[[ ${#WANTED[@]} -eq 0 ]] && return 0
local n
for n in "${WANTED[@]}"; do
[[ "$n" == "$1" ]] && return 0
done
return 1
}
download() {
# Prefer HTTP/1.1: GitHub release assets intermittently REFUSED_STREAM under
# HTTP/2, which is the same failure prefetch_sdl3.sh works around.
local url="$1" dest="$2"
if command -v curl >/dev/null 2>&1; then
curl -fsSL --http1.1 --retry 5 --retry-all-errors --retry-delay 2 \
-o "${dest}" "${url}"
elif command -v wget >/dev/null 2>&1; then
wget -q -O "${dest}" "${url}"
else
echo "error: need curl or wget to download ${url}" >&2
exit 1
fi
}
mkdir -p "${THIRD_PARTY}"
seen=0
fail=0
matched=()
while read -r name file sha url _rest; do
case "${name}" in ""|\#*) continue ;; esac
if [[ -z "${file}" || -z "${sha}" || -z "${url}" ]]; then
echo "error: malformed manifest row: ${name} ${file} ${sha} ${url}" >&2
fail=1
continue
fi
wanted "${name}" || continue
matched+=("${name}")
seen=$((seen + 1))
target="${THIRD_PARTY}/${file}"
if [[ -f "${target}" && "${FORCE}" -eq 0 ]]; then
have="$(sha256_of "${target}")"
if [[ "${have}" == "${sha}" ]]; then
echo "ok: ${name} — third_party/${file}"
continue
fi
echo "error: ${name} — third_party/${file} digest mismatch" >&2
echo " manifest: ${sha}" >&2
echo " on disk: ${have}" >&2
if [[ "${CHECK_ONLY}" -eq 1 ]]; then
fail=1
continue
fi
echo " re-downloading" >&2
elif [[ "${CHECK_ONLY}" -eq 1 ]]; then
echo "missing: ${name} — third_party/${file}" >&2
fail=1
continue
fi
echo "fetching: ${name} <- ${url}"
tmp="$(mktemp "${THIRD_PARTY}/.${file}.XXXXXX")"
# shellcheck disable=SC2064
trap "rm -f '${tmp}'" EXIT
download "${url}" "${tmp}"
have="$(sha256_of "${tmp}")"
if [[ "${have}" != "${sha}" ]]; then
echo "error: ${name} digest mismatch after download" >&2
echo " want: ${sha}" >&2
echo " got: ${have}" >&2
rm -f "${tmp}"
trap - EXIT
fail=1
continue
fi
mv -f "${tmp}" "${target}"
chmod 0644 "${target}"
trap - EXIT
echo "ok: ${name} — third_party/${file}"
done <"${MANIFEST}"
if [[ ${#WANTED[@]} -gt 0 ]]; then
for n in "${WANTED[@]}"; do
found=0
for m in "${matched[@]:-}"; do
[[ "$m" == "$n" ]] && found=1
done
if [[ "${found}" -eq 0 ]]; then
echo "error: no '${n}' row in ${MANIFEST}" >&2
fail=1
fi
done
fi
if [[ "${seen}" -eq 0 ]]; then
echo "error: nothing to do — no manifest rows selected" >&2
exit 1
fi
if [[ "${fail}" -ne 0 ]]; then
exit 1
fi
if [[ "${CHECK_ONLY}" -eq 1 ]]; then
echo "all requested dependencies are vendored and verified."
else
echo "vendored ${seen} dependenc$([[ ${seen} -eq 1 ]] && echo y || echo ies) into third_party/."
echo "configure with -DPSX_DEPS_OFFLINE=ON to forbid any further download."
fi