Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions .github/workflows/ci/openssl-libssl11-shim-unix.sh
Original file line number Diff line number Diff line change
@@ -1,41 +1,72 @@
#!/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.<SHLIBVER> (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 \
/usr/lib/arm-linux-gnueabihf \
/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:-<unset>}" >&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
ln_cmd=(sudo ln -sf)
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"
43 changes: 43 additions & 0 deletions .github/workflows/ci/openssl-libssl11-shim-windows.sh
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions .github/workflows/ci/resolve-targets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down
34 changes: 33 additions & 1 deletion .github/workflows/ci/shared/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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() {
Expand All @@ -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" ;;
Expand Down
22 changes: 11 additions & 11 deletions .github/workflows/ci/targets.json
Original file line number Diff line number Diff line change
@@ -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 }
]
}
44 changes: 34 additions & 10 deletions .github/workflows/ci/vm-dragonfly-prepare.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 3 additions & 1 deletion .github/workflows/ci/vm-netbsd-prepare.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 9 additions & 4 deletions .github/workflows/install-fpc-lazarus.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"

Expand Down
Loading
Loading