#include <sys/param.h>
Глава 13. Что делать нужно, и что делать нельзя
Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.
Содержание
13.1. Введение
Вот список часто встречающихся действий, которые нужно и которые нельзя делать во время процесса портирования. Проверьте порт по этому списку, и также проверьте порты в базе сообщений PR, которые присланы другими людьми. Присылайте любые комментарии о портах, которые вы проверили, так, как это описано в статье о Сообщениях об ошибках и общих замечаниях. Проверка портов в базе сообщений PR позволит нам быстрее коммиттить их и удостовериться, что вы знаете, что делаете.
13.2. WRKDIR
Не пишите ничего в файлы вне каталога WRKDIR
. Каталог WRKDIR
является единственным местом, которое гарантированно будет доступно для записи во время построения порта (обратитесь к главе об установке портов с CDROM за примером построения портов из дерева, доступного только для чтения). Если вам нужно изменить какой-либо из файлов pkg-*, сделайте это, переопределив переменную, но не перезаписывая их.
13.3. WRKDIRPREFIX
Добейтесь того, чтобы ваш порт принимал во внимание значение переменной WRKDIRPREFIX
. Большинство портов об этом не заботятся. В частности, если вы обращаетесь к каталогу WRKDIR
другого порта, заметьте, что его правильным местоположением является WRKDIRPREFIXPORTSDIR/subdir/name/work, а не PORTSDIR/subdir/work или .CURDIR/../../subdir/name/work мли что-то подобное. Кроме того, если вы сами задаете WRKDIR
, то должны поставить перед ним знак ${WRKDIRPREFIX}${.CURDIR}
.
13.4. Различение операционных систем и версий ОС
Вы можете встретиться с кодом, который требует модификаций или условной компиляции в зависимости от того, с какой версией FreeBSD Unix он работает. Предпочтительным способом отделения кода для версий FreeBSD является использование макросов __FreeBSD_version и __FreeBSD__, определённых в sys/param.h. Если этот файл не подключен, добавьте код
в нужном месте файла .c.
__FreeBSD__ определён во всех версиях FreeBSD в качестве старшего номера версии системы. Например, в FreeBSD 9.x __FreeBSD__ определён со значением 9
.
#if __FreeBSD__ >= 9 # if __FreeBSD_version >= 901000 /* 9.1+ release specific code here */ # endif #endif
Полный список значений __FreeBSD_version
доступен в Значения __FreeBSD_version.
13.5. Написание чего-либо после bsd.port.mk
Не пишите ничего после строки .include <bsd.port.mk>
. Этой строки можно избежать, включив в где-то в середину вашего файла Makefile файл bsd.port.pre.mk, и файл bsd.port.post.mk в конец.
Вам нужно включить либо пару файлов bsd.port.pre.mk/bsd.port.post.mk, либо только bsd.port.mk; не используйте оба этих метода одновременно. |
В файле bsd.port.pre.mk определяются лишь несколько переменных, которые могут быть использованы в тестах из файла Makefile, в файле bsd.port.post.mk заданы остальные.
Вот некоторые важные переменные, определенные в файле bsd.port.pre.mk (это не полный список, для выяснения полного списка прочтите, пожалуйста, сам файл bsd.port.mk).
Переменная | Описание |
---|---|
| Архитектура машины в виде, получаемом по команде |
| Тип операционной системы, получаемый по команде |
| Версия релиза операционной системы (например, |
| Версия операционной системы в виде числа, та же, что и |
| Корень дерева "local" (например, |
| Куда, собственно, устанавливается порт (обратитесь к подробной информации о |
Если вы задаете переменную |
Вот несколько примеров того, что вы можете написать после bsd.port.pre.mk:
# no need to compile lang/perl5 if perl5 is already in system .if ${OSVERSION} > 300003 BROKEN= perl is in system .endif
Вы не забываете об использовании табуляции вместо пробелов после BROKEN=
.
13.6. Использование выражения exec
в сценариях обёртках
Если порт устанавливает сценарий на языке shell, который служит для запуска другой программы, и если запуск этой программы является последним действием сценария, убедитесь, что запуск программы производится с использованием выражения exec
, например:
#!/bin/sh exec %%LOCALBASE%%/bin/java -jar %%DATADIR%%/foo.jar "$@"
Выражение exec
заменяет процесс сценария на указанную программу. Если exec
опущен, то процесс сценария во время работы программы остается в памяти, бесполезно потребляя системные ресурсы.
13.7. Поступайте разумно
Файл Makefile должен выполнять действия просто и небеспричинно. Если вы можете сделать что-то на несколько строк короче или более читабельно, сделайте это. В качестве примеров можно привести использование конструкций .if
утилиты make вместо соответствующей конструкции if
командного процессора, ненужность переопределения цели do-extract
при возможности переопределения EXTRACT*
и использование GNU_CONFIGURE
вместо CONFIGURE_ARGS += --prefix=${PREFIX}
.
Если вы обнаружите, что для выполнения чего-то приходится писать много нового кода, то, пожалуйста, просмотрите файл bsd.port.mk на предмет того, не содержит ли он решение именно вашей проблемы. Хотя его трудно читать, имеется много проблем, выглядящих сложными, для которых файл bsd.port.mk уже содержит быстрое решение.
13.8. Относитесь внимательно как к CC
, так и CXX
Порт должен принимать во внимание как переменную CC
, так и CXX
. Под этим мы подразумеваем, что порт ни в коем случае не должен устанавливать значения этих переменных, переопределяя имеющиеся значения; вместо этого можно добавлять нужные значения к уже имеющимся. Это связано с тем, что параметры построения, относящиеся ко всем портам, могут быть заданы глобально.
Если порт не учитывает значения этих переменных, добавьте строку NO_PACKAGE=ignores either cc or cxx
в файл Makefile.
Далее следует пример файла Makefile, использующего как переменную CC
, так и CXX
. Обратите внимание на использование символов ?=
:
CC?= gcc
CXX?= g++
Вот пример, в котором не принимаются во внимание ни CC
, ни CXX
:
CC= gcc
CXX= g++
В системах FreeBSD обе переменные CC
и CXX
могут быть определены в файле /etc/make.conf. В первом примере задаётся значение, если оно ранее не было определено в /etc/make.conf, что сохраняет любые определения, данные на уровне системы в целом. Второй пример переопределяет всё, что было задано ранее.
13.9. Относитесь внимательно к CFLAGS
Порт должен учитывать переменную CFLAGS
. Под этим мы подразумеваем, что порт ни в коем случае не должен устанавливать значения этой переменной, переопределяя имеющиеся значения; вместо этого можно добавлять нужные значения к уже имеющимся. Это связано с тем, что параметры построения, относящиеся ко всем портам, могут быть заданы глобально.
Если порт не учитывает значения этой переменной, добавьте строку NO_PACKAGE=ignores cflags
в файл Makefile.
Далее следует пример файла Makefile, использующего переменную CFLAGS
. Обратите внимание на использование символов +=
:
CFLAGS+= -Wall -Werror
А вот пример, в котором не учитывается значение переменной CFLAGS
:
CFLAGS= -Wall -Werror
В системе FreeBSD переменная CFLAGS
определена в файле /etc/make.conf. В первом примере к переменной CFLAGS
добавляются дополнительные флаги, при этом сохраняются все определения, данные ранее на уровне системы. Во втором примере всё, что было задано ранее, игнорируется.
Из сторонних файлов Makefile следует удалить флаги оптимизации. Общесистемные флаги оптимизации находятся в системной переменной CFLAGS
. Пример из немодифицированного Makefile:
CFLAGS= -O3 -funroll-loops -DHAVE_SOUND
При использовании системных флагов оптимизации Makefile станет похожим на следующий пример:
CFLAGS+= -DHAVE_SOUND
13.10. Подробные логи сборки
Заставьте систему сборки портов отображать все команды, выполняемые на этапе сборки. Полные логи сборки критически важны для отладки проблем с портами.
Пример неинформативного лога сборки (плохой):
CC source1.o CC source2.o CCLD someprogram
Пример подробного журнала сборки (хороший):
cc -O2 -pipe -I/usr/local/include -c -o source1.o source1.c cc -O2 -pipe -I/usr/local/include -c -o source2.o source2.c cc -o someprogram source1.o source2.o -L/usr/local/lib -lsomelib
Некоторые системы сборки, такие как CMake, ninja и GNU configure, настроены на подробное ведение журнала в рамках инфраструктуры портов. В других случаях портам могут потребоваться индивидуальные изменения.
13.11. Обратная связь
Посылайте подходящие изменения/патчи автору/сопровождающему для включения в следующий релиз. Это только сделает вашу работу гораздо легче при выходе следующего релиза.
13.12. README.html
README.html не является частью порта и генерируется при помощи make readme
. Не включайте этот файл в патчи или коммиты.
Если не удается выполнить |
13.13. Пометка неустанавливаемого порта как BROKEN
, FORBIDDEN
или IGNORE
В некоторых случаях пользователи не должны допускаться к установке порта. Для того, чтобы сообщить пользователю, что порт не следует устанавливать, имеется несколько make
-переменных, которые могут быть использованы в файле Makefile порта. Значения следующих make
-переменных будут причиной, возвращаемой пользователям, по которой порт отказывает в установке. Пожалуйста, используйте корректные make
-переменные, так как каждая переменная make передает абсолютно различный смысл как для пользователей, так и для автоматизированных систем, которые полагаются на файлы Makefile, таких как кластер построения портов, FreshPorts.
13.13.1. Переменные
BROKEN
предназначена для портов, которые в настоящее время не компилируются, не устанавливаются или не удаляются правильно. Следует использовать, когда проблема считается временной.В особых случаях кластер построения будет продолжать попытки собрать их, чтобы показать, решена ли основная проблема. (Однако, как правило, кластер запускается без этой возможности.)
В частности, используйте
BROKEN
, когда порт:не компилируется
выполняет со сбоем конфигурирование или процесс установки
устанавливает файлы вовне ${PREFIX}
не удаляет полностью все свои файлы при деинсталляции (тем не менее, это может быть допустимо, и подходит для портов, оставляющих после себя файлы, измененные пользователем)
имеет проблемы во время выполнения на системах, где он должен работать нормально.
FORBIDDEN
используется для портов, которые содержат уязвимости в информационной безопасности или являются потенциально вредными в плане обеспечения информационной безопасности системы FreeBSD при установке данного порта (например: заведомо небезопасная программа или программа, которая предоставляет легко взламываемые сервисы). Порты должны помечаться какFORBIDDEN
, как только в конкретном программном обеспечении обнаружилась уязвимость, но обновление выпущено не было. В идеальном случае порты должны обновляться максимально быстро после обнаружения уязвимости, чтобы уменьшить число уязвимых хостов FreeBSD (нам нравится иметь репутацию безопасной системы), однако иногда случается значительный временной разрыв между обнаружением уязвимости и выходом обновлённого релиза уязвимого программного обеспечения. Не помечайте порт какFORBIDDEN
, если причина не вызвана соображениями информационной безопасности.IGNORE
предназначена для портов, которые не должны строиться по какой-либо другой причине. Следует использовать для портов, в случае когда проблема считается структурной. Кластер построения ни при каких условиях не будет строить порты, помеченные какIGNORE
. В частности, используйтеIGNORE
, когда порт:не работает на установленной версии FreeBSD
имеет distfile, который не может быть автоматически загружен из-за ограничений лицензирования
не работает с некоторыми другими установленными портами (например, порт зависит от www/drupal7, но установлен www/drupal8)
Если порт будет конфликтовать с уже установленным портом (например, если они устанавливают файл в то же место, но с иным функциональным назначением), то используйте вместо этого
CONFLICTS
.CONFLICTS
сам установит значениеIGNORE
.
13.13.2. Заметки о реализации
Не заключайте значения переменных BROKEN
, IGNORE
и связанных с ними в кавычки. Из-за способа отображения информации пользователю, формулировка сообщений для каждой переменной отличается:
BROKEN= fails to link with base -lcrypto
IGNORE= unsupported on recent versions
и в результате make describe
выведен информацию в таком виде :
===> foobar-0.1 is marked as broken: fails to link with base -lcrypto.
===> foobar-0.1 is unsupported on recent versions.
13.14. Архитектурные соображения
13.14.1. Общие замечания об архитектурах
FreeBSD работает на гораздо большем количестве архитектур процессоров, чем только хорошо известные x86-совместимые. Некоторые порты имеют ограничения, характерные для одной или нескольких из этих архитектур.
Для списка поддерживаемых архитектур выполните:
cd ${SRCDIR}; make targets
Значения отображаются в форме TARGET
/TARGET_ARCH
. Переменная только для чтения ARCH
в ports устанавливается на основе значения TARGET_ARCH
. Makefile в портах должны проверять значение этой переменной.
13.14.2. Пометка порта как архитектурно нейтрального
Порты, которые не имеют зависимых от архитектуры файлов или требований, определяются установкой NO_ARCH=yes
.
Пакеты, собранные из таких портов, имеют строку архитектуры, оканчивающуюся на :*
(архитектура с подстановочным символом), в отличие от, например, freebsd:13:x86:64
(архитектура amd64).
|
13.14.3. Пометка порта как игнорируемого только на определенных архитектурах
Чтобы пометить порт как
IGNORE
только для определенных архитектур, существуют две другие удобные переменные, которые автоматически устанавливаютIGNORE
:ONLY_FOR_ARCHS
иNOT_FOR_ARCHS
. Примеры:ONLY_FOR_ARCHS= i386 amd64
NOT_FOR_ARCHS= ia64 sparc64
Пользовательское сообщение
IGNORE
можно задать с помощьюONLY_FOR_ARCHS_REASON
иNOT_FOR_ARCHS_REASON
. Для отдельных архитектур возможны записи сONLY_FOR_ARCHS_REASON_ARCH
иNOT_FOR_ARCHS_REASON_ARCH
.
Если порт загружает и устанавливает бинарные файлы i386, установите
IA32_BINARY_PORT
. Если эта переменная задана, /usr/lib32 должен присутствовать для IA32-версий библиотек, а ядро должно поддерживать совместимость с IA32. Если одно из этих двух условий не выполняется,IGNORE
будет установлен автоматически.
13.14.4. Специфические аспекты для кластеров
Некоторые порты пытаются оптимизировать себя под конкретную машину, на которой они собираются, указывая компилятору
-march=native
. Этого следует избегать: либо добавить этот параметр в опцию, отключенную по умолчанию, либо удалить его полностью.В противном случае стандартный пакет, созданный кластером сборки, может не запускаться на каждой машине с данной
ARCH
.
13.15. Пометка порта на удаление с DEPRECATED
или EXPIRATION_DATE
Помните, что BROKEN
и FORBIDDEN
будут использованы как временное средство, если порт не является работающим. Постоянно неработоспособные порты должны полностью удаляться из дерева.
В подходящих ситуациях пользователи могут быть оповещены о предстоящем удалении через переменные DEPRECATED
и EXPIRATION_DATE
. Первое - это просто строка, сообщающая причину запланированного удаления порта; вторая является строкой в формате ISO 8601 (YYYY-MM-DD). Обе будут показаны пользователю.
Переменную DEPRECATED
можно установить без использования EXPIRATION_DATE
(в частности, при рекомендации новой версии порта), но обратный порядок не имеет никакого смысла.
При пометке порта как |
Не существует установленного правила о том, насколько заранее нужно уведомлять. Текущая практика предполагает один месяц для проблем, связанных с безопасностью, и два месяца для проблем сборки. Это также дает заинтересованным коммиттерам немного времени на исправление проблем.
13.16. Избегайте использования конструкции .error
Правильным способом подать сигнал для Makefile о том, что порт не может быть установлен из-за какого-то внешнего фактора (например, пользователь указал недопустимую комбинацию опций построения), является установка непустого значения для IGNORE
. Это значение будет сформатировано и показано пользователю во время make install
.
Использование для этих целей .error
является распространенной ошибкой. Проблема в том, что в этой ситуации будут повреждены многие инструменты автоматизации, работающие с деревом портов. Наибольшим образом это распространено при попытке построить /usr/ports/INDEX (смотрите Запуск make describe
). Тем не менее, даже более простые команды, такие как make maintainer
, в этом случае также вернут ошибку. Это не является приемлемым.
.error
Из следующих двух вариантов строки файла Makefile первый приведёт к неудачному завершению работы make index
, а второй - нет:
.error "option is not supported"
IGNORE=option is not supported
13.17. Использование sysctl
Использование sysctl не рекомендуется, кроме как при выполнении целей. Это вызвано тем, что вычисление любых makevar
, таких как во время команды make index
, с необходимостью запуска этой команды, еще больше замедляет весь процесс.
sysctl(8) следует всегда использовать через переменную SYSCTL
, поскольку она содержит полностью заданный путь, и при необходимости может быть переопределена.
13.18. Меняющиеся дистрибутивные файлы
Иногда авторы программного обеспечения изменяют содержимое выпущенных дистрибутивных файлов, не меняя их названия. Убедитесь, что изменения официальны и были выполнены автором. В прошлом случалось, что дистрибутивный файл тихо изменялся на серверах загрузки с целью нанесения вреда или компрометации безопасности конечного пользователя.
Отложите старый distfile в сторону, загрузите новый, распакуйте их и сравните содержимое с помощью diff(1). Если ничего подозрительного нет, обновите distinfo.
Убедитесь, что вы выделили основные различия в PR и журнале коммитов, чтобы другие люди знали, что ничего плохого не произошло. |
Связжитесь с автором этого программного обеспечения для подтверждения изменений.
13.19. Используйте стандарты POSIX
В большинстве случаев порты FreeBSD ожидают соответствия стандарту POSIX. Некоторые программы и системы сборки делают предположения, основанные на конкретной операционной системе или окружении, что может вызывать проблемы при использовании в порте.
Не используйте /proc, если есть другие способы получить информацию. Например, setprogname(argv[0])
в main()
, а затем getprogname(3) для получения имени исполняемого файла.
Не полагайтесь на поведение, не документированное в POSIX.
Не записывайте метки времени в критическом пути приложения, если оно работает и без них. Получение меток времени может быть медленным в зависимости от точности меток времени в ОС. Если метки времени действительно необходимы, определите, насколько точными они должны быть, и используйте API, которое, согласно документации, предоставляет только необходимую точность.
Ряд простых системных вызовов (например, gettimeofday(2), getpid(2)) работают намного быстрее в Linux® по сравнению с любой другой операционной системой из-за кэширования и используемой оптимизации vsyscall. Не полагайтесь на их дешевизну в критичных к производительности приложениях. В целом, старайтесь избегать системных вызовов там, где это возможно.
Не полагайтесь на специфичное для Linux® поведение сокета. В частности, отличаются размеры буфера сокета по умолчанию (выполните вызов setsockopt(2) с SO_SNDBUF
и SO_RCVBUF
, и в то время как в Linux® при заполнении буфера сокета send(2) блокируется, FreeBSD возвращает ошибку и устанавливает ENOBUFS
в качестве значения errno.
Если требуется рассчитывать на нестандартное поведение, инкапсулируйте это должным образом в общий для всех API с проверкой поведения на этапе конфигурации, и если требуемое поведение не найдено, прекращайте выполнение.
Используйте страницы справочника для проверки, относится ли функция к интерфейсу POSIX (ищите раздел "STANDARDS" на странице справочника).
Не рассчитывайте на то, что в качестве /bin/sh используется bash. Убедитесь, что командная строка, переданная в system(3), будет работать в POSIX-совместимой оболочке.
Список основных bash-измов расположен здесь.
Проверьте, что используемые заголовочные файлы включены в POSIX или список, рекомендуемый страницей справочника, т.к. например, забыть подключить sys/types.h - не такая уж проблема в Linux®, однако это не так во FreeBSD.
Изменено: 18 сентября 2025 г. by Vladlen Popolitov