diff --git a/.github/workflows/ci/openssl-libssl11-shim-unix.sh b/.github/workflows/ci/openssl-libssl11-shim-unix.sh index a01bc73..16043d8 100644 --- a/.github/workflows/ci/openssl-libssl11-shim-unix.sh +++ b/.github/workflows/ci/openssl-libssl11-shim-unix.sh @@ -1,16 +1,30 @@ #!/usr/bin/env bash # TODO(FPC 3.2.4): remove this shim. FPC 3.2.2 hardcodes libssl.so.1.1, so -# symlink the OpenSSL 3.x ELF libraries to the 1.1 sonames on Linux/BSD. +# symlink the real OpenSSL 3.x libraries to the 1.1 sonames on Linux/BSD. +# Linux installs libssl.so.3; FreeBSD/DragonFly dports install +# libssl.so. (currently libssl.so.12), so the soname can't be assumed. set -euo pipefail ARCH_DIR="${1:-}" + +# True if $1 holds a real OpenSSL libssl (any soname except the .1.1 we create). +dir_has_libssl() { + local d="$1" f + [ -n "$d" ] || return 1 + for f in "$d"/libssl.so.*; do + case "$f" in */libssl.so.1.1) continue ;; esac + [ -e "$f" ] && return 0 + done + return 1 +} + if [ -z "$ARCH_DIR" ] && command -v gcc >/dev/null 2>&1; then multiarch="$(gcc -print-multiarch 2>/dev/null || true)" - if [ -n "$multiarch" ] && [ -f "/usr/lib/$multiarch/libssl.so.3" ]; then + if [ -n "$multiarch" ] && dir_has_libssl "/usr/lib/$multiarch"; then ARCH_DIR="/usr/lib/$multiarch" fi fi -if [ -z "$ARCH_DIR" ] || [ ! -f "$ARCH_DIR/libssl.so.3" ]; then +if [ -z "$ARCH_DIR" ] || ! dir_has_libssl "$ARCH_DIR"; then for candidate in \ /usr/lib/powerpc64-linux-gnu \ /usr/lib/ppc64-linux-gnu \ @@ -18,18 +32,35 @@ if [ -z "$ARCH_DIR" ] || [ ! -f "$ARCH_DIR/libssl.so.3" ]; then /usr/lib/aarch64-linux-gnu \ /usr/lib/x86_64-linux-gnu \ /usr/lib; do - if [ -f "$candidate/libssl.so.3" ]; then + if dir_has_libssl "$candidate"; then ARCH_DIR="$candidate" break fi done fi -if [ ! -f "$ARCH_DIR/libssl.so.3" ]; then - echo "openssl-libssl11-shim-unix: libssl.so.3 not found under $ARCH_DIR" >&2 +if ! dir_has_libssl "$ARCH_DIR"; then + echo "openssl-libssl11-shim-unix: no OpenSSL 3.x libssl.so.* found under ${ARCH_DIR:-}" >&2 exit 1 fi +# Resolve the real source lib for a base name, preferring the Linux .so.3 soname +# and otherwise taking the dports-versioned file (e.g. libcrypto.so.12). +find_src() { + local base="$1" f + if [ -e "$ARCH_DIR/$base.so.3" ]; then + printf '%s\n' "$ARCH_DIR/$base.so.3"; return 0 + fi + for f in "$ARCH_DIR/$base.so."*; do + case "$f" in */"$base.so.1.1") continue ;; esac + [ -e "$f" ] && { printf '%s\n' "$f"; return 0; } + done + return 1 +} + +ssl_src="$(find_src libssl)" +crypto_src="$(find_src libcrypto)" + ln_cmd=(ln -sf) if [ "${OPENSSL_USE_SUDO:-1}" = "1" ] && [ "$(id -u)" -ne 0 ]; then if command -v sudo >/dev/null 2>&1; then @@ -37,5 +68,5 @@ if [ "${OPENSSL_USE_SUDO:-1}" = "1" ] && [ "$(id -u)" -ne 0 ]; then fi fi -"${ln_cmd[@]}" "$ARCH_DIR/libssl.so.3" "$ARCH_DIR/libssl.so.1.1" -"${ln_cmd[@]}" "$ARCH_DIR/libcrypto.so.3" "$ARCH_DIR/libcrypto.so.1.1" +"${ln_cmd[@]}" "$ssl_src" "$ARCH_DIR/libssl.so.1.1" +"${ln_cmd[@]}" "$crypto_src" "$ARCH_DIR/libcrypto.so.1.1" diff --git a/.github/workflows/ci/openssl-libssl11-shim-windows.sh b/.github/workflows/ci/openssl-libssl11-shim-windows.sh new file mode 100644 index 0000000..a8a454e --- /dev/null +++ b/.github/workflows/ci/openssl-libssl11-shim-windows.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# TODO(FPC 3.2.4): remove this shim. FPC 3.2.2's openssl unit hardcodes the +# OpenSSL 1.1 Windows DLL names, but modern Windows CI runners ship only +# OpenSSL 3.x. Copy the runner's OpenSSL 3 DLLs (already on PATH) to the 1.1 +# names FPC expects so the default InitSSLInterface finds them. FPC 3.2.4+ +# knows the OpenSSL 3 names directly. +# +# Mirrors openssl-libssl11-shim-unix.sh / -macos.sh, but Windows has no cheap +# symlink, so we copy. We write next to the source DLL (already on PATH) so the +# make binary loads it without us having to mutate the caller's PATH (this runs +# in a subshell and could not export PATH back anyway). +set -euo pipefail + +# Bitness matters: FPC 3.2.2 (and OpenSSL 3) use different DLL names per arch, +# matching make.pas's old {$IFDEF WIN64} split. 64-bit looks for +# libssl-1_1-x64.dll (OpenSSL 3 ships libssl-3-x64.dll); 32-bit looks for +# libssl-1_1.dll (OpenSSL 3 ships libssl-3.dll). Derive from the FPC target the +# make binary is compiled for; default to 64-bit (the only Windows CI target). +case "${FPC_TARGET:-}" in + i386-win32|*-win32|*win32*) SRC_SUFFIX="-3"; DST_SUFFIX="-1_1" ;; + *) SRC_SUFFIX="-3-x64"; DST_SUFFIX="-1_1-x64" ;; +esac + +# Find $1$SRC_SUFFIX.dll on PATH and copy it to the $1$DST_SUFFIX.dll FPC wants. +copy_alias() { + local base="$1" src="" dir + local IFS=':' + for dir in $PATH; do + if [ -f "$dir/$base$SRC_SUFFIX.dll" ]; then + src="$dir/$base$SRC_SUFFIX.dll" + break + fi + done + if [ -z "$src" ]; then + echo "openssl-libssl11-shim-windows: $base$SRC_SUFFIX.dll not found on PATH" >&2 + return 1 + fi + cp -f "$src" "$(dirname "$src")/$base$DST_SUFFIX.dll" + echo "openssl-libssl11-shim-windows: $src -> $(dirname "$src")/$base$DST_SUFFIX.dll" +} + +copy_alias libssl +copy_alias libcrypto diff --git a/.github/workflows/ci/resolve-targets.sh b/.github/workflows/ci/resolve-targets.sh index 4be5ae5..5aed4a9 100644 --- a/.github/workflows/ci/resolve-targets.sh +++ b/.github/workflows/ci/resolve-targets.sh @@ -53,6 +53,13 @@ NATIVE_MATRIX="$(jq -c --arg ids "$TARGETS" \ '[.targets[] | select(.kind == "native") | select(.id as $i | ($ids | split(",") | index($i)))]' \ "$REGISTRY")" +# Never emit an empty matrix: GitHub renders the literal `${{ matrix.name }}` +# for a job skipped via an empty matrix. A single placeholder keeps the matrix +# valid; the native job no-ops it via `matrix.fpc_target != 'none'`. +if [ "$NATIVE_MATRIX" = "[]" ]; then + NATIVE_MATRIX='[{"name":"Native: (no targets selected)","runner":"ubuntu-latest","fpc_target":"none"}]' +fi + { echo "enabled_targets=${TARGETS}" echo "native_matrix=${NATIVE_MATRIX}" diff --git a/.github/workflows/ci/shared/common.sh b/.github/workflows/ci/shared/common.sh index 4dccd76..02c9eb3 100644 --- a/.github/workflows/ci/shared/common.sh +++ b/.github/workflows/ci/shared/common.sh @@ -29,6 +29,23 @@ ci_default_make_cmd() { esac } +# Download $1 (URL) to $2 (output path) with whatever fetcher exists. +# curl covers Linux/macOS/Windows; fetch is the FreeBSD/DragonFly base tool +# (survives pkg upgrades that drop the curl package); wget is the middle option. +ci_download() { + local url="$1" out="$2" + if command -v curl >/dev/null 2>&1; then + curl -fL --retry 5 --retry-delay 5 --retry-all-errors -o "$out" "$url" + elif command -v wget >/dev/null 2>&1; then + wget --tries=5 --retry-connrefused -O "$out" "$url" + elif command -v fetch >/dev/null 2>&1; then + fetch -a -o "$out" "$url" + else + echo "ci_download: no curl/wget/fetch available" >&2 + return 1 + fi +} + ci_install_toolchain() { : "${FPC_TARGET:?FPC_TARGET is required}" bash "$WORKFLOWS_DIR/install-fpc-lazarus.sh" @@ -135,7 +152,18 @@ ci_preflight() { } ci_run_make() { - instantfpc "$WORKFLOWS_DIR/make.pas" + if command -v instantfpc >/dev/null 2>&1; then + instantfpc "$WORKFLOWS_DIR/make.pas" + return + fi + # Some FPC tarballs (notably the reduced x86_64-dragonfly cross build) ship + # fpc but omit the instantfpc helper. instantfpc just compiles+runs a .pas + # program, so do that directly with fpc instead. -FE/-FU keep build artifacts + # in a temp dir; fpc reads the same fpc.cfg, so units resolve identically. + local build_dir + build_dir="$(mktemp -d 2>/dev/null || mktemp -d -t ci-make)" + fpc -FE"$build_dir" -FU"$build_dir" -omake "$WORKFLOWS_DIR/make.pas" + "$build_dir/make" } ci_build_standard() { @@ -153,6 +181,10 @@ ci_build_prebuilt() { } ci_openssl_hack() { + if ci_is_windows; then + bash "$CI_ROOT/openssl-libssl11-shim-windows.sh" + return + fi case "$(uname -s)" in Linux) bash "$CI_ROOT/openssl-libssl11-shim-unix.sh" ;; Darwin) bash "$CI_ROOT/openssl-libssl11-shim-macos.sh" ;; diff --git a/.github/workflows/ci/targets.json b/.github/workflows/ci/targets.json index 76da320..b5e1457 100644 --- a/.github/workflows/ci/targets.json +++ b/.github/workflows/ci/targets.json @@ -1,16 +1,16 @@ { "comment": "Single source of truth for CI targets. resolve-targets.sh reads this to compute the default set and the native job's dynamic matrix. kind: native (matrixed runner), qemu (QEMU job), vm (vmactions job). default=true targets run automatically on push/PR; default=false targets are opt-in and must be named explicitly via workflow_dispatch enabled_targets (set default=false to stop a slow target from running automatically).", "targets": [ - { "id": "linux-x64", "name": "Linux x86_64", "kind": "native", "default": true, "runner": "ubuntu-latest", "fpc_target": "x86_64-linux" }, - { "id": "linux-arm64", "name": "Linux AArch64", "kind": "native", "default": true, "runner": "ubuntu-24.04-arm", "fpc_target": "aarch64-linux" }, - { "id": "windows-x64", "name": "Windows x86_64", "kind": "native", "default": true, "runner": "windows-latest", "fpc_target": "x86_64-win64" }, - { "id": "macos-arm64", "name": "macOS AArch64 (Apple Silicon)", "kind": "native", "default": true, "runner": "macos-latest", "fpc_target": "aarch64-darwin" }, - { "id": "macos-x64", "name": "macOS x86_64 (Intel)", "kind": "native", "default": true, "runner": "macos-15-intel", "fpc_target": "x86_64-darwin" }, - { "id": "linux-arm32", "name": "Linux ARMv7 (QEMU)", "kind": "qemu", "default": true }, - { "id": "linux-powerpc64-be", "name": "Linux PowerPC64 BE (QEMU)", "kind": "qemu", "default": true }, - { "id": "freebsd", "name": "FreeBSD x86_64", "kind": "vm", "default": true }, - { "id": "solaris", "name": "Solaris x86_64", "kind": "vm", "default": true }, - { "id": "netbsd", "name": "NetBSD x86_64", "kind": "vm", "default": false }, - { "id": "dragonflybsd", "name": "DragonFlyBSD x86_64", "kind": "vm", "default": false } + { "id": "linux-x64", "name": "Native: Linux x86_64", "kind": "native", "default": true, "runner": "ubuntu-latest", "fpc_target": "x86_64-linux" }, + { "id": "linux-arm64", "name": "Native: Linux AArch64", "kind": "native", "default": true, "runner": "ubuntu-24.04-arm", "fpc_target": "aarch64-linux" }, + { "id": "windows-x64", "name": "Native: Windows x86_64", "kind": "native", "default": true, "runner": "windows-latest", "fpc_target": "x86_64-win64" }, + { "id": "macos-arm64", "name": "Native: macOS AArch64 (Apple Silicon)", "kind": "native", "default": true, "runner": "macos-latest", "fpc_target": "aarch64-darwin" }, + { "id": "macos-x64", "name": "Native: macOS x86_64 (Intel)", "kind": "native", "default": true, "runner": "macos-15-intel", "fpc_target": "x86_64-darwin" }, + { "id": "linux-arm32", "name": "QEMU: Linux ARMv7", "kind": "qemu", "default": true }, + { "id": "linux-powerpc64-be", "name": "QEMU: Linux PowerPC64 BE", "kind": "qemu", "default": true }, + { "id": "freebsd", "name": "VM: FreeBSD x86_64", "kind": "vm", "default": true }, + { "id": "solaris", "name": "VM: Solaris x86_64", "kind": "vm", "default": true }, + { "id": "netbsd", "name": "VM: NetBSD x86_64", "kind": "vm", "default": true }, + { "id": "dragonflybsd", "name": "VM: DragonFlyBSD x86_64", "kind": "vm", "default": true } ] } diff --git a/.github/workflows/ci/vm-dragonfly-prepare.sh b/.github/workflows/ci/vm-dragonfly-prepare.sh index e9ea0f8..d20c799 100644 --- a/.github/workflows/ci/vm-dragonfly-prepare.sh +++ b/.github/workflows/ci/vm-dragonfly-prepare.sh @@ -5,18 +5,42 @@ set -eu # common.sh (which targets bash, e.g. BASH_SOURCE / set -o pipefail). CI_ROOT="$(cd "$(dirname "$0")" && pwd)" -pkg install -y bash curl git gmake openssl +# Refresh the package catalogue (and bootstrap a newer pkg if the cached image +# ships an old one). +# +# We deliberately do NOT run a blanket `pkg upgrade`. The cached VM image is +# stale enough that pkg 2.x's SAT solver can't reconcile the full set of upgrade +# candidates; instead of failing, it "resolves" the conflict by DROPPING +# packages we rely on (curl, git-lite, and friends), which are then never +# reinstalled — observed breaking CI. Installing each build dependency below in +# its own small transaction keeps every solver decision trivially satisfiable. +pkg update -f -# TODO(dragonfly-dns): remove once the DragonFlyBSD VM image has reliable DNS. -# Resolution of the package/source mirrors intermittently fails inside the VM, -# so pre-resolve them with drill and pin the result in /etc/hosts. Best-effort: -# a lookup miss leaves the host unpinned rather than failing the job. -for h in github.com packages.lazarus-ide.org downloads.freepascal.org; do - ip=$(drill "$h" 2>/dev/null | awk '/^'"$h"'/{print $5; exit}') - if [ -n "$ip" ]; then - echo "$ip $h" >> /etc/hosts - fi +# bash is mandatory: the VM 'run' step is `bash ...`. Keep it strict. +pkg install -y bash + +# Best-effort extras. The build no longer depends on any single one of these +# (make.pas falls back to fetch for downloads and the base image already ships +# openssl), so a solver miss must warn, not abort the whole job. +for p in gmake openssl curl; do + pkg install -y "$p" || echo "WARN(dragonfly-prepare): could not install $p; continuing" done +# Prefer full git over the base image's git-lite (git-lite omits features that +# lazbuild/tooling may want later). pkg swaps the conflicting git-lite out as +# part of installing git; best-effort so a solver miss leaves git-lite in place. +if pkg install -y git; then + pkg remove -y git-lite git-litem 2>/dev/null || true +else + echo "WARN(dragonfly-prepare): could not install full git; keeping git-lite if present" +fi + +# vmactions copies artifacts back out of the VM with rsync. The openssl upgrade +# above triggers an ABI cleanup that removes the base rsync (it was linked +# against the old openssl), so reinstall it or the job fails at the final +# "Copyback artifacts" step with "rsync: not found". Strict: the job cannot +# succeed without it, so surface a failure here rather than at copyback. +pkg install -y rsync + # TODO(FPC 3.2.4): drop the OpenSSL 1.1 shim once FPC links against OpenSSL 3. OPENSSL_USE_SUDO=0 bash "$CI_ROOT/openssl-libssl11-shim-unix.sh" /usr/local/lib diff --git a/.github/workflows/ci/vm-netbsd-prepare.sh b/.github/workflows/ci/vm-netbsd-prepare.sh index 3c3b10c..93d4f78 100644 --- a/.github/workflows/ci/vm-netbsd-prepare.sh +++ b/.github/workflows/ci/vm-netbsd-prepare.sh @@ -7,4 +7,6 @@ export PKG_PATH="https://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$ # Upgrade the base pcre2 first so the new tools link against it; tolerated # because a fresh image may have nothing to upgrade. pkg_add -uu pcre2 || true -pkg_add bash curl git gmake mozilla-rootcerts-openssl +# -u: update already-installed packages (the base image now ships bash) instead +# of failing on a version mismatch; not-yet-installed packages install normally. +pkg_add -u bash curl git gmake mozilla-rootcerts-openssl diff --git a/.github/workflows/install-fpc-lazarus.sh b/.github/workflows/install-fpc-lazarus.sh index f2ea290..75c7487 100644 --- a/.github/workflows/install-fpc-lazarus.sh +++ b/.github/workflows/install-fpc-lazarus.sh @@ -33,6 +33,12 @@ set -euo pipefail # Match only truthy values so a flat CI_DEBUG=0 (the CI default) stays quiet. case "${CI_DEBUG:-}" in 1|true|yes|on) set -x ;; esac +# tar (the FPC tarball extraction and install.sh's internal tars) inherits +# LANG/LC_* that some minimal VMs (notably DragonFly) point at a locale that +# isn't installed, which prints "tar: Failed to set default locale". Force the +# always-present C locale; harmless on every platform. +export LC_ALL=C LANG=C + INSTALL_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=ci/shared/common.sh source "$INSTALL_SCRIPT_DIR/ci/shared/common.sh" @@ -78,10 +84,9 @@ WORK_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t fpc-install)" cd "$WORK_DIR" echo "Downloading $URL" -# curl is on every platform we target; wget isn't (macOS notably). -# Retry to ride out transient mirror hiccups. -curl -fL --retry 5 --retry-delay 5 --retry-all-errors \ - -o "$TARBALL" "$URL" +# Prefer curl (Linux/macOS/Windows); fall back to wget, then the BSD base +# `fetch`. Retries ride out transient mirror hiccups. +ci_download "$URL" "$TARBALL" tar xf "$TARBALL" diff --git a/.github/workflows/make.pas b/.github/workflows/make.pas index c73c9cd..df2ed30 100644 --- a/.github/workflows/make.pas +++ b/.github/workflows/make.pas @@ -228,6 +228,8 @@ TMakeRunner = class procedure RunSampleProject(const APath: string); procedure InitSslForDownloads; procedure DownloadAndExtract(const AUrl, ADestDir: string); + procedure DownloadToFile(const AUrl, ADestFile: string); + function TryExternalDownload(const AUrl, ADestFile: string): Boolean; function GetDepsBaseDir(const ASubDir: string): string; function InstallOPMPackage(const APackageName: string): string; function InstallGitHubPackage(const AOwnerRepo, ARef: string): string; @@ -1592,60 +1594,119 @@ procedure TMakeRunner.UpdateSubmodules; Log(CSI_Yellow, Trim(CommandOutput)); end; -// TODO(FPC 3.2.4): drop this Windows override. FPC 3.2.2's openssl unit -// hardcodes the OpenSSL 1.1 DLL names (libssl-1_1*.dll / libeay32.dll), but -// modern Windows CI runners ship only OpenSSL 3.x. Point FPC at the 3.x DLLs -// so HTTPS downloads work. FPC 3.2.4+ already knows the OpenSSL 3 names, so -// this whole procedure can become a plain InitSSLInterface call then. procedure TMakeRunner.InitSslForDownloads; begin - {$IFDEF MSWINDOWS} - {$IFDEF WIN64} - DLLSSLName := 'libssl-3-x64.dll'; - DLLUtilName := 'libcrypto-3-x64.dll'; - {$ELSE} - DLLSSLName := 'libssl-3.dll'; - DLLUtilName := 'libcrypto-3.dll'; - {$ENDIF} - {$ENDIF} InitSSLInterface; end; procedure TMakeRunner.DownloadAndExtract(const AUrl, ADestDir: string); var TempFile: string; - Stream: TFileStream; - Client: TFPHttpClient; Unzipper: TUnZipper; begin TempFile := GetTempFileName; - Stream := TFileStream.Create(TempFile, fmCreate or fmOpenWrite); try - Client := TFPHttpClient.Create(nil); + DownloadToFile(AUrl, TempFile); + + CreateDir(ADestDir); + Unzipper := TUnZipper.Create; try - Client.AddHeader('User-Agent', 'Mozilla/5.0 (compatible; fpweb)'); - Client.AllowRedirect := True; - Client.Get(AUrl, Stream); - Log(CSI_Cyan, 'downloaded ' + AUrl); + Unzipper.FileName := TempFile; + Unzipper.OutputPath := ADestDir; + Unzipper.Examine; + Unzipper.UnZipAllFiles; + Log(CSI_Cyan, 'extracted to ' + ADestDir); finally - Client.Free; + Unzipper.Free; end; finally - Stream.Free; + DeleteFile(TempFile); end; +end; - CreateDir(ADestDir); - Unzipper := TUnZipper.Create; +procedure TMakeRunner.DownloadToFile(const AUrl, ADestFile: string); +var + Stream: TFileStream; + Client: TFPHttpClient; +begin + // Prefer FPC's own HTTP client; it works on every platform we target except + // DragonFlyBSD, where FPC 3.2.2's TInetSocket.Connect deterministically fails + // even though the host resolves and the system TLS stack is healthy (verified + // in CI: `fetch` downloads the very same URL/IP that TFPHttpClient cannot + // connect to). Treat any client failure as a cue to fall back to an external + // downloader rather than special-casing one OS. try - Unzipper.FileName := TempFile; - Unzipper.OutputPath := ADestDir; - Unzipper.Examine; - Unzipper.UnZipAllFiles; - Log(CSI_Cyan, 'extracted to ' + ADestDir); - finally - Unzipper.Free; - DeleteFile(TempFile); + Stream := TFileStream.Create(ADestFile, fmCreate or fmOpenWrite); + try + Client := TFPHttpClient.Create(nil); + try + Client.AddHeader('User-Agent', 'Mozilla/5.0 (compatible; fpweb)'); + Client.AllowRedirect := True; + Client.Get(AUrl, Stream); + Log(CSI_Cyan, 'downloaded ' + AUrl); + Exit; + finally + Client.Free; + end; + finally + Stream.Free; + end; + except + on E: Exception do + Log(CSI_Yellow, Format( + 'TFPHttpClient could not download %s (%s: %s); trying external downloader', + [AUrl, E.ClassName, E.Message])); + end; + + if not TryExternalDownload(AUrl, ADestFile) then + raise Exception.CreateFmt( + 'Failed to download %s via TFPHttpClient and external downloaders ' + + '(curl/wget/fetch)', [AUrl]); +end; + +function TMakeRunner.TryExternalDownload(const AUrl, ADestFile: string): Boolean; +const + UserAgent = 'Mozilla/5.0 (compatible; fpweb)'; +var + Output: string; +begin + // Tried in preference order; the first tool present on PATH that succeeds + // wins. RunCommandEx raises if the executable is absent, so each attempt is + // guarded and a missing tool simply falls through to the next. + try + if RunCommandEx('curl', + ['-fsSL', '-A', UserAgent, '-o', ADestFile, AUrl], '', False, Output) then + begin + Log(CSI_Cyan, 'downloaded ' + AUrl + ' via curl'); + Exit(True); + end; + except + on E: Exception do ; + end; + + try + if RunCommandEx('wget', + ['-q', '-U', UserAgent, '-O', ADestFile, AUrl], '', False, Output) then + begin + Log(CSI_Cyan, 'downloaded ' + AUrl + ' via wget'); + Exit(True); + end; + except + on E: Exception do ; end; + + try + if RunCommandEx('fetch', + ['-q', '-o', ADestFile, AUrl], '', False, Output) then + begin + Log(CSI_Cyan, 'downloaded ' + AUrl + ' via fetch'); + Exit(True); + end; + except + on E: Exception do ; + end; + + Result := False; end; function TMakeRunner.GetDepsBaseDir(const ASubDir: string): string; diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 29fd5ee..3d2a9c2 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -14,8 +14,7 @@ on: inputs: enabled_targets: description: >- - Comma-separated list of targets to run (leave empty for the default - set). Opt-in only: netbsd, dragonflybsd — pass explicitly here. + Comma-separated list of targets to run (leave empty for the default set). Valid IDs: linux-x64, linux-arm64, windows-x64, macos-arm64, macos-x64, linux-arm32, linux-powerpc64-be, freebsd, solaris, netbsd, dragonflybsd @@ -64,8 +63,10 @@ jobs: native: needs: setup # native_matrix is built from targets.json filtered to enabled native ids. - # An empty array would be an invalid matrix, so skip the job in that case. - if: needs.setup.outputs.native_matrix != '[]' + # When no native target is enabled, resolve-targets.sh emits a single + # placeholder entry (fpc_target=none) so the matrix is never empty: a job + # skipped via an empty matrix renders the literal `${{ matrix.name }}` in + # the UI. The placeholder's steps no-op via `matrix.fpc_target != 'none'`. name: ${{ matrix.name }} runs-on: ${{ matrix.runner }} timeout-minutes: 120 @@ -75,18 +76,20 @@ jobs: include: ${{ fromJSON(needs.setup.outputs.native_matrix) }} steps: - name: Checkout + if: matrix.fpc_target != 'none' uses: actions/checkout@v6 with: submodules: true - name: Build + if: matrix.fpc_target != 'none' shell: bash env: FPC_TARGET: ${{ matrix.fpc_target }} run: bash .github/workflows/ci/native-build.sh linux-arm32: - name: Linux ARMv7 (QEMU) + name: "QEMU: Linux ARMv7" runs-on: ubuntu-latest timeout-minutes: 120 needs: setup @@ -113,7 +116,7 @@ jobs: run: bash .github/workflows/ci/arm32-run.sh linux-powerpc64-be: - name: Linux PowerPC64 BE (QEMU) + name: "QEMU: Linux PowerPC64 BE" runs-on: ubuntu-latest timeout-minutes: 180 needs: setup @@ -136,7 +139,7 @@ jobs: run: bash .github/workflows/ci/ppc64-be-build.sh freebsd: - name: FreeBSD x86_64 + name: "VM: FreeBSD x86_64" runs-on: ubuntu-latest timeout-minutes: 120 needs: setup @@ -160,7 +163,7 @@ jobs: run: bash .github/workflows/ci/vm-freebsd-run.sh netbsd: - name: NetBSD x86_64 + name: "VM: NetBSD x86_64" runs-on: ubuntu-latest timeout-minutes: 120 needs: setup @@ -181,7 +184,7 @@ jobs: run: bash .github/workflows/ci/vm-run-shared.sh dragonflybsd: - name: DragonFlyBSD x86_64 + name: "VM: DragonFlyBSD x86_64" runs-on: ubuntu-latest timeout-minutes: 120 needs: setup @@ -204,7 +207,7 @@ jobs: run: bash .github/workflows/ci/vm-run-shared.sh solaris: - name: Solaris x86_64 + name: "VM: Solaris x86_64" runs-on: ubuntu-latest timeout-minutes: 120 needs: setup