Сборка ПО из исходного кода

Концепция некоторых систем Linux, а иногда и некоторых других ОС семейства Unix неразрывно связана с компиляцией программного обеспечения из исходного кода. Да и многие руководства, связанные с Linux, например LFS, CLFS или LFA также построены вокруг компиляции ПО. Конечно, многие системы Linux снабжены удалёнными хранилищами уже скомпилированных пакетов, но бывают и случаи, когда в репозиториях нет нужного пакета и его приходится собирать из исходников самостоятельно.

Конечно, LFA может дать вам опыт в сборке ПО из исходного кода, однако у пользователей (особенно начинающих) периодически возникали вопросы по поводу компиляции программ; эта страница содержит ответы на основные из вопросов.

Системы сборки

Современное программное обеспечение достаточно крупное и сложное. Если какую-то простую программу мы сможем скомпилировать всего лишь одной командой, например:

# C
gcc main.c -o main

# C++
g++ main.cpp -o main

# Rust
rustc main.rs

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

  1. Написать BASH-скрипт, последовательно выполняющий команды для сборки.
  2. Использовать специальную программу, принимающую на вход определённый файл со сборочными инструкциями, и выполняющая его.

Для чего-то простого вполне сойдёт и BASH-скрипт: это просто и быстро, да и интерпретатор BASH (или совместимого с ним языка) присутствует практически во всех ОС семейства Unix. Но что делать, если скрипт выполнил, условно говоря, из 100 команд всего 10, а на 11 произошла ошибка и скрипт прервал свою работу? Мы можем как-то исправить ситуацию и начать сборку заново. Но тогда, когда мы вновь будем исполнять те команды, которые ранее были успешно выполнены, мы просто потеряем время. А если мы хотим производить сборку пакета в несколько потоков, чтобы сократить общее время сборки? BASH-скрипты, насколько я знаю, этого не позволяют. А если нам нужно как-то кастомизировать сборку пакета, скомпилировав только то, что нам необходимо в конкретной ситуации, а всё, что ненужно, пропустить?

Использование простых скриптов для сборки можно оправдать разве что для каких-то простых проектов, для чего-то посложнее и были придуманы системы сборки. Существует множество разных систем сборки, наиболее популярные из которых GNU Make и meson+ninja. В LFA вы встречались только с make, а, например, если заглянете в руководство BLFS, то можете увидеть у некоторых пакетов и другие системы сборки, например CMake или meson+ninja. Последняя особенно полюбилась разработчикам рабочего окружения GNOME и многие из проектов этого окружения уже используют meson+ninja для своей сборки.

Как определить, какая система сборки используется у пакета?

Если вы собираете какой-либо пакет из состава LFA, LFS или BLFS, то об этом можете не беспокоиться: просто используйте инструкции, которые приведены в этих руководствах. В случае, если по поводу сборки пакета не сказано и в документации (например, обычно общие инструкции по сборке приводятся в файле INSTALL, который находится в директории с исходниками программы. Там даны лишь общие сведения по поводу использования основных команд и всё, конкретных сборочных инструкций там как правило нет), то вам придётся определить систему сборки самостоятельно. Например, посмотрите содержимое директории с исходным кодом программы:

Система сборкиТипичные для неё файлы
GNU MakeMakefile, Makefile.in, configure, aclocal.m4, config.guess, config.in, config.sub
CMakeCMake.list
meson+ninjameson.build

Общий порядок сборки

Название пунктаВыполнение
1Скачивание архива с исходным кодомВыполняется всегда
2Скачивание необходимых сторонних патчейВыполняется при необходимости
3Распаковка архива с исходниками; переход в директорию с исходникамиВыполняется всегда
4Применение патчейВыполняется при необходимости
5Конфигурирование системы сборки; настройка пакета перед сборкойВыполняется при необходимости и/или при наличии возможности настройки
6Сборка пакетаВыполняется при наличии возможности сборки (например, если вы собираете программу, написанную на скриптовом ЯП, то сборка тут необходима не всегда, под сборкой подразумевается не только компиляция исходников, но и иные действия с ними)
7Установка пакета в системуВыполняется всегда

Примеры сборок пакетов

Рассмотрим процесс сборки пакетов из исходного кода на примере BusyBox и iana-etc.

BusyBox

Шаг 1. Скачивание исходного кода:

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2

Шаг 2. Скачивание необходимых сторонних патчей:

Скачивание патчей здесь не требуется.

Шаг 3. Распаковка архива с исходниками; переход в директорию с исходниками:

tar -xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1

Шаг 4. Применение патчей:

Применение патчей здесь не требуется.

Шаг 5. Конфигурирование системы сборки; настройка пакета перед сборкой:

make mrproper
make defconfig

На этапе настройки системы сборки и конфигурирования пакета перед сборкой создаётся ряд файлов либо с параметрами сборки (примером этого может служить файл .config, содержащий параметры сборки ядра Linux или пакета BusyBox), либо файл со сборочными инструкциями (например, генерация файлов Makefile после исполнения скрипта configure с переданными ему ключами с параметрами сборки).

Шаг 6. Сборка пакета:

make -j4

Если программа написана на компилируемом языке программирования, то на этапе сборки вызывается компилятор нужного языка программирования, чтобы сгенерировать исполняемые двоичные файлы из исходников. Если программа написана на интерпретируемом ЯП, то, как правило, если пакет поддерживает «сборку», то на данном этапе исходный код просто подготавливается для его дальнейшей установки в систему.

Шаг 7. Установка пакета в систему:

sudo make install

На этом этапе собранные файлы копируются либо в системные директории, либо в другое место, указанное либо на этапе конфигурирования, либо непосредственно сейчас.

iana-etc

Шаг 1. Скачивание исходного кода:

wget https://github.com/Mic92/iana-etc/releases/download/20240125/iana-etc-20240125.tar.gz

Шаг 2. Скачивание необходимых сторонних патчей:

Скачивание патчей здесь не требуется.

Шаг 3. Распаковка архива с исходниками; переход в директорию с исходниками:

tar -xf iana-etc-20240125.tar.gz
cd iana-etc-20240125

Шаг 4. Применение патчей:

Применение патчей здесь не требуется.

Шаг 5. Конфигурирование системы сборки; настройка пакета перед сборкой:

Конфигурирование и настройка здесь не требуется.

Шаг 6. Сборка пакета:

Сборка пакета здесь не требуется.

iana-etc — просто набор текстовых файлов. Тут нечего компилировать или подготавливать к установке.

Шаг 7. Установка пакета в систему:

cp -v services protocols $LFA_SYS/etc/

Просто вручную копируем нужные нам файлы в системную директорию LFA.

Решение проблем

  • У пакета, который я собираю, используется система сборки GNU Make, однако нет файла Makefile, без которого я не могу собрать пакет. Что делать?

    • Сгенерируйте пакет с помощью скрипта configure. Например:
./configure --prefix=/usr
  • У меня нет файла configure, хотя используется GNU Make!

    • Используйте программу autoreconf из пакета autoconf для генерации configure.