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
9 changes: 9 additions & 0 deletions .github/workflows/ci/arm32-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail

# shellcheck source=shared/common.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/shared/common.sh"
ci_init_paths

export OPENSSL_ARCH_DIR=/usr/lib/arm-linux-gnueabihf
ci_debian_container_bootstrap
14 changes: 14 additions & 0 deletions .github/workflows/ci/arm32-run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail

CI_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# run-on-arch-action `install` runs at docker build time (no repo mount).
# Install deps here in `run` so arm32-install.sh stays the single source of truth.
bash "$CI_ROOT/arm32-install.sh"

# shellcheck source=shared/common.sh
source "$CI_ROOT/shared/common.sh"
ci_init_paths

ci_build_standard
9 changes: 9 additions & 0 deletions .github/workflows/ci/native-build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail

# shellcheck source=shared/common.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/shared/common.sh"
ci_init_paths

ci_openssl_hack
ci_build_standard
9 changes: 9 additions & 0 deletions .github/workflows/ci/openssl-libssl11-shim-macos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# TODO(FPC 3.2.4): remove this shim. FPC 3.2.2 hardcodes libssl.1.1.dylib, so
# symlink Homebrew's OpenSSL 3 dylibs to the 1.1 names on macOS.
set -euo pipefail

OSSL_LIB="$(brew --prefix openssl@3)/lib"
sudo mkdir -p /usr/local/lib
sudo ln -sf "$OSSL_LIB/libssl.3.dylib" /usr/local/lib/libssl.1.1.dylib
sudo ln -sf "$OSSL_LIB/libcrypto.3.dylib" /usr/local/lib/libcrypto.1.1.dylib
41 changes: 41 additions & 0 deletions .github/workflows/ci/openssl-libssl11-shim-unix.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/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.
set -euo pipefail

ARCH_DIR="${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
ARCH_DIR="/usr/lib/$multiarch"
fi
fi
if [ -z "$ARCH_DIR" ] || [ ! -f "$ARCH_DIR/libssl.so.3" ]; 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
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
exit 1
fi

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"
47 changes: 47 additions & 0 deletions .github/workflows/ci/ppc64-be-build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail

: "${GITHUB_WORKSPACE:?GITHUB_WORKSPACE is required}"
: "${FPC_VERSION:?FPC_VERSION is required}"
: "${FPC_TARGET:?FPC_TARGET is required}"
: "${MAKE_BUILD_BACKEND:?MAKE_BUILD_BACKEND is required}"

CI_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CI_SHARED="$CI_ROOT/shared"
# shellcheck source=ppc64-be-images.env
source "$CI_ROOT/ppc64-be-images.env"

# Cross-compile glibc csu stubs on the x86 host. gcc inside QEMU ppc64
# user-mode often SIGSEGVs; install-fpc-lazarus.sh expects CSU_STUBS_PREBUILT.
STUB_C="$(mktemp --suffix=.c)"
STUB_OBJ="$(mktemp --suffix=.o)"
CSU_STUBS_IN_CONTAINER=/csu_stubs_prebuilt.o
trap 'rm -f "$STUB_C" "$STUB_OBJ"' EXIT

cp "$CI_SHARED/csu-stubs.c" "$STUB_C"

sudo apt-get update -qq
sudo apt-get install -y -qq gcc-powerpc64-linux-gnu
powerpc64-linux-gnu-gcc -c -fPIC -o "$STUB_OBJ" "$STUB_C"
if [ ! -s "$STUB_OBJ" ]; then
echo "::error::cross-compile did not produce csu stubs object at $STUB_OBJ" >&2
exit 1
fi
echo "csu stubs cross-compiled: $(wc -c < "$STUB_OBJ") bytes"

docker run --rm --platform linux/ppc64 \
--security-opt seccomp=unconfined \
-v "${GITHUB_WORKSPACE}:/work" -w /work \
-v "${STUB_OBJ}:${CSU_STUBS_IN_CONTAINER}:ro" \
-e FPC_VERSION \
-e FPC_TARGET \
-e MAKE_BUILD_BACKEND \
-e MAKE_PACKAGE_SCOPE \
-e LAZARUS_BRANCH \
-e LAZARUS_REPO \
-e CI_DEBUG \
-e DEBIAN_FRONTEND=noninteractive \
-e QEMU_CPU=power8 \
-e CSU_STUBS_PREBUILT="${CSU_STUBS_IN_CONTAINER}" \
"$PPC64_RUNTIME_IMAGE" \
bash .github/workflows/ci/ppc64-be-inner.sh
21 changes: 21 additions & 0 deletions .github/workflows/ci/ppc64-be-images.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Pinned image for the linux-powerpc64-be CI flow (sourced by ppc64-be-build.sh).
#
# QEMU (the ppc64 big-endian emulator) is NOT pinned here: it is installed from
# the Ubuntu runner's apt as qemu-user-static (currently QEMU ~8.2) by
# ppc64-qemu-setup.sh. Rationale:
# - multiarch/qemu-user-static is abandoned (frozen at QEMU 7.2.0, Jan 2023).
# - tonistiigi/binfmt ships only little-endian ppc64le, not big-endian ppc64.
# The distro package gives us a current big-endian qemu-ppc64 and auto-registers
# its binfmt handler with the F (fix-binary) flag. See ppc64-qemu-setup.sh.
#
# Runtime rootfs: Debian-ports ppc64 (big-endian) exists only in sid, so there is
# no stable release to track. We currently track the rolling tag and let the
# floating distro QEMU (see above) keep pace with the userland. If sid ever drifts
# ahead of the emulator again (intermittent SIGSEGV / "ppcXXX can't be executed"),
# re-pin by digest: swap the active line below for the commented one and refresh via
# docker buildx imagetools inspect urbanogilson/debian-debootstrap-ports:ppc64-forky-sid
# (full variant — qemu-ppc64-static embedded upstream).
# https://github.com/urbanogilson/debian-debootstrap-ports
PPC64_RUNTIME_IMAGE=urbanogilson/debian-debootstrap-ports:ppc64-forky-sid
# Last-known-good digest (2026-05-15, gcc 15 userland) — uncomment to pin:
# PPC64_RUNTIME_IMAGE=urbanogilson/debian-debootstrap-ports:ppc64-forky-sid@sha256:5a0b62beaeb64dec7ed941f3a28d30827ea0f773b9d10a3f66c79dce48f36841
10 changes: 10 additions & 0 deletions .github/workflows/ci/ppc64-be-inner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail

# shellcheck source=shared/common.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/shared/common.sh"
ci_init_paths

export OPENSSL_ARCH_DIR=/usr/lib/powerpc64-linux-gnu
ci_debian_container_bootstrap gcc binutils
ci_build_standard
38 changes: 38 additions & 0 deletions .github/workflows/ci/ppc64-qemu-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail

# Register the ppc64 (big-endian) binfmt handler on the runner host so that
# `docker run --platform linux/ppc64 ...` (ppc64-be-build.sh) transparently
# executes big-endian binaries under QEMU user-mode.
#
# We install QEMU from the Ubuntu runner's apt (qemu-user-static, currently
# ~8.2) rather than multiarch/qemu-user-static (abandoned at 7.2.0) or
# tonistiigi/binfmt (little-endian ppc64le only). The package's postinst
# registers each handler with the F (fix-binary) flag via update-binfmts, so
# the interpreter fd is preserved into the container and qemu does not need to
# exist inside the rootfs. See ppc64-be-images.env for the rationale.

export DEBIAN_FRONTEND=noninteractive
sudo apt-get update -qq
sudo apt-get install -y -qq qemu-user-static binfmt-support

# Idempotent: enable the handler in case it was installed but left disabled.
sudo update-binfmts --enable qemu-ppc64 2>/dev/null || true

BINFMT_FILE=/proc/sys/fs/binfmt_misc/qemu-ppc64
if [ ! -e "$BINFMT_FILE" ]; then
echo "::error::qemu-ppc64 binfmt handler not registered"
ls /proc/sys/fs/binfmt_misc/ || true
exit 1
fi

echo "qemu-ppc64-static: $(qemu-ppc64-static --version 2>/dev/null | head -1 || echo 'unknown')"
echo "binfmt handler ${BINFMT_FILE}:"
cat "$BINFMT_FILE"

# F (fix-binary) is required so the interpreter works inside the container.
if ! grep -q 'flags:.*F' "$BINFMT_FILE"; then
echo "::error::qemu-ppc64 binfmt flags missing F (fix-binary mode); got:" >&2
cat "$BINFMT_FILE" >&2
exit 1
fi
62 changes: 62 additions & 0 deletions .github/workflows/ci/resolve-targets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail

# Resolve which targets CI should run, from the registry in targets.json.
#
# Inputs:
# INPUT_TARGETS workflow_dispatch CSV. Empty => default set (default=true).
# Outputs (GITHUB_OUTPUT):
# enabled_targets CSV of selected ids; gates the qemu/vm jobs in make.yml.
# native_matrix JSON array of enabled kind=native entries; consumed as the
# native job's strategy.matrix.include (empty => job skipped).
#
# targets.json is the single source of truth. Opt-in targets (default=false,
# e.g. netbsd, dragonflybsd) are excluded from the default and must be named
# explicitly via INPUT_TARGETS.

CI_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REGISTRY="$CI_ROOT/targets.json"

VALID_TARGETS="$(jq -r '[.targets[].id] | join(",")' "$REGISTRY")"
DEFAULT="$(jq -r '[.targets[] | select(.default) | .id] | join(",")' "$REGISTRY")"

if [ -z "${INPUT_TARGETS// /}" ]; then
TARGETS="$DEFAULT"
SOURCE="default"
else
TARGETS="${INPUT_TARGETS// /}"
SOURCE="workflow_dispatch input"
fi

# Warn (don't fail) on unknown ids so a typo is visible but harmless: an
# unrecognised id simply matches no job.
IFS=',' read -r -a _selected <<< "$TARGETS"
IFS=',' read -r -a _valid <<< "$VALID_TARGETS"
for _id in "${_selected[@]}"; do
[ -z "$_id" ] && continue
_found=0
for _v in "${_valid[@]}"; do
if [ "$_id" = "$_v" ]; then
_found=1
break
fi
done
if [ "$_found" -eq 0 ]; then
echo "::warning::Unknown target id \"${_id}\" (valid: ${VALID_TARGETS})"
fi
done

# Filter the registry to enabled native entries. Bind .id before switching the
# pipe context to the split list; index() returns null when absent (falsy) and
# an integer otherwise (0 is truthy in jq).
NATIVE_MATRIX="$(jq -c --arg ids "$TARGETS" \
'[.targets[] | select(.kind == "native") | select(.id as $i | ($ids | split(",") | index($i)))]' \
"$REGISTRY")"

{
echo "enabled_targets=${TARGETS}"
echo "native_matrix=${NATIVE_MATRIX}"
} >> "${GITHUB_OUTPUT:?GITHUB_OUTPUT is required}"

echo "Enabled targets (${SOURCE}): ${TARGETS}"
echo "Native matrix: ${NATIVE_MATRIX}"
Loading
Loading