Глава 10. Тестирование вашего порта

Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.

10.1. Запуск make describe

Некоторые утилиты FreeBSD для сопровождения портов, например, portupgrade(1), опираются на базу данных с именем /usr/ports/INDEX, в которой отслеживаются такие характеристики портов, как их зависимости. Файл INDEX создаётся при помощи ports/Makefile верхнего уровня по команде make index, спускающейся в подкаталог каждого порта и выполняющей в нём make describe. Таким образом, если выполнение make describe с каким-либо портом завершится неудачно, то никому не удастся создать INDEX, при этом много людей вскоре станут несчастны.

Возможность генерировать этот файл очень важна вне зависимости от того, какие параметры присутствуют в make.conf, поэтому, пожалуйста, избегайте, таких вещей, как использование декларации .error, когда (к примеру) требования к зависимости не было удовлетворено. (Смотрите Избегайте использования конструкции .error.)

Если make describe выдаёт строчку, а не ошибку, то для вас это пройдёт безболезненно. Обратитесь к файлу bsd.port.mk, чтобы выяснить значение выдаваемых строк.

Также обратите внимание, что запуск актуальной версии portlint (как указано в следующем разделе) приведёт к автоматическому выполнению make describe.

10.2. Запуск make test

Даже если порт успешно собирается, рекомендуется убедиться, что программа корректно выполняет свои функции. Если исходный проект предоставляет тесты вместе с программным обеспечением, рекомендуется их запустить и проверить, что всё работает, как ожидается.

Порт может автоматически включить тесты, используя переменную TEST_TARGET. Когда эта переменная установлена, она содержит имя цели тестирования порта. Обычно это просто test, но другие варианты включают tests, check или, в специфических случаях, такие значения, как run_tests.py.

В дополнение к переменной TEST_TARGET фреймворк предоставляет следующие переменные для управления выполнением тестов:

  • TEST_WRKSRC — это каталог для выполнения тестов.

  • TEST_ENV содержит дополнительные переменные, которые передаются на этап тестирования.

  • TEST_ARGS содержит любые дополнительные аргументы, переданные на этапе тестирования.

Примеры использования этих переменных можно найти в cad/xyce, www/libjwt и других.

Убедитесь, что тесты не ломаются при обновлении порта.

10.3. Portclippy / Portfmt

Эти инструменты поставляются из пакета:ports-mgmt/portfmt[].

Portclippy — это линтер, проверяющий, расположены ли переменные в файле Makefile в правильном порядке согласно Порядку переменных в Makefile портов.

Portfmt — это инструмент для автоматического форматирования Makefile.

10.4. Portlint

Проверьте свою работу командой portlint перед тем, как её отослать или перенести в дерево портов. portlint предупреждает вас о многих распространённых ошибках, как функциональных, так и стилистических. Для нового (или скопированного внутри хранилища) порта самым подходящим является запуск portlint -A; для уже существующего порта достаточно будет запустить portlint -C.

Так как для обнаружения ошибок portlint использует эвристические методы, то им могут выдаваться и ошибочные предупреждения. Кроме того, время от времени нечто, отмечаемое как некорректность, из-за ограничений механизма создания портов не может быть сделано никак иначе. Если вы сомневаетесь, то лучше всего спросить в Список рассылки, посвящённый Портам FreeBSD.

10.5. Инструменты для работы с портами

Программа ports-mgmt/porttools входит в состав Коллекции Портов.

port является сценарием переднего плана, который может упростить вам задачу тестирования. Если вы хотите проверить новый порт или обновить существующий, то вы можете использовать port test для проверки вашего порта, включая проверку portlint. Эта команда также находит и отображает любые файлы, которые невключенные в pkg-plist. Смотрите следующий пример:

# port test /usr/ports/net/csup

10.6. PREFIX и DESTDIR

Переменная PREFIX определяет, куда будет установлен порт. По умолчанию это /usr/local, но может меняться пользователем на собственный путь, такой как /opt. В вашем порту значение этой переменной должно учитываться.

Если пользователь установил переменную DESTDIR, то она определяет полное альтернативное окружение, обычно, это jail или установленная система, смонтированная в месте, отличном от /. На самом деле порт устанавливается в DESTDIR/PREFIX и регистрируется в базе данных пакетов в DESTDIR/var/db/pkg. Поскольку управление DESTDIR производится автоматически инфраструктурой портов с помощью chroot(8), вам не нужны никакие изменения или проявление особой осторожности при написании портов, совместымых с DESTDIR.

Значение переменной PREFIX будет установлено в LOCALBASE (по умолчанию /usr/local). Если задана переменная USE_LINUX_PREFIX, то PREFIX примет значение LINUXBASE (по умолчанию /compat/linux).

Избегание явно прописываемых путей /usr/local в исходном коде сделает порт гораздо более гибким и способным удовлетворить потребности других серверов. Часто этого можно добиться простой заменой строк /usr/local в различных файлах Makefile внутри порта на ${PREFIX}. Эта переменная автоматически передаётся далее на каждом этапе построения и установки.

Проверьте, что ваше приложение не устанавливает чего-либо в каталог /usr/local вместо PREFIX. Наличие явно указанных путей можно быстро проверить следующим образом:

% make clean; make package PREFIX=/var/tmp/`make -V PORTNAME`

Если что-то было установлено за пределами PREFIX, то процесс создания пакета сообщит об отсутствии файлов.

Это также стоит проверить с использованием поддержки каталога сборки (смотрите Staging):

% make stage && make check-plist && make stage-qa && make package
  • check-plist проверяет отсутствующие в plist файлы и файлы в plist, которые не установлены портом.

  • stage-qa проверяет наличие распространённых проблем, таких как неправильный шебанг (интерпретаторная строка в первой строке скрипта), символьные ссылки, указывающие за пределы stage-директории,файлы с setuid битом и библиотеки с отладочной информацией…​

Эти тесты не обнаружат жёстко заданные пути в файлах порта, а также не проверят, что LOCALBASE используется корректно для ссылок на файлы из других портов. Временно установленный порт в /var/tmp/make -V PORTNAME должен быть протестирован на корректную работу, чтобы убедиться в отсутствии проблем с путями.

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

Обращайтесь к программам и файлам из других портов с помощью упомянутых выше переменных, а не явных путей. Например, если порт требует, чтобы макрос PAGER содержал полный путь к less, не используйте явный путь /usr/local/bin/less. Вместо этого используйте ${LOCALBASE}:

-DPAGER=\"${LOCALBASE}/bin/less\"

Путь с LOCALBASE с большей вероятностью продолжит работать, если системный администратор переместил всё дерево /usr/local в другое место.

Все эти тесты выполняются автоматически при запуске poudriere testport или poudriere bulk -t. Настоятельно рекомендуется каждому участнику разработки портов устанавливать и тестировать свои порты с помощью этого инструмента. Дополнительную информацию можно найти в poudriere.

10.7. poudriere

Для контрибьютора портов poudriere является одним из самых важных и полезных инструментов для тестирования и сборки. Его основные возможности включают:

  • Массовая сборка всего дерева портов, определенных подмножеств дерева портов или отдельного порта с его зависимостями

  • Автоматическая упаковка результатов сборки

  • Генерация файлов журнала сборки для каждого порта

  • Предоставление подписанного репозитория pkg(8)

  • Тестирование сборки портов перед отправкой патча в трекер ошибок FreeBSD или внесением изменений в дерево портов

  • Тестирование успешных сборок портов с использованием различных параметров

Поскольку poudriere выполняет сборку в чистой среде jail(8) и использует возможности zfs(8), он имеет несколько преимуществ по сравнению с традиционным тестированием на основной системе:

  • Отсутствие загрязнения основной среды: никаких оставшихся файлов, случайных удалений или изменений существующих конфигурационных файлов.

  • Проверяет pkg-plist на наличие отсутствующих или лишних записей

  • Коммиттеры портов иногда запрашивают журнал poudriere вместе с отправкой патча, чтобы оценить, готов ли патч для интеграции в дерево портов

Также его настройка и использование довольно просты, он не имеет зависимостей и будет работать в любой поддерживаемой версии FreeBSD. В этом разделе показано, как установить, настроить и запустить poudriere в рамках обычного рабочего процесса разработчика портов.

Примеры в этом разделе показывают стандартную структуру файлов, принятую в FreeBSD. Внесите соответствующие изменения, если у вас используются другие настройки. Дерево портов, обозначаемое как ${PORTSDIR}, находится в /usr/ports. По умолчанию ${LOCALBASE} и ${PREFIX} указывают на /usr/local.

10.7.1. Установка poudriere

poudriere доступен в дереве портов в пакете ports-mgmt/poudriere. Его можно установить с помощью pkg(8) или из портов:

# pkg install poudriere

или

# make -C /usr/ports/ports-mgmt/poudriere install clean

Также существует версия poudriere в разработке, которая в конечном итоге станет следующим релизом. Она доступна в пакете:ports-mgmt/poudriere-devel[]. Эта версия используется для официальных сборок пакетов FreeBSD, поэтому она хорошо протестирована. В ней часто появляются новые интересные функции. Коммиттер портов захочет использовать версию в разработке, так как именно она используется в продакшене и содержит все новые функции, которые гарантируют, что всё будет работать идеально. Контрибьютору не обязательно нужны эти функции, так как наиболее важные исправления переносятся в выпущенную версию. Основная причина использования версии в разработке для сборки официальных пакетов заключается в её скорости — она позволяет сократить время полной сборки с 18 до 17 часов при использовании высокопроизводительного сервера с 32 CPU и 128 ГБ оперативной памяти. Эти оптимизации не будут столь значимы при сборке портов на настольном компьютере.

10.7.2. Настройка poudriere

Порт устанавливает файл конфигурации по умолчанию, /usr/local/etc/poudriere.conf. Каждый параметр описан в этом файле конфигурации.

Вот минимальный пример конфигурационного файла:

ZPOOL=zroot
BASEFS=/usr/local/poudriere
DISTFILES_CACHE=/usr/ports/distfiles
RESOLV_CONF=/etc/resolv.conf
ZPOOL

Имя пула хранения ZFS, который будет использовать poudriere. Должно быть указано в выводе команды zpool status.

BASEFS

Корневая точка монтирования файловых систем poudriere. Эта запись приведет к тому, что poudriere смонтирует tank/poudriere в /poudriere.

DISTFILES_CACHE

Определяет, где хранятся distfiles. В этом примере poudriere и хост используют общий каталог для хранения distfiles. Это позволяет избежать загрузки tарболов, которые уже присутствуют в системе. Пожалуйста, создайте этот каталог, если он ещё не существует, чтобы poudriere мог его найти.

RESOLV_CONF

Используйте файл /etc/resolv.conf хоста внутри клеток для DNS. Это необходимо, чтобы клетки могли разрешать URL-адреса distfiles при загрузке. Это не требуется при использовании прокси. Обратитесь к файлу конфигурации по умолчанию для настройки прокси.

10.7.3. Создание клеток poudriere

Создайте базовые клетки, которые poudriere будет использовать для сборки:

# poudriere jail -c -j 131Ramd64 -v 13.1-RELEASE -a amd64

Загрузите 13.1-RELEASE для amd64 с FTP-сервера, указанного в FREEBSD_HOST в poudriere.conf, создайте ZFS-файловую систему tank/poudriere/jails/131Ramd64, смонтируйте её в /poudriere/jails/131Ramd64 и распакуйте тарболлы 13.1-RELEASE в эту файловую систему.

# poudriere jail -c -j 12i386 -v stable/12 -a i386 -m git+https

Создайте tank/poudriere/jails/12i386, смонтируйте его на /poudriere/jails/12i386, затем извлеките верхушку ветки Git FreeBSD-12-STABLE из GIT_HOST в poudriere.conf или по умолчанию git.freebsd.org в /poudriere/jails/12i386/usr/src, после чего выполните buildworld и установите его в /poudriere/jails/12i386.

Хотя возможно собрать более новую версию FreeBSD на старой версии, в большинстве случаев она не запустится. Например, если требуется клетка на stable/13, то хост также должен работать на stable/13. Запуск 13.1-RELEASE недостаточен.

Для создания клетки poudriere для 14.0-CURRENT:

# poudriere jail -c -j 14amd64 -v main -a amd64 -m git+https

Для запуска клетки 14.0-CURRENT poudriere хостовая система должна работать под управлением 14.0-CURRENT. В общем случае, более новые ядра могут собирать и запускать более старые клетки. Например, ядро 14.0-CURRENT может собирать и запускать клетку 12.4-STABLE, если параметр ядра COMPAT_FREEBSD12 был скомпилирован (включен по умолчанию в конфигурации ядра GENERIC 14.0-CURRENT).

Список клеток, известных poudriere, можно вывести с помощью команды poudriere jail -l:

# poudriere jail -l
JAILNAME             VERSION              ARCH    METHOD
131Ramd64            13.1-RELEASE         amd64   ftp
12i386               12.4-STABLE          i386    git+https

10.7.4. Обновление клеток poudriere

Управление обновлениями очень простое. Команда:

# poudriere jail -u -j JAILNAME

обновляет указанную клетку до последней доступной версии. Для релизов FreeBSD обновление до последнего уровня исправлений с помощью freebsd-update(8). Для версий FreeBSD, собранных из исходников, обновление до последней ревизии git в ветке.

Для клеток, использующих метод git+*, полезно добавить -J КоличествоПараллельныхСборок для ускорения сборки за счёт увеличения количества параллельных задач компиляции. Например, если на машине для сборки 6 CPU, используйте:

# poudriere jail -u -J 6 -j JAILNAME

10.7.5. Настройка деревьев портов для использования с poudriere

Существует несколько способов использования деревьев портов в poudriere. Наиболее простой способ — позволить poudriere создать для себя дерево портов по умолчанию, используя Git:

# poudriere ports -c -m git+https -B main

Эти команды создают tank/poudriere/ports/default, монтируют его в /poudriere/ports/default и заполняют с помощью Git. После этого он включается в список известных деревьев портов:

# poudriere ports -l
PORTSTREE METHOD    TIMESTAMP           PATH
default   git+https 2020-07-20 04:23:56 /poudriere/ports/default

Обратите внимание, что дерево портов "default" является особым. Каждая из команд сборки, объяснённых далее, будет неявно использовать это дерево портов, если явно не указано иное. Чтобы использовать другое дерево, добавьте -p treename к командам.

Лучший способ работы с локальными изменениями для разработчика портов — использовать Git. Как и при создании клеток, можно использовать другой метод для создания дерева портов. Чтобы добавить дополнительное дерево портов для тестирования локальных изменений и разработки портов, предпочтительно использовать клонирование дерева через git (как описано выше).

10.7.6. Использование управляемых вручную деревьев портов с помощью poudriere

В зависимости от рабочего процесса может быть крайне полезно использовать деревья портов, которые поддерживаются вручную. Например, если существует локальная копия дерева портов в /work/ports, укажите poudriere на это расположение:

# poudriere ports -c -m null -M /work/ports -p development

Это будет указано в таблице известных деревьев:

# poudriere ports -l
PORTSTREE   METHOD    TIMESTAMP           PATH
development null      2020-07-20 05:06:33 /work/ports

Тире или null в колонке METHOD означает, что poudriere никогда не будет обновлять или изменять это дерево портов. Полностью на пользователе лежит ответственность за поддержку этого дерева, включая все локальные изменения, которые могут использоваться для тестирования новых портов и отправки исправлений.

10.7.7. Обновление деревьев портов poudriere

Так же просто, как с клетками, описанными ранее:

# poudriere ports -u -p PORTSTREE

Обновит указанное PORTSTREE, дерево, указанное в выводе команды poudriere -l, до последней доступной ревизии на официальных серверах.

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

10.7.8. Тестирование портов

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

Например, локальные изменения в порте www/firefox, расположенном в /work/ports/www/firefox, можно протестировать в ранее созданной клетке 13.1-RELEASE:

# poudriere testport -j 131Ramd64 -p development -o www/firefox

Это соберет все зависимости Firefox. Если зависимость уже была собрана ранее и остается актуальной, будет установлен готовый пакет. Если для зависимости нет актуального пакета, он будет собран с параметрами по умолчанию в клетке. Затем будет собран сам Firefox.

Полная сборка каждого порта записывается в /poudriere/data/logs/bulk/131Ri386-development/build-time/logs.

Имя каталога 131Ri386-development формируется из аргументов -j и -p соответственно. Для удобства также поддерживается символическая ссылка /poudriere/data/logs/bulk/131Ri386-development/latest. Эта ссылка указывает на последний каталог времени сборки. Также в этом каталоге находится файл index.html, который позволяет наблюдать за процессом сборки через веб-браузер.

По умолчанию poudriere очищает клетки и оставляет файлы журналов в указанных выше каталогах. Для упрощения анализа клетки можно оставить запущенными после сборки, добавив -i к testport:

# poudriere testport -j 131Ramd64 -p development -i -o www/firefox

После завершения сборки, независимо от того, была ли она успешной, в клетке предоставляется оболочка. Эта оболочка используется для дальнейшего исследования. Можно указать poudriere оставить клетку запущенной после завершения сборки с помощью -I. poudriere покажет команду для выполнения, когда клетка больше не нужна. Затем можно использовать jexec(8) для входа в неё:

# poudriere testport -j 131Ramd64 -p development -I -o www/firefox
[...]
====>> Installing local Pkg repository to /usr/local/etc/pkg/repos
====>> Leaving jail 131Ramd64-development-n running, mounted at /poudriere/data/.m/131Ramd64-development/ref for interactive run testing
====>> To enter jail: jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root
====>> To stop jail: poudriere jail -k -j 131Ramd64 -p development
# jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root
# [do some stuff in the jail]
# exit
# poudriere jail -k -j 131Ramd64 -p development
====>> Umounting file systems

Неотъемлемой частью инфраструктуры сборки портов FreeBSD является возможность настройки портов под личные предпочтения с помощью опций. Их также можно тестировать с помощью poudriere. Добавление опции -c:

# poudriere testport -j 131Ramd64 -c -o www/firefox

Представляет диалог настройки порта перед его сборкой. Порты, указанные после -o в формате категория/имя_порта, будут использовать указанные опции, все зависимости будут использовать опции по умолчанию. Тестирование зависимых портов с нестандартными опциями может быть выполнено с использованием наборов, см. Использование наборов.

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

10.7.9. Использование наборов

Для всех действий, связанных со сборкой, можно указать так называемый набор с помощью -z имя_набора. Набор относится к полностью независимой сборке. Это позволяет, например, использовать testport с нестандартными параметрами для зависимых портов.

Для использования наборов poudriere ожидает, что будет использована структура каталогов, аналогичная PORT_DBDIR, по умолчанию /var/db/ports, в его конфигурационной директории. Этот каталог затем монтируется с помощью nullfs(5) в клетки, где собираются порты и их зависимости. Обычно подходящую начальную точку можно получить, рекурсивно скопировав существующий PORT_DBDIR в /usr/local/etc/poudriere.d/jailname-portname-setname-options. Это подробно описано в poudriere(8). Например, для тестирования www/firefox в определённом наборе с именем devset, добавьте параметр -z devset к команде testport:

# poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox

Это проверит наличие этих каталогов в следующем порядке:

  • /usr/local/etc/poudriere.d/131Ramd64-development-devset-options

  • /usr/local/etc/poudriere.d/131Ramd64-devset-options

  • /usr/local/etc/poudriere.d/131Ramd64-development-options

  • /usr/local/etc/poudriere.d/devset-options

  • /usr/local/etc/poudriere.d/development-options

  • /usr/local/etc/poudriere.d/131Ramd64-options

  • /usr/local/etc/poudriere.d/options

Из этого списка poudriere nullfs(5) монтирует первое существующее дерево каталогов в директорию /var/db/ports сборных клеток. Таким образом, все пользовательские настройки используются для всех портов во время этого запуска testport.

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

# poudriere options -c www/firefox -z devset

Отображается диалог настройки www/firefox, где можно редактировать параметры. Выбранные параметры сохраняются в набор devset.

poudriere очень гибок в настройке опций. poudriere можно настроить для конкретных клеток, деревьев портов и для нескольких портов одной командой. Подробности см. в poudriere(8).

10.7.10. Предоставление пользовательского файла make.conf

Подобно использованию наборов, poudriere также использует пользовательский make.conf, если он предоставлен. Для этого не требуется специального аргумента командной строки. Вместо этого poudriere ищет существующие файлы, соответствующие схеме именования, производной от командной строки. Например:

# poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox

заставляет poudriere проверять наличие этих файлов в следующем порядке:

  • /usr/local/etc/poudriere.d/make.conf

  • /usr/local/etc/poudriere.d/devset-make.conf

  • /usr/local/etc/poudriere.d/development-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-development-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-devset-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf

В отличие от наборов, все найденные файлы будут добавлены, в указанном порядке, в один make.conf внутри клеток сборки. Таким образом, можно задать общие переменные make, предназначенные для влияния на все сборки, в файле /usr/local/etc/poudriere.d/make.conf. Специальные переменные, предназначенные только для определённых клеток или наборов, можно задать в специализированных файлах make.conf, например, в /usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf.

Пример 1. Использование make.conf для изменения Perl по умолчанию

Для сборки набора с нестандартной версией Perl, например, 5.20, используя набор с именем perl5-20, создайте файл perl5-20-make.conf со следующей строкой:

DEFAULT_VERSIONS+= perl=5.20

Обратите внимание на использование +=, чтобы содержимое переменной не было перезаписано, если она уже установлена в стандартном make.conf.

10.7.11. Удаление ненужных файлов дистрибутива

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

# poudriere distclean -p portstree

будет сканировать папку файлов дистрибутива, DISTFILES_CACHE в poudriere.conf, сравнивая ее с деревом портов, указанным аргументом -p portstree, и запрашивать подтверждение на удаление этих файлов дистрибутива. Чтобы пропустить запрос и удалить все неиспользуемые файлы без подтверждения, можно добавить аргумент -y:

# poudriere distclean -p portstree -y

10.8. Отладка портов

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

  • WITH_DEBUG. Если установлено, порты собираются с отладочными символами.

  • WITH_DEBUG_PORTS. Указывает список портов, которые должны собираться с установленным WITH_DEBUG.

  • DEBUG_FLAGS. Используется для указания дополнительных флагов для CFLAGS. По умолчанию -g.

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

Эти переменные могут быть указаны в make.conf или в командной строке:

# cd category/port && make -DWITH_DEBUG DEBUG_FLAGSS="-g -O0"

Если порт собирается с использованием ports-mgmt/poudriere, отладочные переменные должны быть указаны в make.conf poudriere, а не в /etc/make.conf. Подробности см. в документации ports-mgmt/poudriere.

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


Изменено: 18 сентября 2025 г. by Vladlen Popolitov