diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..049c184901 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "multiversal"] + path = multiversal + url = https://github.com/autc04/multiversal.git diff --git a/README.md b/README.md index 48ad1c657a..f5a77afd0a 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,13 @@ Installing/Building - CMake 3.9 or later - GCC dependencies: GMP 4.2+, MPFR 2.3.1+ and MPC 0.8.0+ - bison version 3.0.2 or later -- Apple Universal Interfaces (version 3.x; version 3.4 is tested) +- ruby version 2.1 or later +- Recommended: Apple Universal Interfaces (version 3.x; version 3.4 is tested) - An ancient Mac and/or an emulator. For Ubuntu Linux, the following should help a bit: - sudo apt-get install cmake libgmp-dev libmpfr-dev libmpc-dev libboost-all-dev bison texinfo + sudo apt-get install cmake libgmp-dev libmpfr-dev libmpc-dev libboost-all-dev bison texinfo ruby On a Mac, get the homebrew package manager and: @@ -37,14 +38,16 @@ In that case, get the tigerbrew package manager and brew install gcc cmake gmp mpfr libmpc bison brew install boost --c++11 -### Apple Universal Interfaces +### Apple Universal Interfaces vs. Multiversal Interfaces -Before you can build Retro68, you need to find a copy of Apple's Universal Interfaces -and put it inside the InterfacesAndLibraries directory in the source tree. -Version 3.4 has received the most testing, but any 3.x version could theoretically -work. -The exact directory layout inside the InterfacesAndLibraries directory does -not matter. The resource forks of the files are not required. +To compile code for the Mac, you need header files and libraries describing +the APIs. There are two choices: Apple's Universal Interfaces, or the +brand-new open source reimplementation, the Multiversal Interfaces. + +The Multiversal Interfaces are included with Retro68 out of the box, and they +are free software. However, they are incomplete and may still contain serious +bugs. Missing things include Carbon, MacTCP, OpenTransport, Navigation Services, +and basically everything introduced after System 7.0. The Universal Interfaces used to be a free download from Apple. However, they have taken the site off-line and the license agreement does not allow @@ -52,17 +55,23 @@ redistribution, which is why it's not included in this repository. The concept of fair use might cover keeping it available for reasons of historical interest, or it might not. I am not a lawyer. +If you find a copy of Apple's Universal Interfaces, you can put it +inside the InterfacesAndLibraries directory in the source tree, and +Version 3.4 has received the most testing, but any 3.x version could theoretically +work. The exact directory layout inside the InterfacesAndLibraries directory does +not matter. It will be picked up automatically when Retro68 is built. + The Universal Interfaces were also included with Apple's free-to-download Macintosh Programmer's Workshop (MPW; redistribution is not officially allowed, either) and with Metrowerks CodeWarrior. One of the most easily found downloads is the MPW 3.5 Golden Master release, -usually in a file named *mpw-gm.img_.bin*. At the time of this writing, this can be -found at: +usually in a file named *MPW-GM.img.bin* or *mpw-gm.img_.bin*. At the time of +this writing, this can be found at: http://macintoshgarden.org/apps/macintosh-programmers-workshop https://www.macintoshrepository.org/1360-macintosh-programmer-s-workshop-mpw-3-0-to-3-5 - + https://staticky.com/mirrors/ftp.apple.com/developer/Tool_Chest/Core_Mac_OS_Tools/MPW_etc./MPW-GM_Images/MPW-GM.img.bin You will need a Mac or a Mac emulator (with DiscCopy) to read that file. diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..54db327cd8 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,45 @@ +trigger: +- master +jobs: + +- job: Linux + pool: + vmImage: 'ubuntu-16.04' + container: + image: 'ubuntu:18.04' + options: "--name ci-container -v /usr/bin/docker:/tmp/docker:ro" + steps: + - script: | + /tmp/docker exec -t -u 0 ci-container \ + sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install sudo" + displayName: set up sudo + - checkout: self + submodules: true + - script: | + whoami + pwd + sudo apt-get install -y \ + cmake libgmp-dev libmpfr-dev libmpc-dev \ + libboost-all-dev bison texinfo \ + ruby + displayName: 'install prerequisites' + - script: | + mkdir build + cd build + ../build-toolchain.bash --no-carbon + displayName: 'build' + +- job: macOS + pool: + vmImage: 'macOS-10.14' + steps: + - checkout: self + submodules: true + - script: | + brew install boost cmake gmp mpfr libmpc bison + displayName: 'brew prerequisites' + - script: | + mkdir build + cd build + ../build-toolchain.bash --no-carbon + displayName: build diff --git a/build-toolchain.bash b/build-toolchain.bash index 51ff1a8dc3..5c66d7d314 100755 --- a/build-toolchain.bash +++ b/build-toolchain.bash @@ -48,6 +48,8 @@ function usage() echo " --host-cxx-compiler specify C++ compiler (needed on Mac OS X 10.4)" echo " --host-c-compiler specify C compiler (needed on Mac OS X 10.4)" echo " --ninja use ninja for cmake builds" + echo " --universal use Apple's universal interfaces (default: autodetect)" + echo " --multiversal use the open-source multiversal interfaces (default: autodetect)" echo " --help show this help message" } @@ -83,6 +85,12 @@ for ARG in $*; do --ninja) CMAKE_GENERATOR=-GNinja ;; + --universal) + INTERFACES_KIND=universal + ;; + --multiversal) + INTERFACES_KIND=multiversal + ;; --help) usage exit 0 @@ -180,6 +188,12 @@ INTERFACES_DIR="$SRC/InterfacesAndLibraries" . "$SRC/interfaces-and-libraries.sh" locateAndCheckInterfacesAndLibraries +if [ ${INTERFACES_KIND} = multiversal ] && [ ${BUILD_CARBON} != false ]; then + echo + echo "Unfortunately, the Multiversal Interfaces don't yet support the Carbon API." + echo "Use either --universal or --no-carbon." + exit 1 +fi ##################### Third-Party components: binutils, gcc, hfsutils @@ -332,7 +346,11 @@ export PATH=$PREFIX/bin:$PATH ##################### Set up Interfaces & Libraries +(cd "${SRC}/multiversal" && ruby make-multiverse.rb -G CIncludes -o "${PREFIX}/multiversal") +mkdir -p "${PREFIX}/multiversal/libppc" +cp "${SRC}/ImportLibraries"/*.a "${PREFIX}/multiversal/libppc/" setUpInterfacesAndLibraries +linkInterfacesAndLibraries ${INTERFACES_KIND} ##################### Build target libraries and samples @@ -383,7 +401,21 @@ if [ $BUILD_CARBON != false ]; then fi echo +echo "===============================================================================" echo "Done building Retro68." +echo "The toolchain has been installed to: ${PREFIX}" +if [ `which Rez` != $PREFIX/bin/Rez ]; then + echo "you might want to add ${PREFIX}/bin to your PATH." +fi +case "${INTERFACES_KIND}" in + universal) + echo "Using Apple's Universal Interfaces." + ;; + multiversal) + echo "Using the open-source Multiversal Interfaces." + ;; +esac + if [ $BUILD_68K != false ]; then echo "You will find 68K sample appliations in build-target/Samples/." fi diff --git a/interfaces-and-libraries.sh b/interfaces-and-libraries.sh index 600e8d826e..ed367bb058 100755 --- a/interfaces-and-libraries.sh +++ b/interfaces-and-libraries.sh @@ -36,9 +36,23 @@ function locateInterfaceThing() function explainInterfaces() { - echo "Please get a copy of Apple's Universal Interfaces & Libraries, " - echo "version 3.x, and place it in the InterfacesAndLibraries directory inside" - echo "the Retro68 source directory." + if [ "$INTERFACES_KIND" = "multiversal" ]; then + echo "Apple's Universal Interfaces & Libraries will not be installed." + echo "Continuing with the open-source Multiversal Interfaces." + echo + return + fi + echo "===============================================================================" + if [ -z "$INTERFACES_KIND" ]; then + echo "If you want to use Apple's Universal Interfaces & Libraries " + echo "rather than the open-source Multiversal Interfaces, get a copy of" + echo "version 3.x, and place it in the InterfacesAndLibraries directory inside" + echo "the Retro68 source directory." + else + echo "Please get a copy of Apple's Universal Interfaces & Libraries, " + echo "version 3.x, and place it in the InterfacesAndLibraries directory inside" + echo "the Retro68 source directory." + fi echo echo "The exact directory layout does not matter, but there has to be" echo " - a directory with C header files (usually \"CIncludes\")" @@ -49,7 +63,17 @@ function explainInterfaces() echo echo "The Interfaces&Libraries folder from Apple's last MPW release (MPW 3.5 " echo "aka MPW GM 'Golden Master') is known to work." - exit 1 + + if [ -z "$INTERFACES_KIND" ]; then + INTERFACES_KIND=multiversal + echo + echo "Continuing with the open-source Multiversal Interfaces." + echo "===============================================================================" + echo + else + echo "===============================================================================" + exit 1 + fi } function locateAndCheckInterfacesAndLibraries() @@ -59,17 +83,19 @@ function locateAndCheckInterfacesAndLibraries() if locateInterfaceThing CONDITIONALMACROS_H ConditionalMacros.h; then CINCLUDES=`dirname "$CONDITIONALMACROS_H"` else - echo "Could not find ConditionalMacros.h anywhere inside InterfaceAndLibraries/" + echo "Could not find ConditionalMacros.h anywhere inside $INTERFACES_DIR" echo explainInterfaces + return fi if locateInterfaceThing CONDITIONALMACROS_R ConditionalMacros.r; then RINCLUDES=`dirname "$CONDITIONALMACROS_R"` else - echo "Could not find ConditionalMacros.r anywhere inside InterfaceAndLibraries/" + echo "Could not find ConditionalMacros.r anywhere inside $INTERFACES_DIR" echo explainInterfaces + return fi if [ $BUILD_68K != false ]; then @@ -79,10 +105,11 @@ function locateAndCheckInterfacesAndLibraries() elif locateInterfaceThing INTERFACELIB_68K libInterface.a; then M68KLIBRARIES=`dirname "$INTERFACELIB_68K"` else - echo "Could not find Interface.o anywhere inside InterfaceAndLibraries/" + echo "Could not find Interface.o anywhere inside $INTERFACES_DIR" echo "(This file is required for 68K support only)" echo explainInterfaces + return fi fi @@ -99,10 +126,9 @@ function locateAndCheckInterfacesAndLibraries() if locateInterfaceThing OPENTRANSPORTAPPPPC OpenTransportAppPPC.o; then PPCLIBRARIES=`dirname "$OPENTRANSPORTAPPPPC"` else - echo "Could not find OpenTransportAppPPC.o anywhere inside InterfaceAndLibraries/" + echo "Could not find OpenTransportAppPPC.o anywhere inside $INTERFACES_DIR" echo "(This file is required for OpenTransport on PPC only)" fi - fi if [ $BUILD_CARBON != false ]; then @@ -113,12 +139,14 @@ function locateAndCheckInterfacesAndLibraries() echo "This is confusing." echo explainInterfaces + return fi else - echo "Could not find Carbon.h anywhere inside InterfaceAndLibraries/" + echo "Could not find Carbon.h anywhere inside $INTERFACES_DIR" echo "(This file is required for Carbon support only)" echo explainInterfaces + return fi if locateInterfaceThing CARBONLIB CarbonLib; then carbondir=`dirname "$CARBONLIB"` @@ -127,96 +155,120 @@ function locateAndCheckInterfacesAndLibraries() echo "This is confusing." echo explainInterfaces + return fi else - echo "Could not find CarbonLib anywhere inside InterfaceAndLibraries/" + echo "Could not find CarbonLib anywhere inside $INTERFACES_DIR" echo "(This file is required for Carbon support only)" echo explainInterfaces + return fi fi + + if [ -z "$INTERFACES_KIND" ]; then + INTERFACES_KIND=universal + fi } -# remove old symlinks in $PREFIX/*-apple-macos/include/ -# and link files from $PREFIX/CIncludes -function linkHeaders() + +function linkThings() +{ + FROM="$1" + TO="$2" + PATTERN="$3" + + mkdir -p "$TO" + (cd "$TO" && find "$FROM" -name "$PATTERN" -exec ln -s {} . \;) +} + +function removeConflictingHeaders() { # On case-insensitive file systems, there will be some conflicts with # newlib. For now, universal interfaces get the right of way. - rm -f "$1/Threads.h" # thread.h: does not currently work anyways - rm -f "$1/Memory.h" # memory.h: non-standard aliasof string.h - rm -f "$1/Strings.h" # strings.h: traditional bsd string functions - - (cd "$1" && find "../../CIncludes" -name '*.h' -exec ln -s {} . \;) + rm -f "$2/Threads.h" # thread.h: does not currently work anyways + rm -f "$2/Memory.h" # memory.h: non-standard aliasof string.h + rm -f "$2/Strings.h" # strings.h: traditional bsd string functions } -function unlinkHeaders() + +function unlinkThings() { for file in "$1/"*; do - if [[ `readlink "$file"` == ../../CIncludes/* ]]; then + if [[ `readlink "$file"` == $2/* ]]; then rm "$file" fi done } -function setUpInterfacesAndLibraries() +function linkInterfacesAndLibraries() { - echo "Preparing CIncludes..." - rm -rf "$PREFIX/CIncludes" - mkdir "$PREFIX/CIncludes" - sh "$SRC/prepare-headers.sh" "$CINCLUDES" "$PREFIX/CIncludes" - - echo "Preparing RIncludes..." - mkdir -p "$PREFIX/RIncludes" - find "$PREFIX/RIncludes" ! -name 'Retro*.r' -type f -exec rm -f {} \; - sh "$SRC/prepare-rincludes.sh" "$RINCLUDES" "$PREFIX/RIncludes" - - echo "Creating Symlinks for CIncludes and RIncludes..." - + linkThings "../$1/RIncludes" "$PREFIX/RIncludes" "*.r" + if [ $BUILD_68K != false ]; then - ln -sf ../RIncludes $PREFIX/m68k-apple-macos/RIncludes - linkHeaders $PREFIX/m68k-apple-macos/include + ln -sf ../RIncludes "$PREFIX/m68k-apple-macos/RIncludes" + removeConflictingHeaders "$PREFIX/m68k-apple-macos/include" + linkThings "../../$1/CIncludes" "$PREFIX/m68k-apple-macos/include" "*.h" fi if [ $BUILD_PPC != false ]; then - ln -sf ../RIncludes $PREFIX/powerpc-apple-macos/RIncludes - linkHeaders $PREFIX/powerpc-apple-macos/include + ln -sf ../RIncludes "$PREFIX/powerpc-apple-macos/RIncludes" + linkThings "../../$1/CIncludes" "$PREFIX/powerpc-apple-macos/include" "*.h" fi - FILE_LIST="$PREFIX/apple-libraries.txt" - rm -f "$FILE_LIST" - touch "$FILE_LIST" + linkThings "../../$1/lib68k" "$PREFIX/m68k-apple-macos/lib" "*.a" + linkThings "../../$1/libppc" "$PREFIX/powerpc-apple-macos/lib" "*.a" +} + +function unlinkInterfacesAndLibraries() +{ + unlinkThings "$PREFIX/RIncludes" "../*/RIncludes" + unlinkThings "$PREFIX/m68k-apple-macos/include" "../../*/CIncludes" + unlinkThings "$PREFIX/powerpc-apple-macos/include" "../../*/CIncludes" + unlinkThings "$PREFIX/m68k-apple-macos/lib" "../../*/lib68k" + unlinkThings "$PREFIX/powerpc-apple-macos/lib" "../../*/libppc" + rm -f "$PREFIX/m68k-apple-macos/RIncludes" + rm -f "$PREFIX/powerpc-apple-macos/RIncludes" +} + +function setUpInterfacesAndLibraries() +{ + rm -rf "$PREFIX/universal" + mkdir "$PREFIX/universal" + + echo "Preparing CIncludes..." + mkdir "$PREFIX/universal/CIncludes" + sh "$SRC/prepare-headers.sh" "$CINCLUDES" "$PREFIX/universal/CIncludes" + + echo "Preparing RIncludes..." + mkdir "$PREFIX/universal/RIncludes" + sh "$SRC/prepare-rincludes.sh" "$RINCLUDES" "$PREFIX/universal/RIncludes" if [ $BUILD_68K != false ]; then echo "Converting 68K static libraries..." + mkdir -p "$PREFIX/universal/lib68k" for macobj in "${M68KLIBRARIES}/"*.o; do if [ -r "$macobj" ]; then libname=`basename "$macobj"` libname=${libname%.o} printf " %30s => %-30s\n" ${libname}.o lib${libname}.a - asm="$PREFIX/m68k-apple-macos/lib/$libname.s" - obj="$PREFIX/m68k-apple-macos/lib/$libname.o" - lib="$PREFIX/m68k-apple-macos/lib/lib${libname}.a" + asm="$PREFIX/universal/lib68k/$libname.s" + obj="$PREFIX/universal/lib68k/$libname.o" + lib="$PREFIX/universal/lib68k/lib${libname}.a" rm -f $lib if ConvertObj "$macobj" > "$asm"; then m68k-apple-macos-as "$asm" -o "$obj" m68k-apple-macos-ar cqs "$lib" "$obj" - echo "m68k-apple-macos/lib/$libname.o" >> "$FILE_LIST" - echo "m68k-apple-macos/lib/lib${libname}.a" >> "$FILE_LIST" fi rm -f "$asm" fi done - for lib in "${M68KLIBRARIES}/"lib*.a; do - libname=`basename "$lib"` - cp $lib "$PREFIX/m68k-apple-macos/lib/" - echo "m68k-apple-macos/lib/${libname}" >> "$FILE_LIST" - done fi if [ $BUILD_PPC != false ]; then + mkdir -p "$PREFIX/universal/libppc" case `ResInfo -n "$INTERFACELIB" > /dev/null || echo 0` in 0) if [ -n "$INTERFACELIB" ]; then @@ -224,7 +276,7 @@ function setUpInterfacesAndLibraries() echo " Falling back to included import libraries." fi echo "Copying readymade PowerPC import libraries..." - cp $SRC/ImportLibraries/*.a $PREFIX/powerpc-apple-macos/lib/ + cp $PREFIX/multiversal/libppc/*.a $PREFIX/universal/libppc/ ;; *) echo "Building PowerPC import libraries..." @@ -232,8 +284,7 @@ function setUpInterfacesAndLibraries() libname=`basename "$shlib"` implib=lib${libname}.a printf " %30s => %-30s\n" ${libname} ${implib} - MakeImport "$shlib" "$PREFIX/powerpc-apple-macos/lib/$implib" \ - && echo "powerpc-apple-macos/lib/$implib" >> "$FILE_LIST" + MakeImport "$shlib" "$PREFIX/universal/libppc/$implib" || true done ;; esac @@ -243,14 +294,12 @@ function setUpInterfacesAndLibraries() for obj in "${PPCLIBRARIES}/"OpenT*.o "${PPCLIBRARIES}/CarbonAccessors.o" "${PPCLIBRARIES}/CursorDevicesGlue.o"; do if [ -r "$obj" ]; then # copy the library: - cp "$obj" "$PREFIX/powerpc-apple-macos/lib/" + cp "$obj" "$PREFIX/universal/libppc/" basename=`basename "${obj%.o}"` # and wrap it in a .a archive for convenience - lib="$PREFIX"/powerpc-apple-macos/lib/lib$basename.a + lib="$PREFIX"/universal/libppc/lib$basename.a rm -f "$lib" powerpc-apple-macos-ar cqs "$lib" "$obj" - echo "powerpc-apple-macos/lib/$basename.o" >> "$FILE_LIST" - echo "powerpc-apple-macos/lib/lib$basename.a" >> "$FILE_LIST" fi done fi @@ -259,20 +308,8 @@ function setUpInterfacesAndLibraries() function removeInterfacesAndLibraries() { - FILE_LIST="$PREFIX/apple-libraries.txt" - if [ -r "$FILE_LIST" ]; then - echo "Removing currently installed Apple Interfaces and Libraries..." - for file in `cat "$FILE_LIST"`; do - rm -f "$PREFIX/$file" - done - unlinkHeaders "$PREFIX/m68k-apple-macos/include" - unlinkHeaders "$PREFIX/powerpc-apple-macos/include" - rm -f "$PREFIX/m68k-apple-macos/RIncludes" - rm -f "$PREFIX/powerpc-apple-macos/RIncludes" - rm -rf "$PREFIX/CIncludes" - find "$PREFIX/RIncludes" ! -name 'Retro*.r' -type f -exec rm -f {} \; - rm -f "$FILE_LIST" - fi + unlinkInterfacesAndLibraries + rm -rf "$PREFIX/universal" } if (return 0 2>/dev/null); then @@ -297,9 +334,19 @@ else if [ "${INTERFACES_DIR}" = "--remove" ]; then removeInterfacesAndLibraries + elif [ "${INTERFACES_DIR}" = "--unlink" ]; then + unlinkInterfacesAndLibraries + elif [ "${INTERFACES_DIR}" = "--multiversal" ]; then + unlinkInterfacesAndLibraries + linkInterfacesAndLibraries "multiversal" + elif [ "${INTERFACES_DIR}" = "--universal" ]; then + unlinkInterfacesAndLibraries + linkInterfacesAndLibraries "universal" else + INTERFACES_KIND=universal locateAndCheckInterfacesAndLibraries removeInterfacesAndLibraries setUpInterfacesAndLibraries + linkInterfacesAndLibraries "universal" fi fi diff --git a/multiversal b/multiversal new file mode 160000 index 0000000000..762bb2eb52 --- /dev/null +++ b/multiversal @@ -0,0 +1 @@ +Subproject commit 762bb2eb52be72539904da2ad22c786bd3ac24c5