Конец ноября в Питере — крайне мрачное время года, на улице лишь холод, сырость и уныние. Что определенно влияет на психику местных жителей, порождая в головах самые нездоровые желания.
Видимо по этой причине, одним мрачным осенним днем мне захотелось создать графическое приложение на современном C++ под классический Mac из 90х.

История
Честно не знаю что вам сказать, на этот раз у меня нет оправданий или логических объяснений для того что я опять сотворил.
Cпишем на влияние Питера, плохую погоду и рептилоидов с Нибиру:
рассказываю и показываю как создавать приложения на современном C++ для классического Apple Macintosh начала 90х.
Примерно такого:

The Macintosh Quadra 700 is a personal computer designed, manufactured and sold by Apple Computer from October 1991 to March 1993.
Сам я никогда не видел такие машины в живую, в годы когда они выпускались, был школотой и жил в далеких сибирских краях. Хотя даже живи я посреди Нью-Йорка в 90е — врядли бы смог позволить компьютер за почти шесть штук баксов:
The Quadra 700 originally had a list price of US$5,700
Такое и сегодня далеко не для всех.
Однако времена славы Макинтошей давно прошли, ныне все эти некогда «звездные» компьютеры — те что еще остались в рабочем состоянии, являются музейными экспонатами и предметами коллекционирования.
Поэтому, то что опишу ниже — точно не имеет никакого практического применения:
все это лишь эталонная, дистиллированная дичь, без примесей и присадок.
Это на тот случай, если вы вдруг ожидаете от статьи чего-то большего.

Все началось, когда были выкованы мегакольц.. ээ нет, это из немного другой эпической сказки.
В нашей все было проще — автор самым банальным образом набрел в сети на один интересный репозиторий, обещающий экзотическое путешествие в мир ужаса неведомые дали:
A GCC-based cross-compilation environment for 68K and PowerPC Macs. Why? Because there is no decent C++17 Compiler targeting Apple's System 6. If that's not a sufficient reason for you, I'm sure you will find something more useful elsewhere.
Разве можно было пройти мимо столь вдохновляющего описания?
Я тоже не удержался, убив в итоге несколько лишних дней на оживление и запуск этого чудовища чуда. Но прежде чем пойдем дальше, стоит рассказать читателям немного старой доброй матчасти:
почему автор так возбудился на какой-то неведомый набор консольных программ
без картинок с голыми женщинами, еще и делающий с точки зрения обывателя не пойми что.
Матчасть
Представьте, что на вашем столе лежит вот такой кусок текстолита с железом, для которого надо написать программу:

Да, на фото выше самый настоящий компьютер:
c процессором, памятью и портами ввода-вывода — все как положено.
Но только слишком слабый для развертывания полноценной среды разработки непосредственно на нем.
Поэтому если вы не маньяк-психопат LISP-разработчик — будет откровенно сложно вести какую-либо разработку на такой хне без кросс-компиляции.
Кросс-компиляция это когда на обычном офисном компьютере без отрыва от игор cобирается приложение, предназначенное для запуска на принципиально другом устройстве:
смартфоне, роутере, соковыжималке, встраиваемой платформе умного дома, коптере или еще каком боевом роботе.
Или на другой операционной системе — сборка на линуксе под Windows это тоже вполне себе кросс-компиляция.
Тулчейн для кросс-компиляции обычно устанавливается (и даже собирается) отдельно, часто бывая очень сложным. Еще он содержит компиляторы, линкеры, ассемблеры для «вражеской» архитектуры и многое другое, не менее интересное.
В некоторых случаях тулчейн включает и части целевой системы:
заголовочные файлы, ресурсы и даже готовые библиотеки для линковки.
Без которых создавать что-то сложнее «Hello, world» с помощью кросс-компиляции было бы проблематично.

Retro68
Теперь, после раскрытия матчасти можно переходить к этому замечательному проекту, чтобы оценить по достоинству масштаб проделанной работы и ее важность:
a gcc-based cross-compiler for classic 68K and PPC Macintoshes
Во-первых «gcc-based», что означает определенную совместимость с нормальными и современными компиляторами, а также отсутствие экзотических проблем, характерных для редких и/или устаревших компиляторов, вроде bcc.
Во-вторых тут две разных целевых архитектуры: 68k и PowerPC.
А значит можно собирать софт для всей линейки Маков с начала 90х и до начала 2000х — до MacOS X Tiger, последней поддерживающей архитектуру PowerPC.
Но пожалуй самое важное это поддержка трех разных UI-фреймворков на целевых системах:

Что означает возможность создавать приложения с графическим интерфейсом для всего зоопарка винтажных маков.
Типа такого:

И все это без доступа к самому физическому устройству и пыток разработкой непосредственно в эмуляторе.
Кстати процесс переноса собранного приложения (в примерах) в целевую систему также максимально упрощен:
сразу собирается готовый образ диска, который затем можно записать на носитель, либо подсунуть эмулятору.
Терминал
Когда только начинал собирать материал для этой статьи, узнал что в первых MacOS (внезапно) не было консоли и абсолютно все приложения были только и исключительно графическими:

Поэтому тот факт, что классическое консольное приложение на С:
#include <stdio.h>
int main(int argc, char** argv)
{
printf("Hello, world.\n");
printf("\n(Press Return)\n");
getchar();
return 0;
}можно собрать в графическое, с вот таким псевдо-терминалом в комплекте:

Тоже заслуга тулчейна Retro68 и интересной линковки при сборке:
LDFLAGS=-lRetroConsoleСборка на FreeBSD
Тулчейн официально поддерживает несколько популярных операционных систем:
Linux, Mac OS X or Windows (via Cygwin)
И действительно совершенно спокойно, без каких-либо проблем и нюансов собирается на линуксе.
Что мне показалось слишком скучным и унылым, поэтому
ради гусарской забавыпортировал этот проект на FreeBSD.
Всегда так делаю.
Если вам такие забавы не близки, сообщаю что для линукса достаточно по шагам выполнить инструкцию в README.
И все сразу будет хорошо, только не у вас.
Ну а мы как обычно пойдем путем хардкора — соберем весь тулчейн на FreeeBSD с нуля.
Кстати форк Retro68 с поддержкой сборки на FreeBSD выложен в отдельном репозитории.
Первым делом надо установить ряд инструментов для разработки и системных библиотек:
pkg install cmake gmp mpfr mpc boost-all bison flex texinfo rubyЗабираем исходники и поскольку репозиторий большой — выгружаем без истори�� коммитов (ключ depth):
git clone --depth 1 https://github.com/autc04/Retro68.gitВыкачиваем зависимые репозитории:
git submodule update --init
git pull
git submodule updateТеперь надо немного изменить скрипт сборки, для учета особенностей FreeBSD.
Первым делом заменяем вызовы make на gmake, поскольку FreeBSD использует свою версию утилиты make, несовместимую с GNU-версией.
Которая конечно также присутствует в пакетах, но называется
gmake.
Дальше необходимо переделать вызовы configure для вложенных проектов из скрипта сборки, суть правок:
пробросить указание на использование библиотек из каталога
/usr/local, куда устанавливаются все внешние с точки зрения системы библиотеки в FreeBSD.
Например для строки:
$SRC/binutils/configure --target=m68k-apple-macos --prefix=$PREFIX --disable-doc необходимо дописать в конец:
CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib Таким образом переменные CFLAGS и LDFLAGS будут переданы скрипту configure в качестве аргумента при вызове.
Чуть сложнее со сборкой GCC (да, мы тут собираем компилятор из исходников), строка:
$SRC/gcc/configure --target=m68k-apple-macos --prefix=$PREFIX \
--enable-languages=c,c++ --with-arch=m68k --with-cpu=m68000 \
--disable-libssp MAKEINFO=missing Тут уже нельзя использовать переменные окружения CFLAGS и LDFLAGS из-за особенностей сборки GCC и необходимо передавать пути для ключевых библиотек специальными аргументами:
--with-mpc=/usr/local --with-mpfr=/usr/local --with-gmp=/usr/local --with-isl=/usr/local --with-libiconv-prefix=/usr/local Дописав их в конец вызова configure.
Таким же образом необходимо поправить еще два места в скрипте сборки: раз и два.
После чего можно запускать сборку.
Запускается она из отдельного каталога:
mkdir ../Retro68-build
cd ../Retro68-build
../Retro68/build-toolchain.bashПосле весьма продолжительной (даже на мощном компьютере) и жутко выглядящей сборки, по накалу страстей на экране напоминающей знаменитый make buildworld из FreeBSD:

..все упадет на вот такой «страшной» ошибке:

Для исправления ситуации, надо всего лишь изменить один import в файле portable_endian.h , в этом месте:
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/endian.h>Суть проблемы в том что расположение заголовка endian.h поменялось и теперь его необходимо включать без указания каталога sys:
# include <endian.h>Исправляем импорт и перезапускаем сборку.
Через какое-то время напряженной работы, в очередной раз напугав обывателя простыней текста, сборка.. опять упадет.
Таков путь, что поделать.
На этот раз падение произойдет на стадии сборки из cmake:

Несмотря на весь внешний ужас, исправляется эта ошибка очень просто (если знать где копать разумеется):
удалением импорта этого заголовка из файла
PEFTools/MakePEF.cc
Поскольку его содержимое в последних версиях FreeBSD добавили в stdlib.
Так что смело удаляем импорт и перезапускаем сборку.
Следующее падение сборки и следующая проблема заключается в пересечении заголовков — системного, из самой FreeBSD и локального — из библиотеки libelf:

Тут к сожалению я не нашел изящного решения, достойного быть упомянутым в летописях, поэтому сделал «колхоз»:
скопировал файл
gelf.hизlibelf/includeв каталогElf2Mac, и поменял ссылки на этот заголовок из глобального на локальный.
Было:
#include <gelf.h>Стало:
#include "gelf.h"Поменять ссылки необходимо во всех файлах проекта Elf2Mac где встречается данный импорт.
Наконец последняя ошибка сборки, связанная с особенностями FreeBSD:

Связана эта ошибка с тем, что часть необходимых структур для работы с сетью на FreeBSD вынесена в отдельный заголовок.
Для исправления достаточно добавить:
#include <netinet/in.h>в файл LaunchAPPL/Client/TCP.cc
Так выглядит успешное завершение сборкиRetro68:

Готовый к использованию тулчейн будет находиться в каталоге toolchain, который стоит добавить в переменную окружения PATH.
Теперь переходим к эмулятору, поскольку живого Mac тех лет, на котором возможно запустить результат сборки у меня нет.

Эмулятор
Вообще эмуляторов винтажных Mac довольно много, поскольку маководы это сектанты очень увлеченные люди и многие из них используют и устаревшие компьютеры Apple и устаревший софт до сих пор, всячески отвергая прогресс и здравый смысл.
Такова сила бренда, созданного Стивом Джобсом.
Я буду использовать один из самых популярных и известных эмуляторов классических Macintosh:
Basilisk II is an Open Source 68k Macintosh emulator.
Разработан он был еще в начале 2000х, немецким инженером Christian Bauer, ныне активная разработка уже не ведется.
Поэтому я использовал более современный форк проекта, где решены вопросы совместимости с современным же окружением и обновлены используемые библиотеки.
И внезапно добавлен JIT (Just-In-Time Compiler).
Еще форкнутая версия немного стабильнее, с более адекватным поведением перехвата курсора.
Эмулятор использует следующие библиотеки, которые необходимо установить до попыток сборки:
pkg install sdl2 autoconf automake mpfr gmpТеперь забираем исходники:
git clone https://github.com/kanjitalk755/macemu.gitСобираем:
cd macemu/BasiliskII/src/Unix
$ ./autogen.sh
$ gmakeВ результате в текущем каталоге появится бинарник BasiliskII, которым и запускается эмулятор:

Для того чтобы запускать MacOS7 в эмуляторе, нужен загружаемый образ диска с установленной системой (или ее инсталлятор) и ROM-файл.
Образ диска можно взять например тут или тут, ROM-файл например отсюда или отсюда. Еще пара вариантов.
Еще вот тут находится крайне интересная табличка, с описанием практически каждого доступного ROM, его особенностей и работоспособности.
Напомню, что для этой статьи я эмулировал модель Quadra 600:

Для эмулятора использовался вот такой ROM-файл:

Указав в разделе «Volumes» путь к образу диска с MacOS7, затем в разделе «Memory/Misc» путь к ROM-файлу, можно наконец запускать эмулятор:

Теперь переходим к самому веселому — к разработке.
Разработка с помощью Retro68
Собственно после сборки Retro68, у вас будет все что нужно для разработки конечного софта, поскольку в каталоге build-target/Samples будут собранные примеры приложений:

Эти примеры собираются автоматически, во время сборки самого тулчейна Retro68, в качестве дополнительных тестов работоспособности.
Для сборки во всех случаях используется
cmake, исходники находятся в каталогеRetro68/Samples.
Чтобы собрать проект с HelloWorld отдельно, выполняем:
сd /opt/src/Retro68/Samples/HelloWorld
mkdir build
cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=/opt/src/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake
gmakeРезультат сборки:

Каждый пример при сборке генерирует образ диска, который можно сразу подключить к эмулятору:

Достаточно указать путь к dsk-файлу, который находится в каталоге build и запустить эмулятор:

На рабочем столе появится иконка с названием, совпадающим с названием примера:

После двойного клика по этой иконке, раскроется окно с содержимым этого виртуального диска в виде единственного запускаемого файла:

Двойной клик по файлу HelloWorld запустит наше приложение.
Примеры приложений
Как уже упоминал, в составе Retro68 есть довольно много демонстрационных приложений.
Каждый пример раскрывает аспект разработки и создан так, чтобы его можно было использовать в качестве основы для собственных проектов.
Автор тулчейна постарался, поэтому все примеры логичны, просты и понятны.
Raytracer
Retro68/Samples/Raytracer
Трассировщик лучей, реализующий генерацию псевдотрехмерной картинки в реальном времени. Собственно процесс отрисовки в этом приложении как раз показан на заглавной картинке к статье.
В проекте на самом деле присутствуют сразу две реализации, одна на С, другая на C++, видимо для сравнения во время работы.
Так выглядит финальный результат рендеринга:

Проект ценен в первую очередь как демонстрация расчетной логики и операций с числами с плавающей точкой.
Dialog
Retro68/Samples/Dialog
Демонстрация работы с модальными диалогами — как задавать размеры и расположение элементов, как создавать формы ввода, как получать вводимые данные и так далее.
В работе:

WDEF
Retro68/Samples/WDEF
Демонстрация работы с многооконными интерфейсами (MDI), создание окна с кастомным оформлением и работа с ресурсами окон.
Так это выглядит в действии:

Кратко по остальным примерам, реализующим какую-то специфическую логику.
MPWTool
Retro68/Samples/MPWTool
Реализует расширение для MPW (Macintosh Programmer's Workshop), точнее для MPWShell, с обработкой запуска оттуда и корректного возвращения в консоль.
SharedLibrary
Retro68/Samples/SharedLibrary
Реализует разделяемую библиотеку и приложение, его использующее в рантайме.
SystemExtension
Retro68/Samples/SystemExtension
Пример простейшего расширения для самой операционной системы MacOS 7, в данном случае вся видимая логика заключается в показе новой иконки при запуске ОС.
Launcher
Retro68/Samples/Launcher
Реализует запуск сторонних приложений через перетаскивание (Drag&Drop).

Настоящий хардкор
Вы же не думали, что я успокоюсь на банальной сборке тулчейна с эмулятором под FreeBSD и запуске пары тестов?
Праздник должен продолжаться:
Clapkit (CLassic APplication KIT) is a framework for developing applications for Classic Mac OS (System 7.x - Mac OS 9.x), basically a C++/object-oriented wrapper for Macintosh Toolbox functions.
Да, глаза вас не подводят, это самый настоящий современный графический фреймворк для компьютеров начала 90х.
Так это выглядит:

Так выглядит код:
#include <ckApp.h>
int main() {
CKApp* app = CKNew CKApp();
app->CKNewMsgBoxNote("Hello world!", nullptr, "OK",
nullptr, [app](int button) {
app->CKQuit();
});
// Run loop: without this, your app will quit as soon as it launches.
while (!app->CKLoop(5));
delete app;
return 0;
}Так выглядит мое тестовое приложение на современном C++, собранное с помощью cmake на FreeBSD и запущенное на MacOS 7 из 90х:

Ну что дорогие читатели, ударим шизой по осенней хандре?
MPW
Конечно ударим, но прежде стоит рассказать про нормальную разработку для продукции Apple, как это происходило у нормальных людей.
Разумеется на маках всегда была собственная среда разработки:
Macintosh Programmer's Workshop (MPW) is a software development environment for the Classic Mac OS operating system, written by Apple Computer.
Ее вполне можно использовать до сих пор, благо образов дисков в сети хватает.
Именно так я и советую поступать (т.е. использовать MPW) в случае любого более-менее серьезного проекта.
Где и когда закончатся возможности кросс-компиляции и вы опустите руки — предсказать не берусь.
Как-то так MPW выглядит в эмуляторе:

Тут находится отличная статья по созданию «Hello, world» на MPW в эмуляторе, которой вполне хватит для начала приключений.
Но в этот раз нам нужен не MPW, а только его часть — системные заголовки, которые мы будем использовать для злодейства сборки.
В Retro68, в каталоге InterfacesAndLibraries находится файл Readme.md, содержимое которого явно намекает на дальнейшие действия:
Find a copy of Apple's Universal Interfaces 3.x (preferrably 3.4) and put them here.
Вообще «Find a copy» это такой толерантный и социально приемлемый синоним старого доброго «скачать варез», прямо из 90х.
Потому как купить официально старое ПО не представляется возможным, если подобное вдруг придет в голову. Даже если компания-разработчик существует (в случае Apple), старые версии своих продуктов она так просто не продаст.
Потому что есть поддержка, гарантии и защита прав потребителей.
И репутация компании.
Поэтому сообщаю по секрету, что «найти» эти самые универсальные интерфейсы можно например тут:
wget https://henlin.net/images/Interfaces\&Libraries.zip
unzip "Interfaces&Libraries.zip" -d /opt/src/Retro68/InterfacesAndLibrariesСсылка кстати взята из другой интересной статьи, в которой автор реализует слой рендера для фреймворка Nuklear, о котором я уже внезапно писал.
Так это демо выглядит в работе, порт эмулятора на Javascript внезапно оказался встроен в статью:

Хотя этот проект успешно собрался из исходников, при попытке запуска в эмуляторе программа на базе Nuklear вылетала.
Разгадка оказалась в необходимости использовать другой эмулятор и собственно полностью другую эмулируемую систему.
Так что расскажу про связку из Nuklear, QuickDraw и Retro68 в другой раз, чтобы не раздувать эту статью до совсем уж космических размеров.
А пока для затравки, показываю эту связку в действии:

Но вернемся к фреймворку ClapKit, благо история с ним еще не закончена.

После распаковки заголовков из MPW, необходимо перезапустить сборку самого тулчейна Retro68:
cd Retro68-build
../Retro68/build-toolchain.bashИ наконец можно приступать к половым утехам с самим ClapKit.
Забираем исходники:
git clone https://github.com/macinlink/clapkit.gitСборка построена на cmake, но перед тем как собирать Clapkit, необходимо указать путь к Retro68 в скрипте сборки:
# Ensure Retro68 toolchain is set BEFORE defining project
set(CMAKE_TOOLCHAIN_FILE "/opt/src/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake")и чуть ниже:
# Define Retro68 path properly
set(RETRO68_PATH /opt/src/Retro68-build/toolchain/m68k-apple-macos)К сожалению в проекте есть небольшой баг с пропущенными заголовками, из-за которых он не собирается.
Для исправления достаточно добавить в include/ckTypes.h два импорта:
#include <Quickdraw.h>
#include <Events.h>В репозитории проекта находится готовый Showcase с демонстрацией возможностей фреймворка, на базе которого я и делал свое тестовое приложение (см. ниже).
Так выглядит сам Showcase в работе:

Выглядит заметно веселее, чем примеры из самого Retro68, согласитесь.
Тестовый образец
Я не хотел сразу пускаться во все тяжкие и портировать Doom/Quake/Cyberpunk 2077 под винтажные Маки из 90х — надо же оставить место воображению, поэтому мой тестовый образец для этой статьи это в первую очередь пример автономного, отделяемого приложения с минимальной логикой.
Которое собирается без привязки к иерархии каталогов Clapkit или Retro68.
Проект выложен в отдельном репозитории на Github.
Так мое приложение выглядит в работе на MacOS 7:

Все что оно делает:
отображает меню «Yo» в Finder, с единственным пунктом «Run me», по клику на который вызывается модальный диалог с двумя кнопками. По нажатию на «Quit» произойдет завершение работы программы.
Фигня-фигней, но только разработано и собрано оно полностью и целиком вне инфраструктуры MacOS и без средств разработки от Apple, даже без техники Apple.
На современном С++, под FreeBSD темной питерской ночью.
Так выглядит основной код на C++, файл main.cpp:
#include "main.h"
#include <ckMenu.h>
CKTestAlexs* app;
int main() {
// класс переименован ради тестов
app = CKNew CKTestAlexs();
// false - не использовать стандартные пункты меню
CKMenuBar* menuBar = CKNew CKMenuBar(false);
// добавляем свой пункт меню в Finder
CKMenu* menuTests = CKNew CKMenu("Yo");
menuBar->AddMenu(menuTests);
// затем элемент в выпадающем списке
CKMenuItem* item = CKNew CKMenuItem("Run me", 'R', [&item](CKEvent e) {
// по клику произойдет отображение стандартного
// модального диалога
app->CKNewMsgBoxNote("Welcome to old school!",
"Hello world", "Mkay", "Quit", [](int button) {
// если нажали Quit - завершить работу приложения.
if (button == 0) {
app->CKQuit();
}
});
});
// связывание элемента с пунктом меню
menuTests->AddItem(item);
// связывание меню с приложением
app->CKSetMenu(menuBar);
// бесконечный цикл ожидания для отрисовки,
// без которого приложение сразу завершится
while (!app->CKLoop(5));
delete app;
return 0;
}Класс описан в заголовке main.h, декларации методов я убрал за ненадобностью:
#include <ckApp.h>
class CKTestAlexs : public CKApp {
};Так выглядит скрипт сборки для cmake, как можно заметить тут происходит автоматическое скачивание родительского фреймворка Clapkit и наложение патча с пропущенными импортами (описаны выше):
cmake_minimum_required(VERSION 3.16)
# Ensure Retro68 toolchain is set BEFORE defining project
set(RETRO68_PATH "/opt/src/Retro68-build/toolchain/m68k-apple-macos")
set(CMAKE_TOOLCHAIN_FILE "${RETRO68_PATH}/cmake/retro68.toolchain.cmake")
project(clapkit VERSION 1.0)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Include Retro68 headers
include_directories(${RETRO68_PATH}/include)
# Set default build type to Release if not specified
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type (Debug or Release)" FORCE)
endif()
set(CLAPKIT_LOCAL_PATH "${CMAKE_SOURCE_DIR}/../../")
option(USE_LOCAL_CLAPKIT "Use local checkout of clapkit instead of fetching from Git" ON)
if(USE_LOCAL_CLAPKIT AND EXISTS "${CLAPKIT_LOCAL_PATH}/CMakeLists.txt")
message(STATUS "Using local clapkit at ${CLAPKIT_LOCAL_PATH}")
add_subdirectory(${CLAPKIT_LOCAL_PATH} clapkit)
set(USE_LOCAL_CLAPKIT ON)
else()
set(cktypes_patch git apply ${CMAKE_SOURCE_DIR}/patches/cktypes.patch)
message(STATUS "Fetching clapkit from GitHub...")
include(FetchContent)
FetchContent_Declare(
clapkit
GIT_REPOSITORY https://github.com/macinlink/clapkit.git
GIT_TAG main
PATCH_COMMAND ${cktypes_patch}
UPDATE_DISCONNECTED 1
)
FetchContent_MakeAvailable(clapkit)
set(USE_LOCAL_CLAPKIT OFF)
endif()
# Add application
add_application(CKTestAlexs
TYPE "APPL"
CREATOR "CKTS"
main.cpp
cktest.r
)
# Debug vs Release settings
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Configuring Debug Build")
target_compile_definitions(CKTestAlexs PRIVATE kCKAPPDEBUG=1)
target_compile_definitions(clapkit PRIVATE kCKAPPDEBUG=1)
set_target_properties(CKTestAlexs PROPERTIES
COMPILE_FLAGS "-O0 -Wall -g -fdata-sections -ffunction-sections"
LINK_FLAGS "-Wl,--mac-single"
)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
message(STATUS "Configuring Release Build")
target_compile_definitions(CKTestAlexs PRIVATE NDEBUG) # Disable debugging in Release
target_compile_definitions(clapkit PRIVATE NDEBUG)
set_target_properties(CKTestAlexs PROPERTIES
COMPILE_FLAGS "-s -O1 -Wall -fmerge-all-constants -fmerge-constants -fstrict-aliasing -fomit-frame-pointer -fdata-sections -ffunction-sections -finline-functions"
LINK_FLAGS "-Wl,--mac-single -Wl,--mac-strip-macsbug"
)
endif()
# Link clapkit
target_link_libraries(CKTestAlexs PRIVATE clapkit)Поскольку пути к Retro68 задаются внутри скрипта сборки, а фреймворк Clapkit автоматически скачивается из Github, сама сборка максимально упрощена:
mkdir build
cd build
cmake ..
gmakeПри успешной сборке будет создан образ диска с приложением внутри, который можно легко подцепить в эмулятор:

Продолжение банкета
Ниже несколько интересных (но все еще социально одобряемых) идей, на тему что еще можно сделать с эмулятором винтажного Macintosh.
Для начала, можно довести накал программерского угара до предела — интегрировав Retro68 с полноценным IDE и отладчиком:
Developing vintage 68K Macintosh apps with CodeLite IDE, Retro68 and pce-macplus emulator
С автодополнением из среды разработки:

С запуском собранного приложения в эмуляторе сразу из среды разработки:

И даже с удаленной отладкой через эмуляцию последовательного порта:

Есть даже отдельное видео с демонстрацией работы:
Следующая замечательная идея в моем списке это очевидная попытка использовать Rust для кросс-компиляции под старые Mac:
Building a Classic Mac OS App in Rust
Нет, автор не шутит, он действительно это сделал:
Through some luck and a little persistence I have actually managed to get Rust code running on classic Mac OS (I’ve tried Mac OS 7.5 and 8.1)
Репозиторий находится тут, проект достаточно свежий (2023 год) и вполне рабочий.
Но предупреждаю сразу, что от исходного кода может случиться сердечный приступ, если любите классический C — на это лучше не смотреть.
Так оно выглядит в работе:

Кстати приложение сетевое, так что на Rust реализована не только работа с интерфейсом, но и с TCP/IP и даже HTTP протоколом.
Для операционной системы из 1994 года.
В догонку
Напоследок и буквально «одной строкой» еще несколько интересных проектов, так или иначе использующих Retro68, которые я тоже когда‑нибудь обязательно разберу.
Как только в сутках появится 25й час.
sdl2macos9
https://github.com/laulandn/sdl2macos9
Порт знаменитой библиотеки SDL для работы на классических Mac:
Despite the name, for MacOS 7/8/9 m68k and ppc, and AmigaOS 3 m68k
peppc
https://github.com/Wack0/peppc
Форк тулчейна Retro68 для сборки приложений под.. Windows NT, причем для архитектуры PowerPC (!):
GCC 9 (Retro68) fork - compiler targeting PowerPC Windows NT (with PASM.EXE assembler and VC4.x linker)
csend
https://github.com/matthewdeaves/csend
Автор в 2025м году пилит P2P-мессенджер для работы как на обычном Linux/BSD так и на классических Mac:
CSend is a cross-platform peer-to-peer chat application written in C, supporting both modern POSIX systems and Classic Macintosh (System 7.x). It demonstrates network programming across different eras of computing, from modern multi-threaded applications to single-threaded GUI applications.
Видео с демонстрацией работы:
P.S.
За время написания этой статьи погода успела радикально поменяться и сегодня уже идет красивый зимний снежок, создавая новогоднее настроение.

Более вольный оригинал статьи как обычно в нашем блоге, форк Retro68 с поддержкой сборки на FreeBSD выложен в отдельном репозитории на Github и пока вы читаете эти строки — идет переписка с автором о включении этой логики в основную ветку.
