Merge pull request #216 from mcayland/feature/docker-build-universal

Retro68: improve Docker support to enable builds with Universal interfaces
This commit is contained in:
Wolfgang Thaller 2023-12-17 23:03:12 +01:00 committed by GitHub
commit a3db211410
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 264 additions and 1 deletions

View File

@ -7,7 +7,7 @@ RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
cmake libgmp-dev libmpfr-dev libmpc-dev \
libboost-all-dev bison texinfo \
ruby flex curl g++ git
ruby flex curl g++ git macutils
# Add toolchain to default PATH
ENV PATH=/Retro68-build/toolchain/bin:$PATH
@ -19,11 +19,25 @@ FROM base AS build
ADD . /Retro68
RUN mkdir /Retro68-build && \
mkdir /Retro68-build/bin && \
bash -c "cd /Retro68-build && bash /Retro68/build-toolchain.bash"
# Release image
FROM base AS release
ENV INTERFACES=multiversal
COPY --from=build \
/Retro68/interfaces-and-libraries.sh \
/Retro68/prepare-headers.sh \
/Retro68/prepare-rincludes.sh \
/Retro68/install-universal-interfaces.sh \
/Retro68/docker-entrypoint.sh \
/Retro68-build/bin/
COPY --from=build /Retro68-build/toolchain /Retro68-build/toolchain
LABEL org.opencontainers.image.source https://github.com/autc04/Retro68
CMD [ "/bin/bash" ]
ENTRYPOINT [ "/Retro68-build/bin/docker-entrypoint.sh" ]

View File

@ -192,6 +192,89 @@ package contains a very portable library, the command will of course fail. Pleas
report bugs, please report successes instead!
Using Retro68 with Docker
-------------------------
Whenever commits are merged into the Retro68 git repository, a build pipeline is triggered to
create a container image which is then pushed to the Retro68 package repository as
`ghcr.io/autc04/retro68`. This image contains the complete 68K and PPC toolchains ready for
use for either local development or as part of CI pipeline. The command line below shows an
example invocation of Retro68 to build the `Samples/Raytracer` app:
```
$ git clone --depth 1 https://github.com/autc04/Retro68.git
$ cd Retro68
$ docker run --rm -v $(pwd):/root -i ghcr.io/autc04/retro68 /bin/bash <<"EOF"
cd Samples/Raytracer
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake
make
EOF
```
The container image is configured by default to use the multiversal interfaces, but it is
possible to use the universal interfaces by passing a path to either a local file or a URL
that points to a Macbinary DiskCopy image containing the "Interfaces&Libraries" directory
from MPW.
Using the universal interfaces from a local file:
```
$ docker run --rm -v $(pwd):/root -v $(pwd)/MPW-GM.img.bin:/tmp/MPW-GM.img.bin \
-e INTERFACES=universal -e INTERFACESFILE=/tmp/MPW-GM.img.bin \
-i ghcr.io/autc04/retro68 /bin/bash <<"EOF"
cd Samples/Raytracer
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake
make
EOF
```
Using the universal interfaces from a URL:
```
$ docker run --rm -v $(pwd):/root \
-e INTERFACES=universal -e INTERFACESFILE=https://mysite.com/MPW-GM.img.bin \
-i ghcr.io/autc04/retro68 /bin/bash <<"EOF"
cd Samples/Raytracer
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake
make
EOF
```
Note that `entrypoint.sh` checks to see if the universal interfaces are installed into
`/Retro68/toolchain/universal` first before attempting to access the file or URL specified
by INTERFACESFILE. This means that it is possible to use caching or another volume so that
the universal interfaces are only processed once to speed up builds e.g.
```
$ docker run --rm -v $(pwd):/root \
-v $(pwd)/universal:/Retro68-build/toolchain/universal \
-e INTERFACES=universal -e INTERFACESFILE=https://mysite.com/MPW-GM.img.bin \
-i ghcr.io/autc04/retro68 /bin/bash <<"EOF"
cd Samples/Raytracer
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake
make
EOF
```
and then on subsequent runs:
```
$ docker run --rm -v $(pwd):/root \
-v $(pwd)/universal:/Retro68-build/toolchain/universal \
-e INTERFACES=universal \
-i ghcr.io/autc04/retro68 /bin/bash <<"EOF"
cd Samples/Raytracer
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake
make
EOF
```
Sample programs
---------------

65
docker-entrypoint.sh Executable file
View File

@ -0,0 +1,65 @@
#!/bin/bash
set -e
TMPDIR=/tmp
BUILDDIR=/Retro68-build
if [[ $INTERFACES == "universal" ]];
then
# If the universal RIncludes directory is empty, download and install the universal headers
if [ ! "$(ls -A $BUILDDIR/toolchain/universal/RIncludes 2> /dev/null)" ]; then
# If INTERFACESFILE is empty, exit
if [[ -z $INTERFACESFILE ]];
then
echo -n "Universal interfaces not present, please specify the location of a suitable "
echo "MacBinary DiskCopy image using the INTERFACESFILE environment variable."
exit 1
fi
BASEINTERFACESFILE=`basename $INTERFACESFILE`
# If INTERFACESFILE is a URL, download it first to TMPDIR. Otherwise assume the file is
# already present and copy it to TMPDIR for installation
if [[ $INTERFACESFILE == http* ]];
then
echo "Downloading Universal interfaces from MacBinary DiskCopy image $BASEINTERFACESFILE..."
curl -s $INTERFACESFILE -o $TMPDIR/$BASEINTERFACESFILE
echo "done"
else
if [[ -z $INTERFACESFILE ]];
then
echo "Unable to locate universal interfaces file $INTERFACESFILE"
exit 1
else
echo "Using Universal intefaces from MacBinary Diskcopy image $BASEINTERFACESFILE"
cp $INTERFACESFILE $TMPDIR/$BASEINTERFACESFILE
fi
fi
# Extract the file
$BUILDDIR/bin/install-universal-interfaces.sh $TMPDIR $BASEINTERFACESFILE
# Switch to universal
echo "Linking Universal interfaces..."
$BUILDDIR/bin/interfaces-and-libraries.sh $BUILDDIR/toolchain $TMPDIR/InterfacesAndLibraries
echo "done"
else
echo "Linking Universal interfaces..."
# Link to existing universal interfaces
PREFIX=$BUILDDIR/toolchain
. "$BUILDDIR/bin/interfaces-and-libraries.sh"
BUILD_68K=true
BUILD_PPC=true
unlinkInterfacesAndLibraries
linkInterfacesAndLibraries "universal"
echo "done"
fi
else
echo "Using multiversal interfaces"
fi
# Execute command
exec "$@"

101
install-universal-interfaces.sh Executable file
View File

@ -0,0 +1,101 @@
#!/bin/bash
#
# install-universal-interfaces.sh
#
# Optionally download and attempt to install the universal interfaces from
# a Macbinary disk image containing the Interfaces&Libraries directory
#
# Usage:
# install-universal-interfaces.sh <tempdir> <filename>
#
# Decompress the Macbinary image at <tempdir>/<filename> into
# <tempdir>/InterfacesAndLibraries in the correct format for
# interfaces-and-libraries.sh.
#
set -e
TMPDIR=$1
FILENAME=$2
if [[ ! -f $TMPDIR/$FILENAME ]];
then
echo "$TMPDIR/$FILENAME not found"
exit 1
fi
echo "Decompressing $FILENAME..."
ConvertDiskImage $TMPDIR/$FILENAME $TMPDIR/$FILENAME.img
echo "Decompression complete"
# Copy over Interfaces&Libraries files
echo "Copying Interfaces&Libraries files..."
hmount $TMPDIR/$FILENAME.img
# Find Interfaces&Libraries directory, get recursive directory listing
HFSINTERFACESANDLIBSDIR=`hls -R | grep 'Interfaces&Libraries:$'`
IFS="$(printf '\n')"
echo "Found Interfaces&Libraries at $HFSINTERFACESANDLIBSDIR"
FILES=`hls -FR1 $HFSINTERFACESANDLIBSDIR`
UNIXINTERFACESANDLIBSDIR=$TMPDIR/InterfacesAndLibraries
mkdir -p $UNIXINTERFACESANDLIBSDIR
# Parse results: first line is the HFS path, following lines contain one file
# per line terminated by an empty line
while IFS= read -r LINE; do
if [[ $LINE == :* ]];
then
# If it starts with : then it is a HFS path
HFSPATH=$LINE
UNIXRELPATH=$(echo "$HFSPATH" | sed "s#$HFSINTERFACESANDLIBSDIR##g" | sed "s#:#/"#g)
UNIXPATH="$UNIXINTERFACESANDLIBSDIR/$UNIXRELPATH"
# Make UNIX directory
mkdir -p $UNIXPATH
else
# If it ends with : it is a directory so ignore (we will find it during the descent)
if [[ ! $LINE == *: ]];
then
# If it isn't empty, it must be a filename
if [[ ! -z $LINE ]];
then
HFSFULLPATH="$HFSPATH$LINE"
UNIXFULLPATH="$UNIXPATH$LINE"
echo "Copying $HFSFULLPATH to $UNIXFULLPATH"
# PPC libraries need a resource fork, but the code in
# interfaces-and-libraries.sh doesn't correctly detect InterfaceLib in
# Macbinary format. Work around this for now by using Basilisk II format
# which can be parsed by ResourceFile and still allows the filename
# detection logic to work.
if [[ $HFSPATH == *SharedLibraries: ]];
then
if [[ ! -d $UNIXPATH.rsrc ]];
then
mkdir $UNIXPATH.rsrc
fi
# First copy as Macbinary
hcopy -m $HFSFULLPATH $UNIXFULLPATH.bin
# Extract data fork using normal name
bash -c "cd $UNIXPATH && macunpack -d $UNIXFULLPATH.bin && mv $UNIXFULLPATH.data $UNIXFULLPATH"
# Extract resource fork into .rsrc directory
bash -c "cd $UNIXPATH && macunpack -r $UNIXFULLPATH.bin && mv $UNIXFULLPATH.rsrc $UNIXPATH.rsrc/$LINE"
# Delete original Macbinary
rm -rf $UNIXFULLPATH.bin
else
hcopy -r $HFSFULLPATH $UNIXFULLPATH
fi
fi
fi
fi
done <<< "$FILES"
# Unmount image
humount