§ 8. Системы сборки кода
Введение
01 Системы сборки кода — это специальные программы, которые собирают и пересобирают код проекта в автоматическом режиме по заранее заданным правилам. Эти системы определяют зависимости между файлами с исходным кодом и выходными файлами (программами, библиотеками и конфигурационными файлами) и в нескольких параллельных процессах выполняют команды компиляции для всех изменившихся со времени последней сборки файлов, соблюдая зависимости. Вторая задача систем сборок — это поиск в операционной системе и подключение к проекту библиотек и программ, которая реализуется наиболее удобными способами в зависимости от операционной системы.
02 В новых языках программирования (Rust, Go) параллельная сборка и поиск зависимостей уже встроены, но для существующих языков (C, C++, Fortran) это невозможно сделать, поэтому для них используют отдельные системы сборки. Про них и пойдет речь в этой лекции.
03 Система сборки является самым важным элементом любого проекта. Эта программа генерирует команды для сборки исходного кода, и чем быстрее эта система собирает код и чем больше рутинных операций автоматизирует, тем быстрее идет разработка, и тем проще настроить непрерывную интеграцию — автоматизированную сборку и тестирование вашей программы. В задачи системы сборки входит
- поиск зависимостей (заголовочных файлов и библиотек),
- генерация различных версий кода в зависимости от платформы, на которой происходит сборка,
- генерация вспомогательных файлов,
- генерация команд для компиляции всех исходный файлов.
04 Как правило, системы сборки поддерживают опции для включения или отключения различных компонент программы. Результатом работы системы сборки является директория, в которой находятся сгенерированные файлы, а также файл с дальнейшими командами для подчиненной (более низкоуровневой) системы сборки. К высокоуровневым системам относятся Autoconf, Cmake, Meson, к низкоуровневым — Make, Ninja. Мы будем изучать Make, Meson и Ninja, а также программу для работы с зависимостями Pkg-config.
Make
05 Классической, а также самой простой системой сборки является GNU Make. Правила сборки для этой системы описываются в файле Makefile, и состоят из списка файлов, которые генерирует (выходные файлы) команда, двоеточия, списка файлов, которые команда использует (входные файлы) для генерации и команд генерации. Если время последнего обновления хотя бы одного входного файла позже времени последнего обновления хотя бы одного выходного файла, то команда выполняется. В противом случае выходные файлы считаются актуальными. Все команды в файле начинаются с символа табуляции.
06 Часто в списке выходных файлов указывают несуществующий файл, тогда команда запускается каждый раз, когда вводится команда make имя-файла
. По умолчанию команда make
собирает первый файл.
07 Поскольку Make был разработан для сборки программ, то в него встроены удобные правила для компиляторов, которые работают даже без наличия в директории Makefile. Например, команда make main.o
запустит команду компиляции прогаммы $CXX $CXXFLAGS -c -o main.o main.cc
. Здесь компилятор и флаги компиляции задаются переменными среды CXX
и CXXFLAGS
, а входной файл определяется автоматически по названию выходного. Если переменные не определены, то используется компилятор по умолчанию (GCC) и флаги по умолчанию (по умолчанию их нет). Команда make main
запустит коману линковки программы $CC $LDFLAGS -o main main.o
. Встроенного правила для сборки библиотек в Make нет, но его легко написать самостоятельно.
08 Переменные среды, используемые Make для сборки программ, стали стандартом и для других систем сборки. Практически все системы сборки их поддерживают. Эти переменные чаще всего используются мейнтенерами пакетов для различных дистрибутивов Linux: в этих переменных указываются флаги, которые используются для сборки всех пакетов дистрибутива. Например, в некоторых системах используется флаг -fstack-protector-strong
, который позволяет получить защиту от взлома программ даже при наличии в них ошибок работы с памятью.
Переменная | Описание |
---|---|
CC | компилятор языка C и линковщик для всех языков |
CFLAGS | флаги компилятора языка C |
CXX | компилятор языка C++ |
CXXFLAGS | флаги компилятора языка C++ |
FC | компилятор языка Fortran |
FFLAGS | флаги компилятора языка Fortran |
LDFLAGS | флаги линковщика |
09 Основным недостатком Make является чрезмерная простота команд: в правилах сборки не учитываются заголовочные файлы, которые включаются в основные файлы с помощью макросов. Это означает, что при изменении заголовочного файла пересборка основного не произойдет. Это послужило причиной создания более совершенных и высокоуровневых систем сборок. Тем не менее, Make до сих пор используется в небольших проектах, в том числе, в проектах, где нужно собирать не код, а что-то другое. Причина этому — простота использования и наличие Make во всех дистрибутивах Linux.
Meson и Ninja
10 Любой проект Meson начинается с дерева директорий, в каждой из которых находится файл для сборки. В meson это файл meson.build. В проектах на C++ с небольшими вариациями используется следующее дерево директорий.
11 Здесь myproject — название проекта, componentN
— логическая единица проекта. Как правило, каждая компонента собирается в отдельную библиотеку (или исполняемый файл), которая затем присоединяется к основному исполняемому файлу. В больших проектах из одной компоненты могут получиться несколько библиотек или исполняемых файлов. При такой схеме название проекта и название компоненты являются частью пути до заголовочного файла, а имя файла совпадает с именем класса, который в нем объявлен. В больших проектах кроме класса в файле могут быть объявлены вспомогательные функции или классы. Чтобы использовать класс Ship
из компоненты component1 в каком-либо файле проекта, его следует подключить, используя путь относительно директории src.
#include <myproject/component1/ship.hh>
12 В небольших проектах структура упрощается путем исключения директорий компонент и хранении всех файлов с исходным кодом в директории myproject. Именно такую структуру я вам рекомендую использовать в заданиях.
13 Корневой файл meson.build для вышеописанной упрощенной структуры содержит параметры проекта: название, версию, язык, опции сборки по умолчанию. Команда project
должна быть первой командой в корневом файле. Команда subdir
исполняет команды из файла meson.build в указанной в качестве аргумента директории.
Для инициализации директории, в которой будет происходить сборка, нужно ввести следующие команды в корне проекта.
meson . build
cd build
ninja
После первичной инициализации после любого изменения кода достаточно набрать ninja
для пересборки проекта. При этом пересоберется только измененная и зависимые от нее части кода.
Pkg-config
14 Для того чтобы подключить библиотеку к вашей программе, достаточно указать директорию с заголовочными файлами, директорию с библиотекой, а также название библиотеки с помощью опции -l
. Если библиотека установлена в систему стандартным способом, то, как правило, достаточно только названия. Процесс подключения библиотек к проекту автоматизируется с помощью программы pkg-config
, которая по названию пакета выдает флаги компилятора и флаги линковщика, которые необходимы для корректной сборки проекта с этой библиотекой.
Команда | Описание |
---|---|
pkg-config --cflags OpenCL | вывести флаги компилятора для подключения библиотеки OpenCL |
pkg-config --libs OpenCL | вывести флаги линковщика для подключения библиотеки OpenCL |
pkg-config --cflags 'OpenCL >= 1.2' | вывести флаги компилятора для подключения библиотеки OpenCL версии не ниже 1.2 |
pkg-config --list-all | вывести список библиотек, установленных в системе и имеющих файл pkg-config |
pkg-config
для подключения библиотек.15 Файл pkg-config
для своего проекта обычно делают из шаблона, в котором прописываются директории, в которые устанавливается проект. В Meson это можно сделать автоматически с помощью модуля pkgconfig
. Файл установится также автоматически при установке всего проекта.
16 Библиотеки также можно автоматически искать с помощью pkg-config
. В Meson это команда dependency
. В случае с Make команды поиска прописываются в CXXFLAGS и LDFLAGS.
Задания
Make1 балл
17 Напишите Makefile с правилами для сборки программы, состоящей из файлов main.cc и main.hh: первый файл включает второй с помощью #include
. Программа должна пересобираться при изменении main.hh. Команды сборки писать не надо, просто укажите зависимости между файлами.
Make + pkg-config1 балл
18 Соберите код из первого задания с библиотекой zlib. Библиотеку подключите с помощью pkg-config
.
Meson1 балл
19 Соберите код из первого задания с библиотекой zlib с помощью Meson.
Git + Meson2 балла
20 Скачайте проект unistdx с помощью команды git
. Соберите его с помощью Meson с флагами компилятора -march=native -O3 и флагом линковщика -flto.