Собираем ядро и мир FreeBSD из исходников

29 марта 2016

Сегодня мы научимся собирать ядро и мир (основные исполняемые файлы, библиотеки и тд) FreeBSD из сходных кодов. Ранее в заметке PostgreSQL: сборка из исходников и настройка под Linux мы выясняли, зачем нужно уметь собирать что-то из исходников. Основными сценариями являются оптимизация под конкретное железо и получение самого свежака прямо из ветки master. Кроме того, вы можете настроить ядро под свои конкретные нужды — выбрать шедулер, отключить IPv6, убрать поддержку лишнего железа и тд. Наконец, если вдруг вы планируете когла-нибудь стать коммитером в ядро FreeBSD, знания о том, как это ядро собирается, будут не лишними.

Дисклеймер: Многое из написанного ниже может потерять актуальность к моменту, когда вы будете это читать. Прежде, чем действовать по приведенной инструкции, не лишним будет сначала свериться с хэндбуком. Заметьте также, что ниже речь идет исключительно про сборку ядра и мира из исходников, а процедура бинарного обновления системы описана в заметке Памятка по обновлению ядра и мира FreeBSD.

Подготовка окружения

При написании заметки я использовал следующий установочный диск:

FreeBSD-10.2-RELEASE-amd64-disc1.iso

Лишней железки под рукой у меня не было, поэтому все эксперименты ставились на VirtualBox. Был выбран VirtualBox, а не Vagrant, так как нам понадобится доступ к монитору системы. В VirtualBox в настройках сети было создана два адаптера — один NAT и один Host Only. Первый нужен для доступа гостевой системы в интернет. Второй позволит ходить в гостевую систему с хост-системы по SSH.

После установки системы ставим пакеты git-lite, vim-lite, tree, bash, sudo, правим /usr/local/etc/sudoers, затем меняем оболочку пользователя:

sudo chsh -s /usr/local/bin/bash eax

В ~/.gitconfig дописываем:

[core]
    pager = less -S

Мне лично еще очень нравится иметь в системе привычный htop:

cd /usr/posts
sudo portsnap fetch extract
cd sysutils/htop
sudo make -DBATCH install clean

Подробности про первоначальную настройку системы и управление пакетами во FreeBSD вы найдете в заметках Использование FreeBSD на десктопе, версия 2.0 и Управление пакетами во FreeBSD при помощи утилиты pkg соответственно.

Собираем ядро

То, как будет собираться ядро FreeBSD, контролируется несколькими файлами конфигурации.

Часть настроек лежит в /etc/make.conf. Этот файл влияет на сборку портов, мира, ядра FreeBSD, и вообще любых программ на C. Здесь можно указать CPU, под который производится сборка, флаги оптимизации, и так далее. Перечень всех доступных опций можно подглядеть в /usr/share/examples/etc/make.conf и man make.conf. Пример /etc/make.conf:

# используем Clang 3.7 вместо идущего по дэфолту 3.4
CC=/usr/local/bin/clang37
CXX=/usr/local/bin/clang++37
CPP=/usr/local/bin/clang-cpp37

# оптимизируем код под используемый на машине CPU
CPUTYPE?=native

# флаги при компиляции кода на C и C++
CFLAGS+=-O2 -pipe
CXXFLAGS+=-O2 -pipe

Еще есть /etc/src.conf, который имеет немного другие настройки и затрагивает только ядро и мир. Подробности смотри в man src.conf. Пример /etc/src.conf:

CPUTYPE?=native
CFLAGS+=-O2 -pipe
COPTFLAGS+=-O2 -pipe

Наконец, также существует и файл конфигурации самого ядра. Про него будет рассказано далее.

Если при установке FreeBSD вы поставили галочку «установить все исходники», то исходники ядра и мира будут находится в каталоге /usr/src. Информацию о том, что в каком подкаталоге находится, можно найти в Developer’s Handbook и файле README.

Забыли поставить галочку? Не расстраивайтесь. Все равно вам, скорее всего, хотелось бы иметь самые свежие исходники, а не те, что были записаны на установочный CD. Исходники FreeBSD можно скачать с официального SVN-репозитория, а также с его зеркала на GitHub.

Мне лично Git ближе и милее, поэтому я сделал следующее:

cd /usr
sudo mkdir src.backup
sudo mv src/* src.backup
sudo git clone https://github.com/freebsd/freebsd.git src
cd src

Выбираем ветку. Я лично выбрал master.

Если же вы все-таки предпочитаете Subversion:

# вместо head укажите интересующую вас ветку или тэг
cd /usr/src && sudo svn co http://svn.freebsd.org/base/head/ ./

Настройки, с которыми собирается ядро, лежат в файле:

/usr/src/sys/(архитектура)/conf/(конфиг)

Название архитектуры зависит от вашего CPU. Как правило, это либо i386, либо amd64. Конфиг ядра, идущего в системе по умолчанию, называется GENERIC. Можно скопировать его и назвать, например, MYKERNEL.

cd sys/amd64/conf
sudo cp GENERIC MYKERNEL

Конфиг хорошо документирован. К примеру, можно отключить поддержку IPv6 и IPSec, закомментировав две строчки:

#options        INET6
#options        IPSEC

Важно! В CURRENT по умолчанию включен механизм witness, предназначенный для поиска дэдлоков. Имейте в виду, что он может выводить в консоль пугающие стэктрейсы, некоторые из которых являются багами и должны быть зарепорчены в рассылку freebsd-current@, а некоторые являются вполне безобидными. Также сообщается, что механизм этот довольно тормозной, и потому вам вполне может захотеться его отключить.

Собираем ядро с нашими настройками:

cd ../../..
sudo make -j4 buildkernel KERNCONF=MYKERNEL

Перед установкой ядра делаем резервную копию текущего:

sudo cp -r /boot/kernel/ /boot/kernel.good

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

Устанавливаем новое ядро:

sudo make installkernel KERNCONF=MYKERNEL

После установки ядро окажется в каталоге /boot/kernel, а резервная копия текущего ядра будет лежать в /boot/kernel.old.

Вместо пары шагов buildkernel и installkernel также можно было использовать команды:

sudo make -j4 kernel KERNCONF=MYKERNEL INSTKERNNAME=kernel.test
sudo nextboot -k kernel.test

Этим мы сказали положить ядро в /boot/kernel.test и использовать его один раз при следующей закрузке. Если все пройдет хорошо, после перезагрузки /boot/kernel.test можно будет переименовать в /boot/kernel. Этот вариант может быть удобнее, если к машине нет физического доступа.

Перезагружаемся:

sudo reboot

После загрузки системы проверяем версию ядра:

uname -a

Должны увидеть что-то вроде

FreeBSD vbox 11.0-CURRENT FreeBSD 11.0-CURRENT #0 6a8922d(master): Tue
Feb 28 13:40:05 MSK 2016 root@vbox:/usr/obj/usr/src/sys/MYKERNEL amd64

Если что-то пошло не так, при загрузке системы в меню можно выбрать загрузку с kernel.old (нажатием цифры 5). Также можно выбрать «Escape to a loader prompt» (нажатием цифры 3) и выбрать вообще любое ядро, например:

boot kernel.good

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

Собираем мир

Мир от FreeBSD 10 почти наверняка будет не лучшим образом работать с ядром FreeBSD 11. Поэтому не лишено смысла вместе с пересборкой ядра системы обновить сразу и мир.

Важно! Компиляция мира может занять очень много времени, особенно если в VirtualBox вы дали виртуалке только одно ядро. Если вы используете реальную машину, вам потребуется физический доступ к ней. Также от вас потребуется вручную смержить множество конфигов, подтвердить удаление множества файлов, а потом (!) переустановить все установленные пакеты и пересобрать все установленные порты. Возможно, вместо сборки нового мира, вам будет проще временно вывести машину из эксплуатации, поставить на нее новую систему, и настроить поверх все необходимое. Или воспользоваться уже упомянутым механизмом бинарного обновления. Как мне кажется, пересборка мира — процедура больше для разработчиков FreeBSD, чем администраторов боевых серверов.

Итак, переходим в каталог с исходниками:

cd /usr/src

Чистим временные файлы, которые могли остаться с предыдущей сборки:

sudo rm -rf /usr/obj

Собираем мир:

sudo make -j4 buildworld

Чтобы минимизировать риски, связанные с обновлением уже запущенных и работающих приложений, рекомендуется перевести ОС в однопользовательский режим:

# в окне VirtualBox или стоя рядом с сервером
sudo shutdown now

Теперь монтируем файловую систему (у меня ZFS):

zfs set readonly=off zroot
zfs mount -a

Если вы используете UFS, тогда:

mount -u /
mount -a -t ufs
swapon -a

Перед установкой нового мира может потребоваться подготовить файлы конфигурации, создать новые группы, и так далее. Делается это командой:

mergemaster -p

Там довольно простой диалоговый режим, ничего особенного.

Ставим новый мир:

cd /usr/src
make installworld

Завершаем правку конфигов и вот это все:

mergemaster -iF

Удаляем файлы, ставшие ненужными:

make delete-old

Перезагружаемся:

reboot

После перезагрузки, согласно хэндбуку, также нужно обновить установленные пакеты:

sudo pkg upgrade

Если что-то ставили из портов, то их тоже придется пересобрать:

cd /usr/ports
sudo portsnap fetch update
sudo pkg install portmaster
sudo portmaster -af

После чего можно удалить библиотеки, ставшие теперь ненужными:

cd /usr/src
sudo make delete-old-libs

Вот так хитро во FreeBSD происходит пересборка мира.

Запуск тестов

Начиная с FreeBSD 11 мир включает в себя набор тестов. Запускаются эти тесты таким образом:

sudo pkg install kyua
sudo kyua test -k /usr/tests/Kyuafile
sudo kyua report

Тесты запускаются под sudo, так как некоторые из них требуют рутовых прав. Без sudo такие тесты будут пропущены. Некоторые тесты выполняются очень долго (скажем, 80 секунд), а всего тестов более 3.5 тысяч, так что будьте терпеливы.

Заключение

Как видите, процесс компиляции ядра и мира FreeBSD из исходных кодов не является самым простым, но разобраться в нем вполне реально. К счастью, во FreeBSD есть превосходная документация практически на все. Поэтому, если в этой заметке вы не нашли чего-то, что вы искали, обращайтесь к хэндубку!

Дополнение: Также вас могут заинтересовать статьи Памятка по отладке ядра и драйверов во FreeBSD и Памятка по сборке ядра Linux из исходного кода.

Метки: , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.