Данный конспект был основан на записи лекций №10 (*тык*), №11 (*тык*), №12 (*тык*) с канала А. В. Маятина
Скомпилированное ядро поставляется в виде сжатого образа vmlinuz, который содержит ПО, нужные модули для управления аппаратным обеспечением и интерфейс системных вызов для взаимодействия с ядром. Ядро не содержит:
ls или grepСамо ядро также не умеет устанавливать стороннее ПО, а именно загружать пакеты с готовыми исполняемыми файлами, разрешать зависимости и делать так, чтобы установленная программа была доступна пользователю
Из-за этого установка ПО совершается кодом из пользовательского пространства системы. Ключевые проблемы появления программ, которые устанавливают ПО, это:
Разрешение зависимостей, то есть установка нужных библиотек и компонентов нужных версий, которые нужны для устанавливаемого ПО
Очень важно, чтобы зависимости были совместимы c конкретной версией ядра, с конкретным аппаратным обеспечением и с конкретной программой, которую мы устанавливаем
Также библиотеки не должны избыточно повторяться в системе, то есть по возможности несколько программ должны использовать один экземпляр библиотеки
Процедуры пред- и постустановки
Множество программ дополнительно требуют совершить действия перед или после их установки, например, добавление этой программы как сервис systemd
Удаление и очистка
Как правило, установленное ПО может записывать журналы, иметь базу данных, а также зависимости, которые нужны только этому ПО. Удаление исполняемого файла не очистить то, что эта программа породила
Стандартизация и воспроизводимость
При установке ПО библиотеки могут находиться в разных местах и иметь разные версии, из-за чего установка может давать разные результаты. Единая система установки позволяет добиваться воспроизводимой установки, используя согласованный набор версий пакетов
Всего есть 3 способа:
Установка из локального пакета
Пакет отличается от архива с исходным кодом тем, что содержит вместо кода готовый исполняемый файл и информацию о программе (версия, автор, зависимости). Также пакет содержит нужные скрипты, которые сами устанавливают нужные зависимости, решают конфликты других пакетов и их версий, а также добавляют программу в /usr/bin
Пользователю нужно лишь найти и скачать нужный пакет, вместо того, чтобы мучиться с установкой зависимостей
Эволюцией таких скриптов стал пакетный менеджер - специальная программа, которая хранит базу данных установленных пакетов, из-за чего может управлять зависимостями. Тогда пакету достаточно хранить всего лишь список нужных библиотек. Например, при удалении одного пакета менеджер может удалять его зависимости, но только те, которые не нужны другим установленным пакетам
Установка из удаленного репозитория
Современные пакетные менеджеры умеют скачивать пакеты из удаленных репозиториев. Удаленные репозитории представляют базы данных, которые хранят все версии пакетов, загруженных разработчиком, и полный список зависимостей. Также репозиторий гарантирует, что в нем окажутся все зависимости любого пакета
Удаленные репозитории также отвечают за безопасность предоставляемого ПО. Разработчик может криптографически подписать пакет своим приватным ключом. Далее при отправки репозиторий проверяет, что этот пакет действительно от этого разработчика
Современные дистрибутивы поставляют свои пакетные менеджеры:
dpkg (от Debian Package), который управляется через apt (Advanced Package Tool)rpm (RPM Package Manager, ранее Red Hat Package Manager), который управляется через утилиту dnf (от Dandified YUM, буквально “изысканная вкуснятина”). Ранее вместо dnf использовалась утилита yum (от Yellowdog Updater, Modified)pacman (сокращение от package manager)Как правило последний способ самый удобный, так как, введя всего лишь одну команду (например, apt install fastfetch), можно установить программу и пользоваться. Но, чтобы пакет попал в удаленный репозиторий, он должен пройти нужные проверки, в том числе проверку на востребованность - затратно поддерживать пакет, который почти не востребован и к тому же усложняет граф зависимостей
Помимо этого дистрибутивов Linux очень много, поэтому делать пакеты для каждого дистрибутива осмелиться не каждый разработчик
По этой причине в Linux существуют все 3 способа
Помимо этих трех способов можно применить контейнеризацию, которая позволяет решить конфликты зависимостей и помогает более изолировать процессы, но такой подход сильно требует вычислительных ресурсов
Как правило, исходный код хранится в архиве с расширением .tar.gz. Сначала каталог с файлами:
.tar с помощью утилиты tar,.tar.gzЭтот архив распаковывается в каталог. В каталоге есть скрипт, который указывает, как эту программу нужно собрать
В случае проектов на языке C используется утилита Make. Тогда в каталоге будет файл Makefile, в нем, как правило, указаны действия для 4 целей:
install - установка, то есть сборка программы и перенос программы в каталог /usr/binuninstall - деинсталляция программы, то есть удаление из /usr/bin и ее зависимостейclean - очистка результатов и промежуточных файлов компиляцииdistclean - делает то, что и clean, но и удаляет конфигурациюТакже как правило архив содержит скрипт configure - этот скрипт создает конфигурацию и Makefile под эту систему. Дело в том, что установленный в системе библиотеки могут располагаться в разных местах. configure распознает, где установлены библиотеки, и создает нужный Makefile. Также configure позволяет управлять установкой, например, выбрать место установленной программы
Поэтому установка такой программы может быть выполнена тремя командами:
./configure # создание конфигурации
make # компиляция
make install # установка
Если для выбранного ПО существует пакет под нужный дистрибутив, то можно установить его вместо сборки исходного кода
Исторически сложилось так, что разные дистрибутивы имеют разный формат пакетов, которые несовместимы между собой. Разница форматов появилась из-за различия архитектурных особенностей
Принципиально пакеты разных форматов ничем не отличаются, кроме организации файлов: пакет содержит исполняемый файл, метаинформацию о пакете, скрипты для конфигурации и постустановки. Поэтому такие утилиты, как alien, позволяют совершать конвертацию пакетов, но без гарантии результата
Рассмотрим два распространенных формата
debТакой формат используется в дистрибутивах Ubuntu, Debian, Linux Mint и других производных
Пакет формата deb представляет архив с расширением .deb (архивация происходит через утилиту ar). В этом архиве есть 3 файла в таком порядке:
debian-binary, который содержит версию формата пакета (сейчас это 2.0)control.tar.gzdata.tar.xz (расширение зависит от утилиты архивации)В архиве control.tar.gz находятся файлы, которые не устанавливаются в систему напрямую, а используются пакетным менеджером dpkg для управления установкой. Ключевые файлы в нем:
control - основной файл с информацией о пакете
Здесь хранятся название пакета, версия, архитектура, описание, а также зависимости, без которых программа не будет работать. Например, control для бинарного пакета выглядит так:
Package: fastfetch
Version: 2.62.1+dfsg-1
Architecture: amd64
Maintainer: Hiago De Franco <hiago@defranco.dev.br>
Installed-Size: 1915
Depends: libc6 (>= 2.38), libyyjson0 (>= 0.12.0+ds)
Section: utils
Priority: optional
Multi-Arch: foreign
Homepage: https://github.com/fastfetch-cli/fastfetch
Description: neofetch-like tool for fetching system information
Fastfetch is a neofetch-like tool for fetching system information and
displaying them in a pretty way. It is written mainly in C, with
performance and customizability in mind.
Здесь:
Architecture - архитектура процессораDepends - зависимостиSection - раздел репозиторияPackage - уникальное имя пакетаVersion - версия программыMaintainer - контакты разработчика, который занимается упаковкой программыDescription - описаниеInstalled-Size - примерный размер, который пакет займет на диске после установки (в килобайтах)Priority - приоритет пакета для системы, в порядке убывания важности: Required, Important, Standard, Optional, Extra (упразднен)Homepage - ссылка на официальный сайт проектаmd5sums - контрольные суммы для каждого файла из архива данных для проверки файлов на повреждения или подменуpreinst запускается перед установкойpostinst запускается после установки (например, может запустить службу в systemd)prerm запускается перед удалениемpostrm запускается после удаленияconffiles - список файлов, которые считаются конфигурационными. При обновлении пакета dpkg не будет их просто перезаписывать, а задаст вопрос, что делать с изменениямиВ другом архиве data.tar.gz содержатся файлы, которые будут скопированы в файловую систему: исполняемые файлы, библиотеки, документация и так далее. Пути к файлам внутри архива указываются относительно корня файловой системы. Содержимое архива может выглядеть так:
usr
├── bin
│ └── flashfetch
└── share
├── fastfetch
│ └── presets
│ └── ...
├── man
│ └── man1
│ └── fastfetch.1
└── ...
Таким образом, программа dpkg:
control.tar.gz и проверяет зависимости из файла controlpreinstdata.tar.gz в соответствующие места в системе (в примере выше добавятся /usr/bin/fastfetch, страницы для утилиты man и другое)postinstИсточник: https://manpages.debian.org/unstable/dpkg-dev/deb.5.en.html
Помимо создания пакетов с готовыми программами, формат предполагает создание пакетов с исходным кодом. Такой пакет состоит из 3 частей:
<пакет>_<версия>.dsc (Debian Source Control) - текстовый файл с метаданными исходного пакета. Он содержит короткую версию control, контрольные суммы архивов ниже и подпись разработчика<пакет>_<версия>.orig.tar.xz - архив с немодифицированным исходным кодом программы<пакет>_<версия>-<ревизия>.debian.tar.xz - архив, содержащий все файлы, добавленные мейнтейнером этого пакета для Debian, содержащий только папку debian
В этой папке есть свой debian/control, и выглядит он так:
Source: fastfetch
Section: utils
Priority: optional
Maintainer: Hiago De Franco <hiago@defranco.dev.br>
Uploaders: Carlos Henrique Lima Melara <charlesmelara@riseup.net>,
Maytham Alsudany <maytham@debian.org>,
Rules-Requires-Root: no
Build-Depends:
cmake,
debhelper-compat (= 13),
directx-headers-dev,
libchafa-dev,
...
Standards-Version: 4.7.2
Homepage: https://github.com/fastfetch-cli/fastfetch
Vcs-Browser: https://salsa.debian.org/debian/fastfetch
Vcs-Git: https://salsa.debian.org/debian/fastfetch.git
Package: fastfetch
Architecture: any
Multi-Arch: foreign
Depends:
${shlibs:Depends},
${misc:Depends},
Description: neofetch-like tool for fetching system information
Fastfetch is a neofetch-like tool for fetching system information and
displaying them in a pretty way. It is written mainly in C, with
performance and customizability in mind.
Здесь:
Source - имя исходного пакета, из которого будут собраны один или несколько бинарных пакетовUploaders - сопровождающие, имеющие право загружать пакет в архив DebianBuild-Depends - зависимости, необходимые для сборки исходного пакета в бинарныеStandards-Version - версия политики Debian, которой соответствует пакетVcs-Browser и Vcs-Git - ссылки на репозиторий пакета в системе контроля версий DebianДальше идут блоки, начинающиеся с Package, - они описывают готовые после сборки пакеты (тут таковой один)
Также эта папка содержит:
debian/rules - правила сборки (обычно это файл для утилиты Make)debian/copyright - информация о правообладателя кодаdebian/changelog - журнал измененийdebian/preinst, debian/postinst, debian/prerm, debian/postrmdebian/install - инструкция для утилиты dh_install, которая сообщает, какие файлы из исходников нужно скопировать в бинарный пакетdebian/source/format - версия формата пакета, сейчас это 3.0 (quilt) для пакетов, где дистрибутив не важен, и 3.0 (native) для пакетов, которые есть только в Debian (в них нет архива .orig.tar.xz)debian/config иdebian/templates - скрипт и шаблоны диалогов для системы debconf, которая позволяет задавать пользователю вопросы в процессе установки пакета и сохранять ответы для последующей настройкиДальше из этих двух архивов с помощью утилиты dpkg-buildpackage собирает готовый пакет .deb
rpmТакой формат используется в дистрибутивах Red Hat Enterprise Linux, Fedora, CentOS, AlmaLinux, openSUSE, Oracle Linux и других
Пакет формата rpm - не просто архив ar, а архив с расширением .rpm со своими полями:
rpm), версию формата и указание на то, является ли пакет бинарным или исходным
Сейчас распространены две версии формата: V4, более стабильная версия, и V6, более продвинутаяcpio), содержащий все файлы, которые будут установлены в систему
Чтобы извлечь содержимое, можно использовать утилиту rpm2cpioСама полезная нагрузка содержит файлы, которые будут скопированы в файловую систему, наподобие как сделано в пакетах формата deb, например:
usr
├───bin
│ fastfetch
├───lib
│ └───...
└───share
├───doc
│ └───fastfetch
│ README.md
├───fastfetch
├───man
│ └───man1
│ fastfetch.1.gz
└───...
Исходный пакет, который содержит исходный код программы и имеет расширение .src.rpm, устроен иначе, в нем вместо одного архива в полезной нагрузки есть:
<пакет>.spec<пакет>-<версия>.tar.gz, содержащий исходный код программыЗдесь проявляется ключевое отличие пакета rpm от пакета deb: вместо множества файлов в пакете rpm вся информация хранится в файле <пакет>.spec. Этот файл может выглядеть так:
Name: fastfetch
Version: 2.61.0
Release: 1%{?dist}
Summary: Fast neofetch-like system information tool
License: MIT
URL: https://github.com/fastfetch-cli/fastfetch
Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz
BuildRequires: cmake
...
BuildRequires: yyjson-devel
Recommends: hwdata
Suggests: libXrandr
...
Suggests: elfutils-libelf
ExcludeArch: %{ix86}
%description
fastfetch is a neofetch-like tool for fetching system information and
displaying them in a pretty way. It is written in c to achieve much better
performance, in return only Linux and Android are supported. It also uses
mechanisms like multithreading and caching to finish as fast as possible.
%prep
%autosetup -p1
%build
%cmake -DBUILD_TESTS=ON -DENABLE_SYSTEM_YYJSON=ON -DBUILD_FLASHFETCH=OFF
%cmake_build
%check
%ctest
%install
%cmake_install
%files
%license LICENSE
%doc README.md
%{_bindir}/%{name}
%{_datadir}/%{name}/
%{_mandir}/man1/fastfetch.1*
%{_datadir}/bash-completion/completions/%{name}
%{_datadir}/fish/vendor_completions.d/%{name}.fish
%{_datadir}/zsh/site-functions/_%{name}
%changelog
<журнал изменений>
Сначала идет преамбула. Она содержит метаданные самого пакета:
Name - имяVersion - версияRelease - релизSummary - краткое описаниеLicense - лицензияURL - страница проектаGroup - группа репозитория (по сути категория)Source (исходные файлы) и Patch (патчи), они могут быть указаны как локальный архив или архив на удаленном сервереBuildRequires - зависимости сборки программыRequires - зависимости самой программыObsoletes - пакеты, которые заменяет этот пакетConflicts - пакеты, которые конфликтуют с этим пакетомExclusiveArch - зависимость от архитектуры процессораНа основе этих тегов формируется стандартное имя пакета: Name-Version-Release.Architecture.rpm
Потом идет тело файла, которое состоит из серии секций, каждая из которых отвечает за свой этап сборки. Основные из них это:
%description - подробное описание программы%prep - подготовка исходного кода (распаковка архива, применение патчей)%build - компиляция и сборка исходного кода%install - установка скомпилированных файлов
Как правило, секцию %install пишут так, чтобы операции в ней были обратимыми, поэтому секции %uninstall нет%check - запуск тестов для проверки работоспособности собранного ПО%post - скрипты, выполняющиеся после установки%clean - очистка после сборки%preun - подготовка перед удалением установленной программы%postun - скрипты, выполняющиеся после удаления установленной программы%files - важный список всех файлов и директорий, которые должны попасть в итоговый бинарный пакет%changelog - журнал измененийСам пакет формата rpm устанавливается утилитой rpm. Эта утилита умеет только устанавливать пакет из уже скачанного файла. Чтобы загружать зависимости и пакеты из удаленного репозитория, существуют другие утилиты:
yum (от Yellowdog Updater, Modified), написанная на Python, из-за чего обход графа зависимостей (а следовательно установка пакета) работает медленноУтилита dnf (от Dandified YUM, буквально “изысканная вкуснятина”), написанная на C++
dnf быстрее работает, имеет хорошую документацию, и аккуратно убирает зависимости
Сейчас из-за проблем с совместимостью yum все еще поставляется с дистрибутивами