Сборка из исходников: make, ./configure

Что на самом деле происходит, когда README говорит «./configure && make && make install», и как не превратить /usr/local в свалку.

Сборка из исходников — превращение исходного кода программы в исполняемые файлы прямо на вашей машине компилятором, в отличие от установки готового бинарного пакета через apt/dnf.

В 95% случаев программу ставят пакетным менеджером — это быстро и безопасно. Но иногда выбора нет: нужна версия новее, чем в репозитории; нужны опции компиляции, которых нет в готовом пакете; программы просто нет в репозитории; или вы патчите исходники сами. Тогда в дело идёт классическая троица configure → make → make install. Понимать её обязан любой, кто работает с серверами: рано или поздно вы соберёте nginx с нужным модулем, свежий htop или чью-то утилиту с GitHub.

Инструменты: gcc и make в двух словах

gcc (или cc, clang) — компилятор: переводит .c-файлы в машинный код и линкует их в исполняемый файл. Простейший пример:

cat > hello.c <<'EOF'
#include <stdio.h>
int main(void) { printf("Привет из C\n"); return 0; }
EOF

gcc hello.c -o hello       # скомпилировать в файл hello
./hello

Вывод:

Привет из C

Когда файлов сотни, вручную звать gcc невозможно — этим управляет make. Утилита make читает Makefile (список целей и правил), смотрит на даты файлов и пересобирает только то, что изменилось. Цель — это имя задачи; типичные цели — сборка (по умолчанию), install, clean. Минимальный Makefile:

hello: hello.c
	gcc hello.c -o hello

clean:
	rm -f hello

(Отступ в Makefile обязан быть символом табуляции, не пробелами.) Теперь make соберёт hello, а make clean уберёт результат.

Зачем нужен ./configure

Реальные проекты должны собираться на разных системах с разным набором библиотек. Скрипт ./configure (его генерирует Autotools) проверяет окружение: есть ли компилятор, какие библиотеки и заголовки установлены, поддерживает ли система нужные функции. По итогам он создаёт Makefile, заточенный под вашу машину. Если чего-то не хватает — configure сразу падает с понятной ошибкой, и это лучше, чем загадочный сбой в середине компиляции.

Канонический цикл сборки

# 1. скачать и распаковать исходники
tar xzf htop-3.3.0.tar.gz
cd htop-3.3.0

# 2. настроить под систему (без аргументов — параметры по умолчанию)
./configure

# 3. собрать (распараллелить по числу ядер процессора)
make -j"$(nproc)"

# 4. установить (нужны права на целевой каталог)
sudo make install

Что делает каждый шаг: configure проверяет зависимости и пишет Makefile; make компилирует; make install копирует готовые файлы в систему (по умолчанию в /usr/local). Флаг -j у make запускает сборку в несколько потоков — $(nproc) подставит число ядер и заметно ускорит компиляцию крупных проектов.

-dev зависимости: почему configure падает

Самая частая стена новичка — configure ругается: «library X not found» или «header Y.h missing». Причина в том, что для использования библиотеки хватает рантайм-пакета (например, libssl3), а для сборки против неё нужны ещё заголовочные файлы (.h) — они лежат в отдельном пакете с суффиксом -dev (Debian/Ubuntu) или -devel (Fedora/RHEL).

# Debian/Ubuntu: базовый набор для сборки + примеры -dev пакетов
sudo apt install build-essential
sudo apt install libssl-dev zlib1g-dev libncursesw5-dev

# Fedora/RHEL: аналог build-essential — группа, плюс -devel пакеты
sudo dnf groupinstall "Development Tools"
sudo dnf install openssl-devel zlib-devel ncurses-devel

Метапакет build-essential тянет gcc, make, libc-заголовки и прочее — без него собирать нечем. Имя нужного -dev пакета обычно угадывается по сообщению об ошибке: «zlib.h not found» → zlib1g-dev.

prefix: куда устанавливать

По умолчанию make install раскидывает файлы по /usr/local (/usr/local/bin, /usr/local/lib и т.д.). Аргумент --prefix у configure меняет корень установки. Это спасает в двух случаях: установка без root (в домашний каталог) и аккуратная изоляция программы в отдельной папке:

# поставить только себе, без sudo
./configure --prefix="$HOME/.local"
make -j"$(nproc)" && make install
# бинарь окажется в ~/.local/bin — он должен быть в PATH

# изолировать конкретную версию в своём каталоге
./configure --prefix=/opt/htop-3.3.0
make && sudo make install

Связка с прошлым уроком: чтобы система нашла программу из нестандартного --prefix, её bin должен быть в PATH (для ~/.local/bin часто уже так).

Проблема удаления и checkinstall

Главный недостаток make install: он просто копирует файлы, не записывая их в базу пакетного менеджера. Поэтому apt/dnf о такой программе ничего не знают, обновлять и удалять её нечем, а файлы расползаются по системе. Частичные решения:

  • У многих проектов есть цель make uninstall — но только если её предусмотрел автор и вы сохранили дерево сборки.
  • checkinstall вместо make install отслеживает, какие файлы установились, и собирает из них настоящий .deb/.rpm. Тогда программа попадает в базу пакетов и удаляется штатно.
sudo apt install checkinstall
# вместо `sudo make install`:
sudo checkinstall            # создаст и установит .deb
# удалить потом — как обычный пакет:
sudo apt remove htop

Как это работает под капотом

«Скомпилировать» — это на самом деле конвейер из четырёх стадий, который gcc прячет за одной командой: препроцессор раскрывает #include и макросы; компилятор переводит C в ассемблер; ассемблер — в объектные файлы .o (машинный код, но ещё без связей между файлами); линкер (ld) сшивает все .o и подключает библиотеки в единый исполняемый файл. Промежуточные стадии можно увидеть:

gcc -c hello.c -o hello.o    # только компиляция, без линковки -> объектный файл
gcc hello.o -o hello         # отдельный шаг линковки
file hello.o hello           # типы файлов: object vs executable

Заголовочные .h нужны именно препроцессору и компилятору — отсюда обязательность -dev пакетов. А make экономит время, сравнивая даты .c и .o: если исходник не менялся, его .o не пересобирается — поэтому повторный make в большом проекте отрабатывает мгновенно.

Частые ошибки

  • Пропустили build-essential / «Development Tools» — собирать нечем, configure не находит компилятор.
  • Видят «header.h not found» и не понимают, что нужен -dev/-devel пакет соответствующей библиотеки, а не сама библиотека.
  • Делают sudo make install на каждый чих в системный /usr/local, а потом не могут это удалить — используйте --prefix в отдельный каталог или checkinstall.
  • В Makefile отступ сделан пробелами вместо табуляции — make падает с «missing separator».
  • Запускают чистый make на 8-ядерной машине без -j — сборка тянется в один поток в разы дольше.

Итоги

  • Сборка из исходников нужна, когда пакета нет, версия устарела или требуются особые опции компиляции.
  • Цикл ./configure && make && make install: проверка окружения → компиляция → установка файлов в систему.
  • build-essential (или «Development Tools») даёт компилятор и make; -dev/-devel пакеты дают заголовки для сборки против библиотек.
  • --prefix задаёт корень установки — для установки без root или изоляции версии; не забудьте про PATH.
  • make install не регистрирует файлы в пакетном менеджере; checkinstall или make uninstall решают проблему удаления.
Проверьте себя
1. При запуске ./configure вы видите ошибку «openssl/ssl.h: No such file or directory», хотя сам OpenSSL в системе установлен и работает. Что нужно сделать?
AПереустановить OpenSSL целиком
BУстановить -dev/-devel пакет (libssl-dev или openssl-devel) — он содержит заголовочные .h-файлы, нужные для сборки против библиотеки
CЗапустить configure с правами root
DДобавить путь к OpenSSL в PATH
2. Почему `sudo make install` считается «грязным» способом установки по сравнению с пакетным менеджером, и что предлагает checkinstall?
Amake install заражает систему вирусами; checkinstall их вычищает
Bmake install копирует файлы по системе, не регистрируя их в базе пакетов (нечем штатно обновить/удалить); checkinstall отслеживает установленные файлы и собирает из них .deb/.rpm
Cmake install работает только от root; checkinstall позволяет ставить без прав
Dmake install не умеет компилировать; checkinstall компилирует за него