Package for Amiga for publishing

This commit is contained in:
Cameron Armstrong (Nightfox) committed 2026-08-23 22:19:43 +08:00
1 parent a52110770c
commit 3ea3271978
6 files changed
+397 -1

No files matched your search

+4
View File
@@ -94,3 +94,7 @@
# Benchmarking input and output
/bench/data
/bench/work
# AmigaOS packaging output
dist/
bld-*/
+37 -1
View File
@@ -126,9 +126,45 @@ if (AMIGA)
endif()
elseif ($ENV{CROSS_PFX} STREQUAL "ppc-amigaos")
set(AMIGA_PPC ON)
message(STATUS "Building for PowerPC AmigaOS")
if (NOT DEFINED PPC_CRT)
set(PPC_CRT "newlib")
endif()
set(PPC_CRT "${PPC_CRT}" CACHE STRING "ppc-amigaos C runtime: newlib, clib2 or clib4")
set_property(CACHE PPC_CRT PROPERTY STRINGS newlib clib2 clib4)
if (NOT PPC_CRT STREQUAL "newlib" AND
NOT PPC_CRT STREQUAL "clib2" AND
NOT PPC_CRT STREQUAL "clib4")
message(FATAL_ERROR "PPC_CRT must be newlib, clib2 or clib4 (got: ${PPC_CRT})")
endif()
if (NOT PPC_CRT STREQUAL "newlib")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcrt=${PPC_CRT}")
endif()
message(STATUS "Building for PowerPC AmigaOS using CRT: ${PPC_CRT}")
elseif($ENV{CROSS_PFX} STREQUAL "ppc-morphos")
set(MORPHOS ON)
if (NOT DEFINED MORPHOS_CLIB)
set(MORPHOS_CLIB "default")
endif()
set(MORPHOS_CLIB "${MORPHOS_CLIB}" CACHE STRING "MorphOS C library: default or libnix")
set_property(CACHE MORPHOS_CLIB PROPERTY STRINGS default libnix)
if (NOT MORPHOS_CLIB STREQUAL "default" AND NOT MORPHOS_CLIB STREQUAL "libnix")
message(FATAL_ERROR "MORPHOS_CLIB must be default or libnix (got: ${MORPHOS_CLIB})")
endif()
option(MORPHOS_BASEREL32 "MorphOS: build with -mbaserel32" OFF)
if (MORPHOS_CLIB STREQUAL "libnix")
# Same situation as the -noixemul path below: libnix's headers
# disagree with the ixemul ones about va_list, so the varargs
# helpers in debug.c trip -Wincompatible-pointer-types.
set(DISABLE_WERROR ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types")
endif()
if (MORPHOS_CLIB STREQUAL "libnix")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mclib=libnix")
endif()
if (MORPHOS_BASEREL32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mbaserel32")
endif()
message(STATUS "Building for PowerPC MorphOS using clib: ${MORPHOS_CLIB}, baserel32: ${MORPHOS_BASEREL32}")
if (NOIXEMUL)
message(STATUS "Building for PowerPC MorphOS without ixemul")
set(DISABLE_WERROR ON)
+73
View File
@@ -346,6 +346,13 @@ make
libjson-c.a will get created in the build directory.
Select the C runtime with `-DPPC_CRT=`: `newlib` (default), `clib2` or `clib4`.
Anything other than `newlib` is passed to the compiler as `-mcrt=<value>`.
```
cmake -DPPC_CRT=clib4 ..
```
### To build for PowerPC MorphOS:
```
@@ -363,6 +370,72 @@ If you are making an application that absolutely requires ixemul, then remove th
libjson-c.a will get created in the build directory.
Two further options apply to MorphOS:
* `-DMORPHOS_CLIB=` selects `default` (ixemul) or `libnix` (passed as
`-mclib=libnix`). That is the same multilib `-noixemul` selects, and is the
self-contained ABI -- an ixemul build needs `ixemul.library` on the target.
* `-DMORPHOS_BASEREL32=ON` adds `-mbaserel32`.
```
cmake -DMORPHOS_CLIB=libnix ..
cmake -DMORPHOS_BASEREL32=ON ..
```
### Building and packaging every variant
Two scripts at the repository root build the whole matrix across all three
systems, so you do not have to drive the container by hand.
* `build-amiga-sdk.sh [OS ...]` — builds every variant and installs
`libjson-c.a` plus the `json-c/` headers into an SDK tree. The location comes
from `$AMIGA_SDK` (default `/opt/amiga`); either a `<target>/` or an
AmigaSDK-gcc-style `amigaos3/sdk/<target>/` layout is accepted, and an OS
whose subdirectory is absent is skipped rather than failing.
* `package-amiga.sh [OS ...]` — builds the same matrix into a staging tree and
produces `dist/json-c.lha` for distribution.
Both default to `AmigaOS3 AmigaOS4 MorphOS`, and both take the variant list
from the same table in `build-amiga-sdk.sh`, so they cannot disagree. 22
libraries are built in total: 15 for AmigaOS 3 (newlib, libnix and clib2, each
across the five multilib slots), 3 for AmigaOS 4 (newlib, clib2, clib4) and 4
for MorphOS (ixemul and native, each with and without `-mbaserel32`).
Which of them actually *link* is a separate question from whether they build,
and was checked by compiling a program against each one:
| target | links |
|--------|-------|
| AmigaOS 3, libnix | all 5 slots |
| AmigaOS 3, clib2 | `lib/libm020/` and `lib/libb32/libm020/` only |
| AmigaOS 3, newlib | none -- the m68k newlib tree has no `gettimeofday()` |
| AmigaOS 4 | all 3 (newlib, clib2, clib4) |
| MorphOS | all 4 slots |
The clib2 failures are inside clib2 itself: its 68000 multilib provides no
`strtoll`/`strtoull`, and 16-bit `-fbaserel` overflows with *truncated to fit:
DREL16* once json-c's data is added -- `-fbaserel32` has no 64 KB limit. Link
with `-ljson-c -lm` after your own objects, and add `-lunix` for clib2.
The archive is laid out with the readme at the root and one directory per
system, each following the compiler's own layout so it can be copied straight
over an SDK:
```
json-c.readme
json-c/AmigaOS3/{include,lib,...}/ plus libnix/ and clib2/ subtrees
json-c/AmigaOS4/{include,lib,lib/clib2,lib/clib4}/
json-c/MorphOS/{include,lib,lib/libb32,lib/libnix}/
```
Note that m68k and PPC lay their C runtimes out differently, and the variant
table follows each. On m68k a runtime is a separate tree (`libnix/`, `clib2/`),
each with its own `include/` and `lib/`. On PPC a runtime is a multilib *slot*
beneath a single shared `lib/`: `-mcrt=clib4` searches `<target>/lib/clib4/`
and takes headers from `<target>/include/`. This was read off
`-print-search-dirs` rather than assumed, because installing to the wrong one
produces a library the compiler silently never finds.
<a name="linking"></a>
Linking to `libjson-c`
----------------------
+111
View File
@@ -0,0 +1,111 @@
#!/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.
#
# ./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}
cd "$(dirname "$0")"
ROOT=$PWD
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 Haszlakiewicz et al.
Uploader: Cameron Armstrong <cameronscottarmstrong@gmail.com>
Type: dev/lib
Version: 0.19.99
Architecture: m68k-amigaos >= 2.0; ppc-amigaos; ppc-morphos
Distribution: Aminet
Requires: an Amiga gcc cross compiler
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.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.
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Build every json-c variant for the requested Amiga systems and package them
# into dist/json-c.lha.
#
# ./package-amiga.sh [OS ...] # default: all three
#
# Archive layout:
# json-c.readme at the archive root
# json-c/AmigaOS3/... per-OS libraries and headers
# json-c/AmigaOS4/...
# json-c/MorphOS/...
set -uo pipefail
cd "$(dirname "$0")"
ROOT=$PWD
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; }
# 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 "$ROOT/json-c.readme" "$STAGE/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" ./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"