Теряем невинность с Таненбаумом: Amsterdam Compiler Kit

от автора

Пока вы рождались, ходили в школу, заканчивали учебу и выходили на свою первую работу, на свете существовал совершенно особенный набор компиляторов, о котором крайне мало известно на просторах РФ.

Именно о нем пойдет сегодняшний рассказ.

Компиляция консольного приложения на Си из-под FreeBSD в.. MS-DOS. В 2025м году.

Компиляция консольного приложения на Си из-под FreeBSD в.. MS-DOS. В 2025м году.

Amsterdam Compiler Kit

Врядли среди читателей обнаружится аксакал живой пользователь этого удивительного проекта:

The Amsterdam Compiler Kit is a venerable piece of software that dates back to the early 1980s. It was originally written by Andrew Tanenbaum and Ceriel Jacobs as a commercial product; for many years it was also used as Minix’ native toolchain. After eventually failing as a commercial project, it was made open source under a BSD license in 2003 when it looked like it was going to be abandoned and the code lost.

Сочетание «начало 80х» и «коммерческий продукт» оставляет мало шансов на появление пользователей ACK в родных краях, поскольку в 80е еще вовсю жил СССР и вопрос покупки иностранного программного обеспечения был мягко говоря неактуальным.

Теперь подробнее, что там внутри и почему оно до сих пор шевелится представляет интерес:

The ACK contains compilers for ANSI C, K&R C, Pascal, Modula-2, Occam 1, and a primitive Basic. It contains code generators for a large number of architectures, mostly 8 and 16 bit machines; there are also a set of generic optimisation, linker and librarian tools.

В принципе стандартный набор языков для тех лет, но есть нюанс:

It contains assembler and linker support for: 6500, 6800, 6805, 6809, ARM, i80, Z80, Z8000, i86, i386, 68000, 68020, NS32016, S2650, SPARC, VAX, PDP11 and VideoCore IV.

Это уже несет определенный «вау-эффект», причем как для тех так и для этих лет, поскольку даже для популярных clang и gcc столь широкая поддержка различных архитектур решается путем форков и неофициальных патчей.

В мейнстриме и готовых пакетах столь дикого набора архитектур разумеется нет, при этом сильно устаревшие еще и регулярно ломают, а некоторые вообще удаляют.

Современная версия ACK, которая с 2003 года разрабатывается как открытый проект, поддерживает следующие платформы:

pc86, linux386, linux68k, linuxppc, linuxmips, cpm, rpi (VideoCore IV), pdpv7, msdos86 and msdos386.

Лично у меня глаз начал дергаться после cpm и pdpv7, msdos86 по сравнению с этим уже творческие мелочи.

Для юных читателей, не заставших даже дискет стоит пояснить, что CP/M это операционная система из 1970х, для примерно таких компьютеров:

Обратите внимание на ширину дисковода, это еще 3'5 дискеты, которые использовались до формата 1'44

Обратите внимание на ширину дисковода, это еще 3’5 дискеты, которые использовались до формата 1’44

Как выглядит PDP-7 уже показывал в предыдущей статье, но на всякий случай напомню:

Когда-то это называли "мини-компьютером"

Когда-то это называли «мини-компьютером»

И ACK дает вам возможность скомпилировать приложение в современном окружении в 2025м году, которое будет работать на этом.

Чтобы у вас не сложилось впечатление, будто ACK это только лишь про плешивых дедов пожилых программистов и их древние игрушки, покажу как выглядит заявленный выше VideoCore IV:

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

Minix

Отдельно стоит упомянуть историю с Minix — той самой операционной системой, созданной тем самым Таненбаумом для обучения нерадивых студентов сложной теме разработки операционных систем.

В почтовой рассылке, посвященной этой ОС когда-то давно некий Линус Торвальдс впервые представил свой известный проект, вызвавший эпический архитектурный срач дискурс, ныне являющийся историческим событием.

Дело в том, что ACK когда-то был основным системным компилятором в Minix, при этом являясь коммерческим продуктом — поставлялся в виде готовых бинарников:

The ACK has been used as the standard Minix compiler for years. While the ACK was still commercial, this was done by distributing binaries; when it get opened, a version was forked off and is now used as part of the Minix base build.

Форк с поддержкой Minix мне был не особо интересен, поэтому искать не стал, тем более что в современной Minix 3 используется вполне стандартный clang.

Однако на поддержке столь широкого набора архитектур возможности ACK не заканчиваются и чтобы добить окончательно нежную психику современных разработчиков, процитирую следующий абзац:

Each language comes with its own runtime, so if you’re a C programmer you also get a libc. Compared to gcc, it is far smaller, faster and easier to port.

Стоило догадаться об этом, прочитав список поддерживаемых архитектур и прикинув как оно вообще может работать, но тем не менее.

Так что ACK это уникальный, редкий и необычный проект, позволяющий творить запредельную дичь вроде кросс-компиляции из FreeBSD в MS-DOS подручными средствами, которую вы могли видеть в шапке статьи.

Ниже я опишу процесс сборки и использования этого необычного проекта.

Сборка

Собирать буду по традиции на FreeBSD 14, поэтому часть требуемых шагов несколько отличается от стандартных.

Проект старый, разработка в git ведется давно, поэтому внутри репозитория присутствует множество разных веток, не актуальных для обывателя.

Чтобы не выкачивать всю эту дичь, я использовал ключ --depth -1, с которым будет выгружена только ветка по-умолчанию:

git clone --depth 1 https://github.com/davidgiven/ack.git

Таким образом собирать мы будем текущую 6.0 версию:

ACK 6.0 is a ground-up reworking of the whole compiler suite, with a lot of the more archaic features removed.

Сборка проекта.. весьма своеобразна, поскольку основана на скриптах Python и немного Lua. Как гласит описание:

The version 5.0 build mechanism has been completely rewritten (twice).

И видимо это еще не конец.

Для сборки нужен достаточно банальный набор инструментов:

  • любой ANSI C компилятор (автор использовал GCC)

  • flex и yacc

  • GNU make (gmake)

  • Lua с библиотекой lua-posix

  • Python 3.4 и выше

  • ~2Гб свободного места

В трекере проекта и пул-реквестах есть сообщения от комрадов, использующих ACK на OpenBSD, так что врядли будут проблемы в куда более популярных Linux, Windows и MacOS.

Запускается сборка стандартным образом — вызовом GNU Make в корне проекта:

gmake

Поскольку автор собирал на FreeBSD, которая имеет определенную специфику в именовании инструментов, появится такая ошибка:

Происходит это из-за того, что бинарник lua во FreeBSD имеет постфикс версии:

Так что надо отредактировать Makefile в корне проекта и поменять значение переменной LUA=, добавив версию:

Следующая ошибка также специфична для FreeBSD, поскольку gcc у нас тоже с постфиксом версии:

Несмотря на документацию, которая утверждает что актуальный компилятор должен подхватываться через стандартную переменную окружения CC=, нашлось место в скриптах сборки, где были прямо забиты названия используемых бинарников:

Нужный файл называется ack/build/ab.mk и почему-то несмотря на название и расположение — не является генерируемым.

По аналогии с lua, добавляем постфикс версии и сохраняем:

После этого заново запускаем сборку и ждем, никаких других ошибок при сборке замечено не было.

Итоговый размер после завершения сборки, со всеми временными файлами получился размером в 1.7Гб, что несколько больше заявленного в требованиях:

По-умолчанию ACK устанавливается в каталог /opt/pkg/ack, поэтому запускаем из корня проекта:

mkdir -p /opt/pkg/ack gmake install

Перед установкой будут запущены тесты, но далеко не все:

Итоговый каталог bin выглядит следующим образом:

Хотя основные бинарники находятся в ack/lib/ack:

Теперь переходим к самому интересному — к запуску и работе с ACK, это будет действительно весело.

В репозитории проекта находится каталог examples, где лежат примеры более-менее сложной логики на Си, Паскале и Бейсике, которые точно собираются и работают с помощью ACK.

Один из таких примеров под названием mandelbrot.c , выводящий в консоль с помощью символа * фрактал Мандельброта вы можете лицезреть в работе на заглавной картинке к статье.

Но поскольку мне был интереснее сам процесс компиляции и запуска приложений на разных экзотических архитектурах из древних времен нежели специфика каждой конкретной платформы, не стал заморачиваться сложной логикой, взяв в качестве эталона классический «Hello world!» на Си:

#include <stdio.h>  int main(void) {   printf("Hello, alex0x08 \n");   return 0; }

И собственно ниже покажу сборку и запуск этой нестареющей классики под крайне экзотические (по современным меркам) архитектуры.

Компиляция FreeBSD->MS-DOS

Компиляцию в COM-файл с последующим запуском можно увидеть на заглавной картинке, поэтому ниже покажу компиляцию в EXE под DOS:

/opt/pkg/ack/bin/ack -mmsdos386 -O hello.c -o hello.exe

Цитируя документацию:

msdos386 produces i386 MS-DOS 32-bit DPMI .EXE files

Поэтому для работы нужен запущенный DPMI-резидент — т. н. «расширитель памяти», который можно взять например тут.

Так это выглядит в записи:

Как видите запуск осуществлялся в известном эмуляторе DOS под названием Dosbox, установленном из пакетов FreeBSD.

Компиляция для CP/M

Продолжая исторический угар, показываю сборку и запуск под CP/M, напоминаю что это операционная система из 1970х (старше автора) а компьютеры, на которых она работала выглядели так:

Kaypro II

Kaypro II

Тут надо сделать небольшое отступление и рассказать про эмулятор CP/M, поскольку его в пакетах FreeBSD не нашлось — пришлось собирать руками.

RunCPM — Z80 CP/M emulator

Разработка ведется на Github, забираем исходники:

git clone https://github.com/MockbaTheBorg/RunCPM.git

При сборке будет описанная выше проблема с номером версии в названии исполняемых файлов компилятора GCC — стандартная для FreeBSD, поэтому необходимо в файле RunCPM/Makefile.posix в переменную СС= добавить номер версии:

Сама сборка запускается командой:

gmake posix build

Но это еще не все приключения, после сборки необходимо подготовить рабочее пространство — специальный каталог из которого будет запускаться эмулятор:

mkdir disk unzip ../../DISK/A0.ZIP cp ../RunCPM .

В результате появится каталог A/0, внутри которого будут все управляющие команды CP/M, в корне будет запускаемый бинарник самого эмулятора.

Все готово к использованию, для проверки можно запустить эмулятор:

Должна быть отображена шапка с версией и работать команда DIR. Для завершения работы эмулятора введите EXIT.

Теперь можно переходить к сборке тестового приложения.

«Hello world» для CP/M

Для компиляции под эту систему достаточно указать ключ -mcpm:

 /opt/pkg/ack/bin/ack -mcpm -O hello.c -o hello.com

Следующим шагом копируем полученный бинарник, обязательно с именем в верхнем регистре:

cp ~/hello.com ./A/0/HELLO.COM

Запускаем эмулятор и вводим команду hello:

Круто?

Круто, но недостаточно, поскольку среди поддерживаемых ACK систем есть:

pdpv7         produces PDP/11 V7 Unix binaries

Думаю вы догадываетесь, что пройти мимо такого было невозможно, поэтому автор убил еще неделю показываю нечто действительно удивительное.

Компиляция для Unix v7 и PDP-11 в 2025м году (!)

Чтение этого абзаца прибавляет 100 баллов к инженерным навыкам.

Напоминаю как выглядел PDP-11:

Вот так выполняется компиляция из ACK для этого древнего монстра:

 /opt/pkg/ack/bin/ack -mpdpv7 -O hello.c -o hello

Как ни странно и неожиданно, но стандартная утилита file, присутствующая во всех UNIX-системах с незапамятных времен честно показывает тип:

Apout — Simulate PDP-11 Unix a.out binaries

Для проверки я сначала запустил полученный бинарник на этом:

This program is a user-level simulator for UNIX a.out binaries. Binaries for V1, V2, V5, V6, V7, 2.9BSD and 2.11BSD can be run with this simulator. The user-mode PDP-11 instructions are simulated, and TRAP instructions are emulated by calling equivalent native-mode system calls.

Собирается оно под FreeBSD одной командой, поскольку внешних зависимостей нет:

export CC=gcc13 gmake

После сборки в корне проекта появится бинарник apout, так выглядит в работе запуск нашего «Hello world»:

Но разумеется сильно круче было бы попробовать запустить в реальном симуляторе PDP с Unix v7 на борту, что я и сделал.

SIMH

Эмуляцию PDP как впрочем и множества других исторических систем обеспечивает известный проект Open SIMH. Нужный нам Unix v7 заявлен на главной странице проекта в качестве ключевого примера:

For example Version 7 Unix, released in 1979, runs unchanged today on SimH.

В этот раз эмулятор присутствовал в готовом виде среди пакетов FreeBSD, так что хотя-бы его не пришлось собирать из исходников.

На этот раз.

Забираем готовый образ диска с Unix v7 для PDP-11 отсюда, существует известная инструкция по полной установке с использованием образов установочной ленты:

Нормальные люди на таком слушали музыку, ненормальные - хранили бекапы.

Нормальные люди на таком слушали музыку, ненормальные — хранили бекапы.

Но автор решил не убивать еще неделю что это уже перебор, поэтому использовал готовый образ диска с Unix v7.

В архиве по ссылке будет файл unix_v7_rl.dsk , который необходимо распаковать:

mkdir v7 cd v7 unzip ~/uv7swre.zip

Дальше необходимо создать конфигурационный файл эмулятора:

set cpu u18 set cpu idle attach rl0 unix_v7_rl.dsk attach rl1 hello.tar boot rl0

Сохраните файл как simh-pdp11.ini, в том же самом каталоге v7 , куда был распакован образ диска.

Теперь надо создать tar-файл с собранным бинарником «Hello world» приложения:

cd ~ tar cvf hello.tar hello cp hello.tar ~/v7/

Итоговый набор файлов должен выглядеть как-то так:

Запускаем эмулятор:

pdp11 simh-pdp11.ini

После появления приглашения в виде символа @ вводим:

boot

Появится древний предок современного Grub, загрузчик:

Вводим:

rl(0,0)rl2unix

Появится приглашение в виде символа # , что означает запуск Unix v7 в однопользовательском режиме:

Нажмите CtrlD для начала работы в многопользовательском режиме:

Появится хорошо знакомое любому юниксоиду приглашение авторизации.

Введите root в качестве логина и пароля:

При первом запуске будет необходимо выполнить ряд дополнительных шагов.

Создаем каталог для временных файлов:

mkdir /tmp

Создаем ссылки на устройства:

cd /dev make rl

Таким образом со стороны запущенной в эмуляторе Unix v7 будет доступно устройство, эмулирующее ленту и можно будет добраться наконец до собранного на хосте бинарника:

cd /tmp tar xvf /dev/rrl1

В результате в файловой системе появится тот самый файл hello, собранный на FreeBSD с помощью ACK:

Наконец сам запуск:

Ну кто еще вам спрашивается покажет такую красоту?

Эпилог

ACK имеет отличную портируемость и расширяемость, поэтому существует столь интересный форк этого проекта:

This fork of the Amsterdam Compiler Kit supports the Cray X-MP supercomputer and the COS operating system platform.

Его тоже удалось собрать и запустить, но ввиду невероятной сложности самобытности COS, история будет уже в отдельной статье.

Следите за анонсами, как говорится.

P. S. Более вольный оригинал как обычно в нашем блоге, все желающие получить обои с автографом (и не умеющие пользоваться нейросетями) должны будут повторить все описанные в статье шаги и прислать скриншот с работающим «Hello <username>» под Unix v7 на PDP, где username — ваш ник на Хабре.


ссылка на оригинал статьи https://habr.com/ru/articles/938120/