Ретроспектива: Bud, DSSS и другие старые системы сборки

До появления DUB в 2012 году в сообществе D-шников не было единой системы автоматизации сборки. Все использовали что-то свое — от классического Make до кастомных скриптов. Расскажу о нескольких таких проектах, которые застал лично.

Build/Bud

Согласно deadalnix, первой известной системой сборки для D была программа Build (впоследствии переименованная в Bud), которую написал Дерек Парнелл в середине нулевых. Является ли название DUB отсылкой к этому проекту, я точно сказать не могу, но вероятность такая есть) В 2011 году Bud 3 была портирована на D2, ее даже можно скачать по ссылке ниже.

Как и все ранние системы сборки, Bud использовала собственный формат конфигов, похожий на INI-файлы. Конфигурация была до крайности громоздкой и неудобной, и альтернативы стали появляться, как грибы после дождя.

Страница Build/Bud на DSource: https://dsource.org/projects/build

D Shared Software System (DSSS)

Довольно мощный сборщик, написанный Грегором Ричардсом в качестве альтернативы Build. DSSS, строго говоря, был комплектом из сборщика Rebuild и пакетного менеджера DSSS. Для конфигурации он использовал файлы *.conf, концептуально тоже близкие к INI — наборы пар «ключ=значение». Интересной фичей DSSS была поддержка нескольких таргетов в одном конфиге: конфиг мог быть поделен на секции, каждая из которых описывала сборку отдельного таргета, ассоциированного с указанным главным модулем:

[example.d]
target=example_binary

Можно было собирать один и тот же модуль в разных конфигурациях:

[example.d+withfeature]
target=example_binary_withfeature
buildflags=-version=withfeature

Также поддерживались хуки (prebuild, postbuild, preinstall, postinstall и др.), которые впоследствии были реализованы и в DUB. Другая концепция родом из DSSS — возможность установки собранного ПО в систему, аналогично dub fetch/dub run.

DSSS был написан на D1, поэтому я его не использовал — на D1 я никогда не писал, сразу начал с D2, так как было жутко неудобно ставить обе версии языка сразу. Позже появился проект по портированию DSSS на D2, но я с какого-то момента перестал за ним следить.

Страница оригинального DSSS на DSource: https://dsource.org/projects/dsss

Форк для D2 на GitHub: https://github.com/apriori/dsss

xfBuild

Тоже проект родом из нулевых, система сборки от легендарного h3r3tic. Одно время была перспективной альтернативой DSSS, но, к сожалению, тоже исключительно под D1, да еще под Tango — поэтому подробно о ней ничего сказать не могу, я ей никогда не пользовался.

Существует порт xfBuild на D2: https://github.com/SiegeLord/xfbuild

Cook

Был период в истории D, когда все пользователи поделились на два лагеря — сторонники Bud и любители DSSS, и эта ситуация создавала серьезные сложности для мейнтейнеров публичных проектов. Затем Парнелл и Ричардс пропали из сообщества, обе системы утратили активную поддержку, и вновь наступили «темные века». Именно в это время я открыл для себя D. Отсутствие сборщика под D2 побудило меня написать сначала простой скрипт для запуска через RDMD, а потом полноценную программу под названием Cook.

Программа автоматически сканировала структуру модулей проекта и кэшировала зависимости между модулями, так что циклы пересборки были очень быстрые. В отличие от DUB, Cook следовала идее инкрементальной сборки: все D-модули компилировались в отдельные объектные файлы, и пересобирались только те модули, которые были изменены (плюс все зависящие от них, так как в D нет деления на интерфейсные файлы и файлы реализации — если изменились шаблонные сущности, то нужно пересобирать код, который их использует).

В Cook я тоже использовал собственный формат conf-файлов — JSON в те времена был еще не так популярен, да и не очень он удобен для конфигов, если честно. Cook могла работать без конфига, если проект не использует специфичные настройки тулчейна. В конфиге можно было указать пути к компилятору и линкеру, указать флаги (cflags, lflags), переопределить команды компиляции и линковки и многое другое — громадным преимуществом Cook была возможность запускать разные версии компилятора. Вот как выглядел мой типичный кроссплатформенный конфиг:

windows.compiler_dir: "C:/dlang/dmd-2.067/windows";
linux.compiler_dir: "/opt/dlang/dmd-2.067/linux";
linux.compiler: "%compiler_dir%/bin32/dmd";
linux.linker: "%compiler_dir%/bin32/dmd";
windows.compiler: "%compiler_dir%/bin/dmd";
windows.linker: "%compiler_dir%/bin/dmd";
windows.obj.path: "o_windows";
linux.obj.path: "o_linux";

Формат конфигов представлял собой, по сути, мини-DSL с поддержкой любых кастомных переменных (не такой мощный, как в CMake, но все же получше, чем INI). Для переменных поддерживались платформ-префиксы. Подобно другим старым сборщикам, Cook поддерживала мультитаргетные проекты. Еще она могла загружать зависимости из git-репозиториев и подключать к проекту зависимости, хранящиеся локально. Ее можно было даже настроить для кросс-компиляции windows-программ под Linux при помощи Wine!

Получилась до того удобная штука, что я использовал Cook аж до конца десятых, предпочитая ее DUB, и прекратил разработку лишь в 2019 году, когда уже стало ясно, что DUB теперь полноправный стандарт. Cook прекрасно работает до сих пор — можете скачать, собрать и протестировать: https://github.com/gecko0307/cook2. Есть определенные задачи, где она, имхо, подходит лучше, чем DUB — например, при сборке в экзотические целевые платформы с использованием LDC.

Не могу сказать, что я доволен DUB на 100%, есть задачи, которые он не покрывает (впрочем, как и альтернативные сборщики). Например, до сих пор нет инструментария для автоматической интеграции в проект библиотек, написанных на других языках. Но эта проблема, судя по всему, в общем случае нерешаема.

Можно ли программировать при помощи нейросетей?

Мне, как мейнтейнеру значимых OpenSource-проектов, Microsoft предоставил бесплатный доступ к Copilot. Пользуюсь им теперь регулярно, как и ChatGPT, но в зависимость, как многие, не впадаю. Могу сказать вот что. В среднем нейронки хорошо справляются с чем-то типовым — например, запросами вроде «напиши функцию-хелпер на JS, которая принимает на вход массив и делает то-то и то-то». То есть, алгоритмами, которые я бы и сам написал, но иногда тупо лень это делать. Ситуация становится резко сложнее с программами, которые должны работать с определенными интерфейсами, библиотеками, API. Чем экзотичнее библиотека, тем хуже результат. Зачастую ИИ просто не знает, как выглядит та или иная функция API, и пытается угадать. Попадает пальцем в небо очень часто, хотя концептуально его решения могут быть правильными. Бывает, что код достаточно легко подчистить от ляпов, а бывает, что он в принципе не может работать.

Абсолютно ничего не выходит, если в проекте много матана и всяких строгих теорем. В узкоспециализированных научных областях ChatGPT почти не разбирается. Также он плохо помогает в задачах оптимизации, отладки сложных систем, в вопросах архитектуры. Copilot, который вроде бы имеет доступ к полноценному контексту, тоже больше угадывает, чем реально что-то анализирует. А это и есть самое сложное в программировании — выбрать для проекта подходящую архитектуру, грамотно спроектировать модели данных, обезопаситься от побочных эффектов. Не все люди-то это умеют.

Нейронки хорошо справляются с рутинными задачами. Переписать код с одного языка на другой, переименовать множество функций по заданному шаблону, сгенерировать какие-то однотипные конструкции — все, что не требует интеллекта вообще. Но для такого они не особо нужны, это решается несложной автоматикой: текстовыми фильтрами, регулярными выражениями и т.д. Чем меньше в проекте рутины и чем больше инженерного творчества, тем сложнее заменить живого автора. Утверждение, что якобы с нейронками даже непрограммисты могут создавать полноценные продукты — это миф. Как в рассказе Роберта Шекли «Верный вопрос»: Абсолютный Ответчик помогает только тем, кто правильно формулирует вопросы — а для этого, как резюмирует писатель, нужно знать большую часть ответа.

Встроенный UI в Dagon

Наконец-то дошли руки начать пилить свой уютный UI-тулкит! Убийцу ImGui я, конечно, не планирую — это будет набор базовых виджетов для добавления в игру простых отладочных инструментов. Уже готовы окна и TextView — на скриншоте ниже демонстрируется вывод лога приложения.

Об администрировании сервера

Сегодня, в эпоху облачных провайдеров и SaaS, управлять сервером самостоятельно — крайне нишевое занятие. Для этого нужно очень хорошо разбираться в Linux и его многочисленных системных компонентах, которые, к тому же, постоянно обновляются и меняются, из-за чего знания и опыт быстро устаревают. Я много лет пользуюсь Linux, но и то не знаю всех тонкостей, постоянно учусь. Сама система принципиально несложная и понятная, но в ней постоянно появляется что-то новое, какие-то дополнительные слои абстракции. Linux многолик, его можно использовать в самых разных контекстах — отсюда и сложность. Ну и, конечно, знать систему на уровне десктопа — это одно, а админить по SSH — слегка другое.

(далее…)

C3: неужели наконец-то нормальный C-подобный язык?

Современная замена C — это то, чего очень не хватает всем, кто пишет что-то для десктопа с нуля, не полагаясь на популярнные платформы типа веба, Java/.Net, скриптовых языков и т.д. До настоящего времени реального аналога C, можно сказать, не было вовсе (исключением является BetterC-режим D, но это все-таки не отдельный язык, а подмножество, и он не для «зашедших с улицы», а совсем наоборот — для самых опытных программистов на D). Go и Rust не предлагать! 🤣

И вот, захожу я как-то раз в ньюсгруппу d.D и вижу ссылку на C3: https://c3-lang.org. «Продать» мне что-то новомодное сложно, но язык зацепил! Я тестировал еще не все фичи, но вот что понравилось практически сразу:

  • Компилятор довольно легко установить. Вначале, правда, выкачивается майкрософтовский SDK, но после этого компилятор становится самостоятельным и Студию не требует;
  • Не нужна отдельная система сборки, компилятор сам выполняет ее функции;
  • Простая и вменяемая система типов, полностью совместимая с C без костылей;
  • Векторы, матрицы и кватернионы в стандартной библиотеке — бесценно! Сразу уйма работы отпадает при написании игрового движка;
  • Вообще, в целом, читаемая и красивая стандартная либа. Открываешь любой модуль, и все понятно;
  • Управление памятью, чем-то похожее на то, что я делаю в dlib (аллокаторы, универсальный new). Сборщика мусора нет;
  • Красивая обработка ошибок со встроенным Optional и проверкой на null на уровне синтаксиса. Optional — это просто модификатор типа: если его использовать, то компилятор тупо не дает прочитать такую переменную без предварительного null-чекинга. Можно его делать самостоятельно, а можно просто использовать оператор «!!», тогда компилятор вставит проверку сам. Все выглядит очень просто и читаемо.

Конечно, многого пока не хватает — например, нет менеджера пакетов. Биндинги к некоторым популярным библиотекам есть тут, но я пока не разобрался, как они линкуются, документации по этой теме нет. Нативных библиотек, ясное дело, тоже выбор пока совсем минимальный. Еще один жирный минус — не поддерживается компиляция в bare metal, а без этого язык нельзя назвать системным, и стопроцентной заменой C он считаться, строго говоря, не может.

Обновления

Dagon 0.23.1

Небольшое обновление Dagon 0.23. Добавлена поддержка переключения отдельных рендер-таргетов в PassTerrain — то есть, для материалов ландшафта работают свойства outputColor, outputNormal и др. Движок теперь использует dlib 1.3.2. Добавлены новые уроки — 9, 13 и 15.

К следующему релизу готовлю поддержку Assimp, о которой уже писал, а также перенос расширения dagon:ftfont в ядро движка, что позволит реализовать различные встроенные UI-компоненты.

BindbC-Assimp

Биндинг к Assimp 5 размещен на GitHub и доступен в качестве DUB-пакета. К сожалению, название bindbc-assimp занято заброшенным и несуществующим ныне проектом, поэтому пришлось зарегать как bindbc-assimp5.

Оптимизация блога

Я настроил объектный кэш на основе Redis, а также добавил HTML-кэш и заголовок Cache-Control, что заметно ускорило загрузку страниц блога. Было исправлено множество мелких проблем верстки. Все архивные игры теперь размещены на одном сервере с блогом.

Тема, которую я использую, теперь также доступна на GitHub. Это форк WPEX Blogger 1.2 от WPExplorer, в котором я внес исправления для совместимости с PHP 8, исправил поиск в мобильном меню, добавил новые переводы на русский, а также внес патч, исправляющий совместимость с плагином Code Syntax Block.

Поддержка Assimp

Библиотека Assimp — относительно тяжеловесное, но самое функциональное решение для загрузки 3D-моделей. У меня наконец-то дошли руки добавить поддержку Assimp 5+ в Dagon как расширение dagon:assimp, благодаря чему можно будет использовать в движке модели форматов FBX, Collada, 3DS и многих других. Пока загружаются только меши, но в планах добавить поддержку материалов, узлов и анимации.

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

AssimpAsset aModel;

override void beforeLoad()
{
    aModel = this.addAssimpAsset("assets/cacodemon.fbx");
    aModel.loaderOption =
        aiPostProcessSteps.Triangulate | aiPostProcessSteps.FlipUVs;
}

После этого можно использовать меши из массива aModel.meshes для рендеринга:

auto e = addEntity();
e.drawable = aModel.meshes[0];

Новый блог

Я со своим блогом вынужден переехать во второй раз. К сожалению, Hostingru, на котором я уже долгое время держу большинство своих сайтов, стремительно скатился во второсортный хостинг с чуть ли не еженедельными даунтаймами. Сломанный FTP, потери данных, проблемы с доступом к cPanel — с 2019 года я повидал все. Решил перейти на нидерландский VPS с Linux, на котором у меня уже почти год как крутятся облачные сервисы, связанные с персональным брендом PixelPerfect — доволен абсолютно, никаких проблем ни разу не испытывал. В связи с этим адрес меняется на https://blog.pixperfect.online/.

Спешу заверить, что тематика блога радикально не меняется — я все так же буду писать о своем опыте разработки на D и комментировать то, что делаю на GitHub. Но PixelPerfect — это больше, чем геймдев: отныне мой блог станет универсальным домом для всех моих профессиональных интересов.

По состоянию на 30.05.25 все материалы перенесены, причем удалось даже пофиксить проблемы с битыми изображениями в самых старых постах. Дизайн остался без изменений, я только поменял плагин WordPress для просмотра изображений и пофиксил строку поиска в мобильном режиме. Также слегка изменилась структура главного меню и добавился календарь постов.

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

Новый сайт Dagon

Серьезно обновил https://gecko0307.github.io/dagon — реализован новый движок на основе рендеринга Markdown-документов, сайт переверстан в более современном дизайне, добавлены уроки, появилась отдельная страница со списком фич и скриншотами. Напомню, справка по API теперь живет на том же сайте: https://gecko0307.github.io/dagon/doc/dagon.html.

Написал новые уроки:

Также обновил урок Tutorial 11. Exporting Assets from Blender — там теперь подробности по экспорту из Blender и загрузке в Dagon моделей glTF.

Dagon 0.23.0

Обновил Dagon. Релиз не содержит нововведений и, в основном, оптимизирующий: теперь объекты Shader хранят прямые ссылки на параметры и обращаются по ним вместо строковых имен, когда записывают данные в методе bind. Индексы субрутин GLSL также извлекаются один раз при инициализации шейдера. Эта оптимизация дала весьма ощутимый прирост производительности на стороне CPU.

Удалено расширение dagon:stbi, так как стандартный загрузчик текстур Dagon полностью его заменяет. bindbc-sdl обновлен до версии 1.5.2.

К движку наконец-то появилась онлайн-документация — она доступна здесь. Документация генерируется из исходников. Полностью задокументированы пакеты dagon.core, dagon.graphics, dagon.resource, dagon.game и dagon.ui.