commit c4309b996189e5b217ddd789a0e7b85e415b43c6
parent 3884cebf5460bcd05c1fc89688a7be851508223c
Author: Anton Konyahin <me@konyahin.xyz>
Date: Fri, 19 May 2023 21:46:46 +0300
post: openbsd ports
Diffstat:
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`.