Сборочные зависимости и адаптация к окружению
Что не умеет Make (или умеет, но сложно):
- Опциональная сборка (включать / не включать какую-то фичу)
- Поиск расположения библиотек / include-ников / утилит и т. п.
- Проверка наличия и/или работоспособности фич / библиотек
- Настройка на различные варианты сборочного инструментария
- Поддержка workflow разработки (заранее определённые действия для тестов, для документации, дисциплина хранения исходников и т. п.)
- Возможность скрытия командных строк инструментов за human-readable описаниями
- …
⇒ Нужен высокоуровневый инструмент, для которого Makefile — это генерат!
Autotools
Генерация configure — autoconf
autoscan для генерации профиля (может сразу найти какие-то зависимости и подсунуть их в профиль)
Генерация произвольного файла Файл на основе его прототипа Файл.in
autoheader (прототип общего заголовочного файла config.h.in, который потом обрабатывается autoconf-ом)
Автоматическое конструирование Makefile.in из Makefile.am для autoconf — automake (Makefile.in — это тоже прототип, который обрабатывается autoconf-ом)
Переопределение процедур поиска и инструментов automake для конкретной системы — aclocal
autoreconf (последовательность вызова других утилит)
Сценарий-генерат configure порождает Makefile
Теперь make может, грубо говоря, всё ☺
+Сборка и использование библиотек: libtool (сегодня не успеем)
- +Другие надстройки…
Картинка по autotools (без интернационализации):
Под капотом — адские макросы на M4 и не менее адские скрипты на sh и perl. Но если посидеть, повтыкать…
Разбор примера
Первый configure.ac (без automake)
Дополнение: сборка out of tree (TODO перенести в пример?):
Создание профиля (вплоть до появления configure) происходит in-tree
Часто считается, что для воспроизводимой сборки не нужен autotools, поэтому генераты этого этапа включаются в исходники и хранятся в репозитории
Отсюда и мем про крибле-крабле-бумс!configure—make—make install
Cборка: путь-до/configure из нового каталога
- Генераты этого этапа хранятся только в этом каталоге
А попроще?
pkg-config — Только способ запуска gcc для .h и библиотек.
Расширения для других make-подобных инструментов.
CMake
- Простой входной файл
- Разные back-end-ы (make, ninja, VC++-проект, XCode), ...
- Предопределённые модули для разных пакетов (вместо pkg-config и вместе с ним)
- ctest и ещё немножко workflow
- Поддержка out-of-tree сборки (есть и в autotools)
Meson / Ninja
- Простой входной файл
- Тестирование и workflow
Не поддерживает make (только ninja, msvc и xcode)
- Поддержка out-of-tree сборки (есть и в autotools)
Поддерживает модули от pkg-config, cmake и некоторые пакето-специфичные (напр. sdl-config)
TODO
Ninja
Аналог make, но
- Принципиально для генератов (например, из meson или cmake)
- Статический разбор сети зависимостей
- Отсутствие умолчаний
- Быстрый (нет условных выражений, поиска соответствий, есть дополнительные оптимизации по скорости)
Нет job server (ребята из CMake вхакивают))
Про job server
TODO пример? А будет ли время?
Все инструменты типа make определяют зависимости
⇒ Есть возможность параллельного запуска сборки независимых целей
- Однако надо соразмеряться с количеством вычислительных ядер (100500 процессов убьют систему)
- ⇒ Нужен примитивный планировщик заданий: N заданий выполняются параллельно, остальные в очереди сообразно зависимостям, когда очередное задания отрабатывает, запускается очередное из очереди
В GNU Make этот планировщик встроенный
В Ninja и подобных ему инструментах «нет необходимости» в планировщике, так как граф зависимостей генерируется статически
Это не работает в составных проектах, где каждый подпроект (библиотека, поддержка фичи и т. п.) собирается изолированно. Например, в Google Chrome пришлось придумать свою систему сборки, которая умеет объединять такие графы.
Современные компиляторы (GCC, причём не только C/C++, но и Rust, Go), поддерживают Link time optimization — это ресурсоёмкая операция, которую можно эффективно распараллелить, если есть job server.
Д/З
Это задание можно выполнять с помощью Autotools, а можно — с помощью других инструментариев (CMake, Meson и т. п.)
- Прочитать
(и прощёлкать) простую методичку по autotols
слайды по autotools
(заглянуть и использовать по необходимости) в Autotools Mythbuster, Autotools Tutorial, AutoBook
- (вариант — то же самое про CMake / Meson / …)
- Простая утилита для подсчёта хешей
Изучить работу библиотеки librhash
- Как вычислять хеш строки и файла
- Как выводить хеш в шестнадцатеричном и в Base64
Установить в сборочное окружение devel-версию библиотеки librhash из пакета согласно правилам вашего дистрибутива
Написать программу rhasher.c, организующую простейшую командную строку (REPL).
- Первое слово командной строки — имя алгоритма хеша.
Второе слово — либо имя файла, либо строка (строка начинается с «"», файл — нет)
Для простоты считаем, что оно не содержит пробелов, и все последующие слова игнорируются
Например, можно использовать strtok
В результате работы команды на stdout выводится соответствующий хеш этого файла или строки, причём
должны поддерживаться как минимум MD5, SHA1 и TTH,
- если имя хеша начиналось с большой буквы, то в шестнадцатеричном виде,
- а если с маленькой — то в Base64 (в примерах есть Base32).
Если команда не опознана или какая-то ошибка с файлом, выводить на stderr сообщение и продолжать работу
Интерфейсом командной строки не заморачиваться, достаточно getline
Конец ввода — Ctrl+D
Изучить работу libreadline
Модифицировать rhasher так, чтобы при сборке можно было использовать и getline(), и readline в зависимости от некоторого #define-а
Написать профиль (Makefile.am + configure.ac или аналог) для сборки проекта
Предусмотреть проверку наличия обеих библиотек (rhash обязательна, readline опциональна)
Предусмотреть принудительную сборку без readline, даже если он есть)
Спойлер тут, но он даже слишком сложный (ncurses какие-то), можно и попроще ☺
Предусмотреть простейшие тесты (как минимум, сравнение с выводом утилит sha1sum и md5sum).
Можно попробовать сделать так, чтобы при вводе не с терминала подсказка не выводилась, но это необязательное усложнение, можно вывод readline() включить в тест
- Как обычно, предусмотреть полное удаление генератов
Создать в репозитории с домашними заданиями подкаталог 07_Environmental и поместить решение туда
Как-то так: