blog

Source for my blog
git clone git://git.konyahin.xyz/blog
Log | Files | Refs

commit c4309b996189e5b217ddd789a0e7b85e415b43c6
parent 3884cebf5460bcd05c1fc89688a7be851508223c
Author: Anton Konyahin <me@konyahin.xyz>
Date:   Fri, 19 May 2023 21:46:46 +0300

post: openbsd ports

Diffstat:
Acontent/blog/brogue-to-openbsd.md | 453+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 453 insertions(+), 0 deletions(-)

diff --git a/content/blog/brogue-to-openbsd.md b/content/blog/brogue-to-openbsd.md @@ -0,0 +1,453 @@ +--- +title: "Портируем brogue на OpenBSD" +date: 2023-05-19T21:31:16+03:00 +--- + +В университетские годы, практически сразу после перехода на Linux, я +от таких игр как Gothic 2, Morrowind и Fallout, перешел к новым +развлечениям: многопользовательским [текстовым +MUDам](https://www.bylins.su/) и рогаликам. Так как друзей, готовых +наслаждаться текстовыми битвами, у меня не нашлось, а я был слишком +робок чтобы влиться в коллектив уже играющих людей, то мады пришлось +забросить и остановиться на оффлайновых развлечениях. + +Перепробовав несколько разных рогаликов я прикипел душой к самому +красочному и простому из них - Brogue. Мне нравилось его изучать, +разбираться как работают те или иные механики, нравилось исследовать +этажи, ища новые свитки, оружие или хотя бы немного еды. Мне нравилось +то, как игра своей случайностью создавала для меня уникальные игровые +ситуации, из которых я так же уникально выбирался. Либо же уникально +умирал. + +Так и не пройдя её полностью, я, тем не менее, провел за игрой +какое-то количество часов и она оставила в моей памяти несколько +приятных воспоминаний. Недавно я снова вспомнил о ней и обнаружил, что +в OpenBSD игру не завезли. Я нашел [репозиторий с +кодом](https://github.com/tmewett/BrogueCE/) и убедился, что с малыми +правками она прекрасно собирается и работает на моей системе, просто +никто не оформил порт. Так почему бы не сделать это самому? + +## Готовимся к работе + +Все новые порты делаются для `current` [версии +OpenBSD](https://www.openbsd.org/faq/faq5.html#Flavors). Обновитесь +хотя бы [до снапшота](https://www.openbsd.org/faq/current.html), чтобы +ваша локальная система не сильно отличалась от той, в которую порт +будут принимать. + +Для работы над новым портом вам нужно дерево уже существующих. Обычно +его кладут в `/usr/ports`. Чтобы не собирать порты под рутом и не +класть их в домашнюю директорию - добавьте себя в группу `wsrc`. + +``` +doas user mod -G wsrc username +``` + +Теперь вам нужно определиться с тем, с какого зеркала вы будете +забирать себе изменения в дереве. Выбор достаточно большой, +ознакомьтесь со списком [вот +тут](https://www.openbsd.org/anoncvs.html). + +```sh +# замените на то, что выбрали выше +USER=anoncvs +HOST=mirror.osn.de + +cd /usr +doas mkdir -m 775 ports +doas chown root:wsrc ports/ + +# запускаем именно из /usr +cvs -qd $USER@$HOST:/cvs checkout -P ports +``` + +Чтобы сэкономить время и трафик, можно вместо выкачивания всех портов +через cvs предзагрузить текущий срез с какого-нибудь +[сервера](https://www.openbsd.org/ftp.html). Тогда скрипт для выкачки +будет выглядеть как-то так. + +```sh +# замените на то, что выбрали выше +HOST=mirror.yandex.ru + +cd /tmp +wget $HOST/pub/OpenBSD/snapshots/ports.tar.gz + +cd /usr +doas tar xzf /tmp/ports.tar.gz +doas chown -R :wsrc ports/ +doas chmod -R 775 ports/ +``` + +У снапшотов [нет .sig +файла](https://marc.info/?l=openbsd-ports&m=147586620109500&w=2), так +что придется обойтись без проверки подписи. + +Чтобы cvs знал, откуда брать обновления, после скачивания портов +выполните следующий скрипт, либо выставьте переменную окружения +`CVSROOT`, либо используйте ключ командной строки `-qd`. + +```sh +# замените на то, что выбрали выше +USER=anoncvs +HOST=mirror.osn.de + +cd /usr/ports +echo "$USER@$HOST:/cvs" > CVS/Root +``` + +Чтобы не возвращаться к этой теме потом, сразу замечу, что порты надо +держать в актуальном состоянии, периодически выкачивая себе новые +изменения. Делается этот вот так. + +```sh +cd /usr/ports +cvs -q up -Pd -A +``` + +## Куда положить и как скачать + +В `/usr/ports` много директорий, и большая часть из них - категории, +содержащие порты. Так как мы портируем игру, то тут с категориями все +просто, мы берем `games` и создаем директорию `brogue` внутри. Давайте +скопируем в неё шаблон `Makefile`, который мы будем потихоньку заполнять. + +```sh +mkdir -p /usr/ports/games/brogue +cp /usr/ports/infrastructure/templates/Makefile.template \ + /usr/ports/games/brogue/Makefile +``` + +Большая часть строк в `Makefile` закомментирована, мы заполним всё +обязательное и будем раскомментировать интересующие нас строки в +процессе работы над портом. + +```make +COMMENT = roguelike game by Brian Walker with X11 support +CATEGORIES = games + +HOMEPAGE = https://sites.google.com/site/broguegame/ + +MAINTAINER = Anton Konyahin <me@konyahin.xyz> +``` + +Хоть `DISTNAME` и `MASTER_SITES` раскомментированы с самого начала, +нам они не нужны, просто удалите эти строчки. Brogue живет на гитхабе +и для него у нас есть очень удобный набор переменных, делающих +ненужными эти две. + +Обратите внимание на то, что после знака равно стоит знак табуляции. +Это стандарт оформления, так что лучше его придерживаться. + +Давайте укажем переменные, необходимые для скачивания исходников с +github. + +```make +GH_ACCOUNT = tmewett +GH_PROJECT = BrogueCE +GH_TAGNAME = v1.12 + +PKGNAME = brogue-${GH_TAGNAME:S/v//} +``` + +Названия переменных говорят сами за себя, мы последовательно заполняем +имя аккаунта, имя проекта и тег, которым помечен последний релиз. Если +апстрим не использует теги для релизов, можно сослаться на конкретный +коммит, заполнив переменную `GH_COMMIT`. + +Здесь же мы указали имя пакета, добавив к названию игры версию из +имени тега. Команда, использованная через двоеточие, заменяет (S - +substitute) v на пустую строку, что в итоге даст нам просто `1.12`. + +Чтобы при сборке можно было проверить, что скачиваемый из интернета +архив не подменили злоумышленники, в каждом порте хранится +чексумма архива с исходниками. Давайте сохраним её и сразу же +проверим. + +```sh +make makesum +make checksum +``` + +Вы получите несколько предупреждений о том, что не всё заполнено в +нашем `Makefile`, пока игнорируйте их. В конце вывода второй команды +вы должны увидеть строку `>> (SHA256) BrogueCE-1.12.tar.gz: OK`, +сигнализирующую о том, что с архивом (и подписью) всё в порядке. + +После выполнения `make makesum` в директории с портом должен появиться +файл `distinfo`, в нем хранится SHA256 подпись архива и его размер. + +Теперь мы можем разархивировать архив командой `make extract`. Файлы +будут сложены в `/usr/ports/pobj/ИМЯ ПАКЕТА/ИМЯ АРХИВА/`. Но искать +его не нужно, просто сделайте `make show=WRKSRC`. + +Следующим важным вопросом является вопрос лицензий. Для разработчиков +важно, чтобы лицензия как на само ПО, так и на используемые им +ресурсы, позволяла опакечивание и распространение в бинарном виде. +Если лицензия этого сделать не позволяет, то пользователю придется +самому собирать приложение из портов. + +В случае с Brogue все достаточно просто: код распространяется под GNU +Affero General Public License, а все игровые ресурсы - под +Creative Commons Attribution-ShareAlike 4.0. Понять это можно +ознакомившись с двумя `LICENSE.txt` файлами, один из которых лежит в +корне проекта, а второй в `/bin/assets`. Эти лицензии позволяют +опакечивание ПО, так что укажем это в нашем `Makefile`. + +```make +# Code: AGPLv3+ +# Assets: CC BY-SA 4.0 +PERMIT_PACKAGE = Yes +``` + +## Собираем и патчим + +К счастью, Brogue для сборки использует обычный `Makefile` (хоть и +содержащий GNU расширения). Собрать проект будет просто. Сразу укажем +несколько зависимостей, проект не соберется без установленных пакетов +sdl2 и sdl2-image. + +```make +USE_GMAKE = Yes +# в рассылке посоветовали указать, так как тестов в проекте нет +NO_TEST = Yes + +# указываем, какую цель из Makefile будем собирать +ALL_TARGET = bin/brogue + +WANTLIB = c m SDL2 SDL2_image +LIB_DEPENDS = devel/sdl2 devel/sdl2-image +``` + +c это стандартная библиотека языка C, m - такая же математическая +библиотека. В `WANTLIB` мы указываем библиотеки так, как указали бы их +для линковки (`-lm -lSDL2_image`), а в `LIB_DEPENDS` пишем названия +портов с категориями, необходимых для работы программы. + +Теперь, прямо в *директории порта*, набираем `make build`. Игра +собирается и мы даже можем её запустить, набрав в директории с +исходниками `./brogue`. Однако, при сборке мы видим некоторое +количество варнингов, которые было бы неплохо исправить. + +Первым делом избавимся от предупреждения о неизвестной опции +компилятора. Для этого мы создадим копию `Makefile` с +расширением `.orig.port` и поправим оригинал. + +```sh +cd `make show=WRKSRC` +cp Makefile Makefile.orig.port + +# убираем опцию из Makefile +vi Makefile + +# возвращаемся директорию порта +cd - + +make update-patches +``` + +Последняя команда автоматически создаст патч с правильным именем, +поместит его в директорию `patches` и откроет на редактирование в +выбранном вами `$EDITOR`. Не спешите закрывать файл, хорошим тоном +считается указать в начале файла что и зачем вы редактировали. +Например вот так. + +```patch + - drop unknown warning -Wformat-overflow=0 + +Index: Makefile +--- Makefile.orig ++++ Makefile +Дальше идет текст патча... +``` + +Схожим образом можно поправить и остальные предупреждения компилятора. +Но не все они чинятся так легко. Например, Brogue использует +небезопасные функции для работы со строками в сотне мест, исправить их +все будет крайне трудозатратно и это добавит в порт огромную кучу +патчей. Так как проект старый и представляет собой всего лишь игру - я +решил их не трогать, но для чего-то более серьезного стоило бы +приложить усилия к исправлению (только не патчами в порте, а сразу в +апстриме. + +## Flavors и флаги сборки + +Если внимательно посмотреть на `Makefile` brogue, можно увидеть +несколько флагов сборки. Самым интересным из них будет `DATADIR`, +позволяющий указать, в какой директории игра будет искать свои ассеты. +По умолчанию это текущая директория, что неприемлемо для порта, ведь +исполняемый файл должен лежать в `/usr/local/bin/`, а необходимые +приложению ресурсы в `/usr/local/share/<name>`. + +```make +MAKE_FLAGS += DATADIR="${PREFIX}/share/brogue" +``` + +Второе, на что стоит обратить внимание, это возможность собрать brogue +как в графическом, так и в консольном варианте (ещё есть web версия, +но её мы оставим где лежит). Порты позволяют нам собирать несколько +вариантов пакета с помощью механизма flavors, и даже несколько +отдельных пакетов (например для утилиты, для GUI под нее и для +документации) с помощью multi packages. В данном случае нам нужен +именно flavors, который мы, аналогично пакетам со схожими вариантами, +назовем `no_x11`. + +```make +FLAVORS = no_x11 +FLAVOR ?= +``` + +Чтобы поменять флаги сборки мы будем ориентироваться на переменную +`FLAVOR`. Для сравнения её с `no_x11` мы воспользуемся модификатором +`M`, подробнее о котором, как и о упоминавшемся выше `S`, можно +почитать в `man make`. + +```make +WANTLIB = c m + +.if ${FLAVOR:Mno_x11} +WANTLIB += curses +MAKE_FLAGS += TERMINAL=YES GRAPHICS=NO +.else +WANTLIB += SDL2 SDL2_image +LIB_DEPENDS += devel/sdl2 devel/sdl2-image +.endif +``` + +Обратите внимание, что мы поменяли `WANTLIB`, оставив там только +библиотеки, общие для всех вариантов пакета, а `LIB_DEPENDS` перенесли +внутрь условия, так как консольная версия не имеет дополнительных +зависимостей. + +В начало добавим отдельное описание для варианта без поддержки иксов. + +```make +COMMENT-no_x11 = roguelike game by Brian Walker +``` + +Чтобы выполнять операции сборки и пакетирования не над основным +пакетом, а над вариацией без иксов, нам нужно будет выставить +переменную окружения. Например, вот так `env FLAVOR=no_x11 make +build`. Обратите внимание, что флейвор собирается в отдельной +директории и `WRKSRC` у неё будет другой. + +## Добавляем свои файлы в порт + +Если собрать игру сейчас и немного в неё поиграть, вы заметите что она +любит создавать самые разные файлы (сохранения, записи и т.п.) прямо в +текущей рабочей директории. Нет никакой возможности указать нужную +директорию при сборке, такое поведение зашито в код сразу в нескольких +местах. Это крайне неудобно и поначалу я пытался пропатчить все эти +места так, чтобы они использовали новый флаг сборки, введенный мною. +Но большое количество патчей это сложное и хрупкое решение. К счастью, +в рассылке мне подсказали более элегантный способ, спасибо [Omar +Polo](https://www.omarpolo.com/) за это и многие другие улучшения +моего порта. + +Мы переместим исполняемый файл игры в `/usr/local/libexec`, где лежат +все дополнительные исполняемые файлы портов, а в `/usr/local/bin` мы +положим небольшой скрипт, который определит директорию с сохранениями +для текущего пользователя, сделает её текущей и уже там запустит игру. + +Дополнительные файлы для порта должны лежать в директории `files`. +Создадим там файл `brogue` со следующим содержимым. + +```sh +#!/bin/sh + +set -e + +userdir="${XDG_DATA_HOME:-$HOME/.local/share}/Brogue" + +mkdir -p "$userdir" +cd "$userdir" +exec ${TRUEPREFIX}/libexec/brogue "$@" +``` + +## Установка и PLIST + +У brogue нет нормального установочного скрипта в `Makefile`, так что +нам придется взять эту обязанность на себя. + +```make +do-install: + ${INSTALL_PROGRAM} ${WRKBUILD}/bin/brogue ${PREFIX}/libexec/ + ${SUBST_PROGRAM} ${FILESDIR}/brogue ${PREFIX}/bin/brogue + ${INSTALL_DATA_DIR} ${PREFIX}/share/brogue/assets + ${INSTALL_DATA} ${WRKDIST}/bin/assets/tiles.png \ + ${PREFIX}/share/brogue/assets/tiles.png + ${INSTALL_DATA} ${WRKDIST}/bin/assets/tiles.bin \ + ${PREFIX}/share/brogue/assets/tiles.bin + ${INSTALL_DATA} ${WRKDIST}/bin/assets/icon.png \ + ${PREFIX}/share/brogue/assets/icon.png +``` + +Мы добавили новую цель, которая будет использоваться во время сборки +пакета, для проведение "фейковой" установки. Наберите в директории +порта `make fake`, а затем ` cd $(make show=WRKINST)`. Вы окажетесь в +директории `fake-amd64` (если вы на amd64, а не на Байкале, конечно), +в которую был установлен ваш пакет. Можете убедиться, что файлы порта +лежат именно там, где вы ожидаете, на следующем шаге именно фейковая +установка послужит основой для описания того, что где и с какими +правами должно лежать после установки на реальной системе. Больше про +фейковую установку можно [почитать +тут](https://man.openbsd.org/bsd.port.mk#THE_FAKE_FRAMEWORK). + +Вернитесь в директорию порта и наберите `make update-plist`. Когда +скрипт отработает, он сообщит вам что создал новый файл - `pkg/PLIST`. + +``` +bin/brogue +@bin libexec/brogue +share/brogue/ +share/brogue/assets/ +share/brogue/assets/icon.png +share/brogue/assets/tiles.bin +share/brogue/assets/tiles.png +``` + +В нашем случае он выглядит достаточно просто - это перечисление файлов +и директорий, с одним только `@bin` напротив исполняемого файла. Но +PLIST может больше, указывать права на файлы, группы пользователей и +даже запускать какие-то программы при установке пакета. О формате и +его возможностей [написано +здесь](https://man.openbsd.org/pkg_create.1#PACKING-LIST_DETAILS). + +Дело осталось за малым - добавьте описание пакета в файл `pkg/DESCR` и +проверьте, не забыли ли вы чего, запустив +`/usr/ports/infrastructure/bin/portcheck` и `make +port-lib-depends-check`. Если всё хорошо, то смело набирайте `make +package`, пора поставить пакет в вашу систему и хорошо всё +потестировать. + +При установке пакета `pkg_add` проверяет его подпись, но наш пакет +самособранный и подписи не имеет. К тому же, он находится не в +репозитории с остальными пакетами, а в вашем разделе с портами. Решить +обе проблемы легко. + +```sh +export PKG_PATH=/usr/ports/packages/amd64/all/ +doas pkg_add -D unsigned brogue +``` + +Если все работает хорошо и стабильно - пакет ставится и удаляется без +проблем, сохранения работают и лишние файлы нигде не появляются, +поздравляю - у вас есть ваш собственный пакет. Если вы хотите +осчастливить им мир - обратитесь в рассылку `ports@openbsd.org`. Если +на ваш порт не обращают внимания не расстраивайтесь, их поддержкой +занимаются волонтеры и им может банально не хватать времени, чтобы +уследить за всем. Я пинговал рассылку два раза, с промежутком в неделю +между каждым пингом, прежде чем смог набрать два ok, требуемых для +принятия нового пакета. + +Последнее о чем хочется упомянуть - используйте `make clean`, если +исправленная вами ошибка не уходит или происходит что-то странное. Эту +команду можно использовать с аргументами, мне очень помогал `make +clean=package` пока я разбирался со сборкой пакета. Ну а если ничего +не помогает, делайте `make clean=all`. + +Из полезных ресурсов можно упомянуть: +- подробный и практически пошаговый [гайд на офф. + сайте](https://www.openbsd.org/faq/ports/guide.html) +- man для [bsd.port.mk](https://man.openbsd.org/bsd.port.mk) +- и почтовую рассылку `ports@openbsd.org`.