Merge pull request #963 from sacredbanana/fbaserel

Amiga enhancements: Build for more platforms + package for Aminet
This commit is contained in:
Eric Hawicz authored and GitHub committed 2026-09-20 16:02:19 -04:00
commit 19980dbafd
7 files changed
+553 -4

No files matched your search

+73
View File
@@ -0,0 +1,73 @@
name: amiga
# Verifies that AmigaOS 3/4 and MorphOS still cross-compile. The uploaded
# json-c.lha is a CI convenience artifact only — official json-c releases
# remain source-only. Aminet uploads are a separate, manual process and
# are not published from this job.
on: [push, pull_request, workflow_dispatch]
concurrency:
group: ${{github.workflow}}-${{github.event.pull_request.number || github.ref}}
cancel-in-progress: true
permissions:
contents: read
jobs:
package:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v7
# Ubuntu's `lha` package is lhasa: extract-only, cannot create archives.
# Build LHa for UNIX (https://github.com/jca02266/lha) instead.
- name: Cache LHa for UNIX
id: cache-lha
uses: actions/cache@v6
with:
path: ~/.local/bin/lha
key: lha-16619b066b189ef289bb8b07b37d1c38d550da99-${{ runner.os }}
- name: Install LHa for UNIX
if: steps.cache-lha.outputs.cache-hit != 'true'
working-directory: ${{runner.temp}}
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake
curl -fsSL -o lha.tar.gz \
https://github.com/jca02266/lha/archive/16619b066b189ef289bb8b07b37d1c38d550da99.tar.gz
tar -xzf lha.tar.gz
cd lha-16619b066b189ef289bb8b07b37d1c38d550da99
autoreconf -is
./configure --prefix="$HOME/.local"
make -j"$(nproc)"
make install
- name: Add LHa to PATH
run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Check lha can create archives
run: |
command -v lha
d=$(mktemp -d)
echo probe > "$d/f"
( cd "$d" && lha -aq2 t.lha f )
test -s "$d/t.lha"
- name: Pull compiler images
run: |
docker pull sacredbanana/amiga-compiler:m68k-amigaos &
docker pull sacredbanana/amiga-compiler:ppc-amigaos &
docker pull sacredbanana/amiga-compiler:ppc-morphos &
wait
- name: Build and package
run: ./amiga/package-amiga.sh
- uses: actions/upload-artifact@v7
with:
name: json-c.lha
path: dist/json-c.lha
if-no-files-found: error
+4
View File
@@ -94,3 +94,7 @@
# Benchmarking input and output # Benchmarking input and output
/bench/data /bench/data
/bench/work /bench/work
# AmigaOS packaging output
dist/
bld-*/
+71 -3
View File
@@ -99,16 +99,77 @@ if (AMIGA)
else() else()
set(NEWLIB ON) set(NEWLIB ON)
endif() endif()
message(STATUS "Building for Motorola 68k AmigaOS using CRT: ${M68K_CRT}") if (NOT DEFINED M68K_BASEREL)
set(M68K_BASEREL "baserel")
endif()
set(M68K_BASEREL "${M68K_BASEREL}" CACHE STRING "m68k base-relative addressing: baserel, baserel32, or off")
set_property(CACHE M68K_BASEREL PROPERTY STRINGS baserel baserel32 off)
if (NOT M68K_BASEREL STREQUAL "baserel" AND
NOT M68K_BASEREL STREQUAL "baserel32" AND
NOT M68K_BASEREL STREQUAL "off")
message(FATAL_ERROR "M68K_BASEREL must be baserel, baserel32, or off (got: ${M68K_BASEREL})")
endif()
set(M68K_CPU "${M68K_CPU}" CACHE STRING "m68k CPU target (e.g. 68020, 68040, 68060); empty uses the compiler default")
if (M68K_CPU STREQUAL "" OR M68K_CPU STREQUAL "off")
set(M68K_CPU_FLAG "")
elseif (M68K_CPU MATCHES "^-")
set(M68K_CPU_FLAG "${M68K_CPU}")
elseif (M68K_CPU MATCHES "^m")
set(M68K_CPU_FLAG "-${M68K_CPU}")
else()
set(M68K_CPU_FLAG "-m${M68K_CPU}")
endif()
if (M68K_CPU_FLAG STREQUAL "")
message(STATUS "Building for Motorola 68k AmigaOS using CRT: ${M68K_CRT}, baserel: ${M68K_BASEREL}")
else()
message(STATUS "Building for Motorola 68k AmigaOS using CRT: ${M68K_CRT}, baserel: ${M68K_BASEREL}, cpu: ${M68K_CPU_FLAG}")
endif()
elseif ($ENV{CROSS_PFX} STREQUAL "ppc-amigaos") elseif ($ENV{CROSS_PFX} STREQUAL "ppc-amigaos")
set(AMIGA_PPC ON) 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") elseif($ENV{CROSS_PFX} STREQUAL "ppc-morphos")
set(MORPHOS ON) 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) if (NOIXEMUL)
message(STATUS "Building for PowerPC MorphOS without ixemul") message(STATUS "Building for PowerPC MorphOS without ixemul")
set(DISABLE_WERROR ON) set(DISABLE_WERROR ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -noixemul")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types")
else() else()
message(STATUS "Building for PowerPC MorphOS with ixemul") message(STATUS "Building for PowerPC MorphOS with ixemul")
endif() endif()
@@ -362,7 +423,14 @@ if ("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
endif() endif()
if (AMIGA_M68K) if (AMIGA_M68K)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fbaserel") if (M68K_BASEREL STREQUAL "baserel")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fbaserel")
elseif (M68K_BASEREL STREQUAL "baserel32")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fbaserel32")
endif()
if (NOT M68K_CPU_FLAG STREQUAL "")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${M68K_CPU_FLAG}")
endif()
endif() endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual")
+111 -1
View File
@@ -275,7 +275,9 @@ make install
Building for Commodore Amiga or MorphOS Building for Commodore Amiga or MorphOS
---------------------- ----------------------
Building for Commodore Amiga is supported for both Motorola 68k (AmigaOS 3) and PowerPC (AmigaOS 4) architectures. MorphOS on compatible PowerPC hardware is also supported. You can set up a cross compiler locally, however it is much easier to use the already preconfigured Amiga development environment wtthin a Docker container. Building for Commodore Amiga is supported for both Motorola 68k (AmigaOS 3) and PowerPC (AmigaOS 4) architectures. MorphOS on compatible PowerPC hardware is also supported. You can set up a cross compiler locally, however it is much easier to use the already preconfigured Amiga development environment within a Docker container.
Included below are instructions for building for specific individual systems, as well as how to build for *all* Amiga variants.
Install Docker on your machine if you don't already have it. You can download Docker Desktop for Windows/macOS/Linux [here](https://www.docker.com/products/docker-desktop/). Install Docker on your machine if you don't already have it. You can download Docker Desktop for Windows/macOS/Linux [here](https://www.docker.com/products/docker-desktop/).
@@ -296,6 +298,41 @@ libjson-c.a will get created in the build directory.
You can change newlib to nix20, nix13, ixemul or clib2 if you would like to build the library suited for libnix or clib2 instead. Newlib is default. You can change newlib to nix20, nix13, ixemul or clib2 if you would like to build the library suited for libnix or clib2 instead. Newlib is default.
By default the m68k build uses `-fbaserel`. You can select a different base-relative mode with `-DM68K_BASEREL=`:
* `baserel` (default) — `-fbaserel`
* `baserel32` — `-fbaserel32`
* `off` — no base-relative flag
```
cmake -DM68K_CRT=newlib -DM68K_BASEREL=baserel32 ..
cmake -DM68K_CRT=newlib -DM68K_BASEREL=off ..
```
You can also set the target CPU with `-DM68K_CPU=`. This is passed to the compiler as `-m<cpu>` (for example `68020` becomes `-m68020`). If omitted, the compiler default is used.
```
cmake -DM68K_CRT=newlib -DM68K_CPU=68020 ..
cmake -DM68K_CRT=newlib -DM68K_CPU=68040 -DM68K_BASEREL=baserel32 ..
```
A note on base-relative addressing (`-fbaserel`, i.e. `M68K_BASEREL=baserel`)
on m68k: a base-relative library keeps its globals at an offset from `a4`, and
`a4` is established once by the program's startup code. Such a library is only
safe inside a program that is itself base-relative **and** that declares every
function the OS can call back into (BOOPSI/MUI dispatchers, `struct Hook`
entries, interrupt servers) with `__saveds`, so `a4` is re-established on entry.
Without that, a hook entered from the OS runs with a foreign `a4` and every
`a4`-relative access made by this library -- or by libnix's `malloc` -- reads
from a wrong address.
Conversely, a library built *without* `-fbaserel` and compiled at `-O1` or above
may allocate `a4` as a scratch register. That is harmless in a program that is
also non-base-relative, but it corrupts the base pointer of a base-relative one.
In short: match `M68K_BASEREL` to the consuming program, and if that program is
base-relative make sure its OS callbacks are `__saveds`.
### To build for PowerPC Amiga: ### To build for PowerPC Amiga:
``` ```
@@ -311,6 +348,13 @@ make
libjson-c.a will get created in the build directory. 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: ### To build for PowerPC MorphOS:
``` ```
@@ -328,6 +372,72 @@ If you are making an application that absolutely requires ixemul, then remove th
libjson-c.a will get created in the build directory. 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 in the `amiga/` directory build the whole matrix across all three
systems, so you do not have to drive the container by hand.
* `amiga/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.
* `amiga/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 `amiga/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 a single `json-c/` directory at the root, with the readme and
one directory per system, each following the compiler's own layout so it can
be copied straight over an SDK:
```
json-c/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> <a name="linking"></a>
Linking to `libjson-c` Linking to `libjson-c`
---------------------- ----------------------
+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"