Address review feedback on the Amiga packaging PR.

Keep Amiga-specific files under amiga/, cache the pinned LHa binary in
CI, and make it explicit that the workflow artifact is not an official
release.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Cameron Armstrong (Nightfox)andCursor committed 2026-08-30 23:28:43 +08:00
1 parent 385c46ef39
commit 083d244d9a
5 files changed
+37 -18

No files matched your search

+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env bash
# Cross-build json-c for Amiga systems across every multilib slot and install
# the archives plus headers into an SDK tree.
#
# ./amiga/build-amiga-sdk.sh [OS ...] # default: AmigaOS3 AmigaOS4 MorphOS
#
# SDK location comes from $AMIGA_SDK (default /opt/amiga).
set -uo pipefail
SDK=${AMIGA_SDK:-/opt/amiga}
AMIGA_DIR=$(cd "$(dirname "$0")" && pwd)
ROOT=$(cd "$AMIGA_DIR/.." && pwd)
cd "$ROOT"
OSES=("$@"); [[ ${#OSES[@]} -eq 0 ]] && OSES=(AmigaOS3 AmigaOS4 MorphOS)
# os | image tag | sdk subdir
os_image() { case "$1" in
AmigaOS3) echo "sacredbanana/amiga-compiler:m68k-amigaos m68k-amigaos" ;;
AmigaOS4) echo "sacredbanana/amiga-compiler:ppc-amigaos ppc-amigaos" ;;
MorphOS) echo "sacredbanana/amiga-compiler:ppc-morphos ppc-morphos" ;;
*) return 1 ;;
esac; }
# Where an AmigaSDK-gcc-style checkout keeps each system's target tree.
os_sdkdir() { case "$1" in
AmigaOS3) echo "amigaos3/sdk" ;;
AmigaOS4) echo "amigaos4/sdk" ;;
MorphOS) echo "morphos/sdk" ;;
*) return 1 ;;
esac; }
# Per-OS variant table: "tree|slot|cmake args"
variants_AmigaOS3=(
"libnix|.|-DM68K_CRT=nix20 -DM68K_CPU=68000 -DM68K_BASEREL=off"
"libnix|libm020|-DM68K_CRT=nix20 -DM68K_CPU=68020 -DM68K_BASEREL=off"
"libnix|libb|-DM68K_CRT=nix20 -DM68K_CPU=68000 -DM68K_BASEREL=baserel"
"libnix|libb/libm020|-DM68K_CRT=nix20 -DM68K_CPU=68020 -DM68K_BASEREL=baserel"
"libnix|libb32/libm020|-DM68K_CRT=nix20 -DM68K_CPU=68020 -DM68K_BASEREL=baserel32"
".|.|-DM68K_CRT=newlib -DM68K_CPU=68000 -DM68K_BASEREL=off"
".|libm020|-DM68K_CRT=newlib -DM68K_CPU=68020 -DM68K_BASEREL=off"
".|libb|-DM68K_CRT=newlib -DM68K_CPU=68000 -DM68K_BASEREL=baserel"
".|libb/libm020|-DM68K_CRT=newlib -DM68K_CPU=68020 -DM68K_BASEREL=baserel"
".|libb32/libm020|-DM68K_CRT=newlib -DM68K_CPU=68020 -DM68K_BASEREL=baserel32"
"clib2|.|-DM68K_CRT=clib2 -DM68K_CPU=68000 -DM68K_BASEREL=off"
"clib2|libm020|-DM68K_CRT=clib2 -DM68K_CPU=68020 -DM68K_BASEREL=off"
"clib2|libb|-DM68K_CRT=clib2 -DM68K_CPU=68000 -DM68K_BASEREL=baserel"
"clib2|libb/libm020|-DM68K_CRT=clib2 -DM68K_CPU=68020 -DM68K_BASEREL=baserel"
"clib2|libb32/libm020|-DM68K_CRT=clib2 -DM68K_CPU=68020 -DM68K_BASEREL=baserel32"
)
# Unlike m68k, where each C runtime is its own tree (libnix/, clib2/), the PPC
# toolchains make the runtime a multilib SLOT under lib/, with headers coming
# from the shared <target>/include/. Verified with -print-search-dirs:
# ppc-amigaos -mcrt=clib2 -> <target>/lib/clib2/
# ppc-amigaos -mcrt=clib4 -> <target>/lib/clib4/
# ppc-morphos -mclib=libnix-> <target>/lib/libnix/
# ppc-morphos -mbaserel32 -> <target>/lib/libb32/
variants_AmigaOS4=(
".|.|-DPPC_CRT=newlib"
".|clib2|-DPPC_CRT=clib2"
".|clib4|-DPPC_CRT=clib4"
)
# MORPHOS_CLIB=libnix (-mclib=libnix) and NOIXEMUL (-noixemul) select the same
# multilib; it is the self-contained ABI, needing no ixemul.library on target.
variants_MorphOS=(
".|.|"
".|libb32|-DMORPHOS_BASEREL32=ON"
".|libnix|-DMORPHOS_CLIB=libnix"
".|libb32/libnix|-DMORPHOS_CLIB=libnix -DMORPHOS_BASEREL32=ON"
)
# $1 out-dir-for-libs $2 out-dir-for-headers $3.. OS list
ok=0; fail=0; failed=()
for os in "${OSES[@]}"; do
read -r image sdksub <<<"$(os_image "$os")" || { echo "skip: unknown OS $os"; continue; }
# /opt/amiga keeps the target tree directly under <target>/, while an
# AmigaSDK-gcc checkout nests it under <os>/sdk/<target>. Accept either.
osdir=$(os_sdkdir "$os")
if [[ -d $SDK/$sdksub ]]; then SDKROOT=$SDK/$sdksub
elif [[ -d $SDK/$osdir/$sdksub ]]; then SDKROOT=$SDK/$osdir/$sdksub
else echo "skip $os: neither $SDK/$sdksub nor $SDK/$osdir/$sdksub"; continue; fi
eval "vars=(\"\${variants_$os[@]}\")"
for v in "${vars[@]}"; do
IFS='|' read -r tree slot cargs <<<"$v"
bdir="bld-$os-$(echo "$tree$slot$cargs" | tr -c 'A-Za-z0-9' '-' | cut -c1-40)"
printf ' %-9s %-7s %-16s ' "$os" "$tree" "$slot"
if ! docker run --rm -v "$ROOT":/work -e USER="$(id -u)" -e GROUP="$(id -g)" "$image" sh -c "
set -e
rm -rf /work/$bdir && mkdir -p /work/$bdir && cd /work/$bdir
cmake $cargs -DCMAKE_BUILD_TYPE=Release -DBUILD_APPS=NO \
-DCMAKE_INSTALL_PREFIX=/work/$bdir/inst .. >cmake.log 2>&1
make -j\$(nproc) json-c >make.log 2>&1
make install >install.log 2>&1
" 2>/dev/null; then
echo "BUILD FAILED (logs in $bdir)"; fail=$((fail+1)); failed+=("$os/$tree/$slot"); continue
fi
lib=$bdir/libjson-c.a
[[ -f $lib ]] || lib=$bdir/inst/lib/libjson-c.a
[[ -f $lib ]] || { echo "no libjson-c.a"; fail=$((fail+1)); failed+=("$os/$tree/$slot"); continue; }
base=$SDKROOT; [[ $tree != "." ]] && base=$SDKROOT/$tree
dest=$base/lib; [[ $slot != "." ]] && dest=$base/lib/$slot
mkdir -p "$dest" "$base/include"
cp "$lib" "$dest/libjson-c.a"
cp -a "$bdir/inst/include/json-c" "$base/include/"
echo "ok"; ok=$((ok+1)); rm -rf "$bdir"
done
done
echo
echo "built+installed: $ok failed: $fail"
((fail)) && { printf 'failures: %s\n' "${failed[*]}"; exit 1; }
exit 0
+110
View File
@@ -0,0 +1,110 @@
Short: JSON parser and generator library (static libs + headers)
Author: Michael Clark, Eric Hawicz et al.
Uploader: Cameron Armstrong (Nightfox) <cameronscottarmstrong@gmail.com>
Type: dev/lib
Version: 0.19
Architecture: m68k-amigaos >= 2.0; ppc-amigaos; ppc-morphos
Requires: an Amiga gcc compiler
Replaces: dev/lib/json-c.lha
json-c implements a reference-counted object model for JSON, a parser that
builds it from text, and a serialiser that writes it back out. This archive
contains static libraries and public headers for Amiga development.
https://github.com/json-c/json-c
Contents
json-c/json-c.readme this file
json-c/AmigaOS3/... m68k AmigaOS libraries and headers
json-c/AmigaOS4/... ppc-amigaos libraries and headers
json-c/MorphOS/... ppc-morphos libraries and headers
Under each OS directory the trees follow the compiler's own layout, so
they can be copied straight over an existing SDK, e.g.
cp -a json-c/AmigaOS3/* /opt/amiga/m68k-amigaos/
AmigaOS3 ships one set per C runtime -- newlib at the top level, plus
libnix/ and clib2/ -- and within each, one library per multilib:
lib/ 68000, absolute addressing
lib/libm020/ 68020, absolute addressing
lib/libb/ 68000, -fbaserel
lib/libb/libm020/ 68020, -fbaserel
lib/libb32/libm020/ 68020, -fbaserel32
On PPC a C runtime is not a separate tree but a multilib slot beneath one
shared lib/, with headers in the single shared include/:
AmigaOS4 lib/ newlib
lib/clib2/ clib2
lib/clib4/ clib4
MorphOS lib/ ixemul
lib/libb32/ ixemul, -mbaserel32
lib/libnix/ native C library (-noixemul)
lib/libb32/libnix/ native C library, -mbaserel32
-mclib=libnix and -noixemul select the same MorphOS multilib. That ABI is
the self-contained one -- an ixemul build needs ixemul.library on the
target -- so prefer lib/libnix/ for new code.
Usage
#include <json-c/json.h>
struct json_object *o = json_tokener_parse("{\"a\":1}");
printf("%s\n", json_object_to_json_string(o));
json_object_put(o);
Link with -ljson-c -lm, after your own objects on the command line. For
clib2 add -lunix as well, since clib2 keeps its POSIX layer there.
Which variants link
Verified by compiling the snippet above against each shipped library.
AmigaOS3 libnix all 5 slots link.
clib2 lib/libm020/ and lib/libb32/libm020/ link. The other
three fail inside clib2 itself: its 68000 multilib has
no strtoll()/strtoull(), and 16-bit -fbaserel overflows
with "truncated to fit: DREL16" once json-c's data is
added. -fbaserel32 has no such limit.
newlib builds, but does not link: the m68k newlib tree has no
gettimeofday(). The libraries are shipped anyway, since
that is a gap in the SDK rather than in json-c and a
newlib with gettimeofday() implemented would link.
AmigaOS4 all three (newlib, clib2, clib4) link.
MorphOS all four slots link.
A note on base-relative addressing (AmigaOS3)
A base-relative library addresses its globals through a4, which the
program's startup code sets up once. Only link the libb/ or libb32/
variants into a program that is itself base-relative AND that marks every
function the OS calls back into (BOOPSI/MUI dispatchers, struct Hook
entries, interrupt servers) with __saveds. The m68k SDI_hook.h macros set
up register arguments but do not add __saveds, so this is easy to get
wrong, and the failure mode is intermittent memory corruption rather than
a clean error -- libnix keeps malloc's heap state in a4-relative storage.
Conversely a non-base-relative library built at -O1 or above may use a4 as
a scratch register, which is harmless in a non-base-relative program but
corrupts the base pointer of one that is.
Match the variant to the program. If in doubt, use the plain lib/ or
lib/libm020/ builds.
Licence
MIT; see COPYING in the source distribution.
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# Build every json-c variant for the requested Amiga systems and package them
# into dist/json-c.lha.
#
# ./amiga/package-amiga.sh [OS ...] # default: all three
#
# Archive layout (single directory at the root):
# json-c/json-c.readme
# json-c/AmigaOS3/... per-OS libraries and headers
# json-c/AmigaOS4/...
# json-c/MorphOS/...
set -uo pipefail
AMIGA_DIR=$(cd "$(dirname "$0")" && pwd)
ROOT=$(cd "$AMIGA_DIR/.." && pwd)
cd "$ROOT"
DIST=$ROOT/dist
STAGE=$DIST/stage
OSES=("$@"); [[ ${#OSES[@]} -eq 0 ]] && OSES=(AmigaOS3 AmigaOS4 MorphOS)
command -v lha >/dev/null || { echo "error: lha not found on PATH" >&2; exit 1; }
# Ubuntu's `lha` package is lhasa, which can only extract.
_lha_probe=$(mktemp -d)
echo x > "$_lha_probe/f"
if ! ( cd "$_lha_probe" && lha -aq2 t.lha f >/dev/null 2>&1 && [[ -s t.lha ]] ); then
echo "error: lha cannot create archives (is it lhasa?). Install LHa for UNIX: https://github.com/jca02266/lha" >&2
rm -rf "$_lha_probe"
exit 1
fi
rm -rf "$_lha_probe"
# Build straight into the staging tree by pointing AMIGA_SDK at it: the build
# script's SDK layout ($SDK/<target>) is the same shape we want per OS, so each
# OS gets staged under its own directory.
rm -rf "$DIST"; mkdir -p "$STAGE/json-c"
cp "$AMIGA_DIR/json-c.readme" "$STAGE/json-c/json-c.readme"
built=()
for os in "${OSES[@]}"; do
case "$os" in
AmigaOS3) sub=m68k-amigaos ;;
AmigaOS4) sub=ppc-amigaos ;;
MorphOS) sub=ppc-morphos ;;
*) echo "skip: unknown OS $os"; continue ;;
esac
tmp=$DIST/sdk-$os
mkdir -p "$tmp/$sub"
echo "=== $os ==="
# Stage whatever landed even if some variants failed -- a single unsupported
# multilib should not drop the whole OS from the archive.
AMIGA_SDK="$tmp" "$AMIGA_DIR/build-amiga-sdk.sh" "$os" || echo " ($os: some variants failed, see above)"
if [[ -n $(find "$tmp/$sub" -name 'libjson-c.a' -print -quit 2>/dev/null) ]]; then
mkdir -p "$STAGE/json-c/$os"
cp -a "$tmp/$sub/." "$STAGE/json-c/$os/"
built+=("$os")
else
echo " $os: nothing built, omitted from the archive"
fi
rm -rf "$tmp"
done
[[ ${#built[@]} -eq 0 ]] && { echo "nothing built"; exit 1; }
# NOTE: build the archive from a clean staging tree with `lha -aq2`. Do NOT try
# to refresh a single entry (e.g. the readme) in an existing archive with
# `lha u` -- it APPENDS a second entry with the same name rather than replacing
# it, and extraction then yields the stale copy.
( cd "$STAGE" && lha -aq2 "$DIST/json-c.lha" * >/dev/null )
rm -rf "$STAGE"
echo
echo "packaged: ${built[*]}"
ls -la "$DIST"