Команда pkg в linux

Обновлено: 07.07.2024

This document aims to give an overview to using the pkg-config tool from the perspective of both a user and a developer. It reviews the concepts behind pkg-config, how to write pkg-config files to support your project, and how to use pkg-config to integrate with 3rd party projects.

More information on pkg-config can be found at the website and in the pkg-config(1) manual page.

This document assumes usage of pkg-config on a Unix-like operating system such as Linux. Some of the details may be different on other platforms.

Modern computer systems use many layered components to provide applications to the user. One of the difficulties in assembling these parts is properly integrating them. pkg-config collects metadata about the installed libraries on the system and easily provides it to the user.

Without a metadata system such as pkg-config, it can be very difficult to locate and obtain details about the services provided on a given computer. For a developer, installing pkg-config files with your package greatly eases adoption of your API.

Concepts

The primary use of pkg-config is to provide the necessary details for compiling and linking a program to a library. This metadata is stored in pkg-config files. These files have the suffix .pc and reside in specific locations known to the pkg-config tool. This will be described in more detail later.

The file format contains predefined metadata keywords and freeform variables. An example may be illustrative:

The keyword definitions such as Name: begin with a keyword followed by a colon and the value. The variables such as prefix= are a string and value separated by an equals sign. The keywords are defined and exported by pkg-config. The variables are not necessary, but can be used by the keyword definitions for flexibility or to store data not covered by pkg-config.

Here is a short description of the keyword fields. A more in depth description of these fields and how to use them effectively will be given in the Writing pkg-config files section.

  • Name: A human-readable name for the library or package. This does not affect usage of the pkg-config tool, which uses the name of the .pc file.
  • Description: A brief description of the package.
  • URL: An URL where people can get more information about and download the package.
  • Version: A string specifically defining the version of the package.
  • Requires: A list of packages required by this package. The versions of these packages may be specified using the comparison operators =, <, >, <= or >=.
  • Requires.private: A list of private packages required by this package but not exposed to applications. The version specific rules from the Requires field also apply here.
  • Conflicts: An optional field describing packages that this one conflicts with. The version specific rules from the Requires field also apply here. This field also takes multiple instances of the same package. E.g., Conflicts: bar = 1.3.0.
  • Cflags: The compiler flags specific to this package and any required libraries that don't support pkg-config. If the required libraries support pkg-config, they should be added to Requires or Requires.private.
  • Libs: The link flags specific to this package and any required libraries that don't support pkg-config. The same rule as Cflags applies here.
  • Libs.private: The link flags for private libraries required by this package but not exposed to applications. The same rule as Cflags applies here.

Writing pkg-config files

When creating pkg-config files for a package, it is first necessary to decide how they will be distributed. Each file is best used to describe a single library, so each package should have at least as many pkg-config files as they do installed libraries.

The package name is determined through the filename of the pkg-config metadata file. This is the portion of the filename prior to the .pc suffix. A common choice is to match the library name to the .pc name. For instance, a package installing libfoo.so would have a corresponding libfoo.pc file containing the pkg-config metadata. This choice is not necessary; the .pc file should simply be a unique identifier for your library. Following the above example, foo.pc or foolib.pc would probably work just as well.

The Name, Description and URL fields are purely informational and should be easy to fill in. The Version field is a bit trickier to ensure that it is usable by consumers of the data. pkg-config uses the algorithm from RPM for version comparisons. This works best with a dotted decimal number such as 1.2.3 since letters can cause unexpected results. The number should be monotonically increasing and be as specific as possible in describing the library. Usually it's sufficient to use the package's version number here since it's easy for consumers to track.

Before describing the more useful fields, it will be helpful to demonstrate variable definitions. The most common usage is to define the installation paths so that they don't clutter the metadata fields. Since the variables are expanded recursively, this is very helpful when used in conjunction with autoconf derived paths.

The most important pkg-config metadata fields are Requires, Requires.private, Cflags, Libs and Libs.private. They will define the metadata used by external projects to compile and link with the library.

Requires and Requires.private define other modules needed by the library. It is usually preferred to use the private variant of Requires to avoid exposing unnecessary libraries to the program that is linking with your library. If the program will not be using the symbols of the required library, it should not be linking directly to that library. See the discussion of overlinking for a more thorough explanation.

Since pkg-config always exposes the link flags of the Requires libraries, these modules will become direct dependencies of the program. On the other hand, libraries from Requires.private will only be included when static linking. For this reason, it is usually only appropriate to add modules from the same package in Requires.

The Libs field contains the link flags necessary to use that library. In addition, Libs and Libs.private contain link flags for other libraries not supported by pkg-config. Similar to the Requires field, it is preferred to add link flags for external libraries to the Libs.private field so programs do not acquire an additional direct dependency.

Finally, the Cflags contains the compiler flags for using the library. Unlike the Libs field, there is not a private variant of Cflags. This is because the data types and macro definitions are needed regardless of the linking scenario.

Using pkg-config files

Assuming that there are .pc files installed on the system, the pkg-config tool is used to extract the metadata for usage. A short description of the options can be seen by executing pkg-config --help. A more in depth discussion can be found in the pkg-config(1) manual page. This section will provide a brief explanation of common usages.

Consider a system with two modules, foo and bar. Their .pc files might look like this:

The version of the modules can be obtained with the --modversion option.

To print the link flags needed for each module, use the --libs option.

Notice that pkg-config has suppressed part of the Libs field for both modules. This is because it treats the -L flag specially and knows that the $ directory /usr/lib is part of the system linker search path. This keeps pkg-config from interfering with the linker operation.

Also, although foo is required by bar, the link flags for foo are not output. This is because foo is not directly needed by an application that only wants to use the bar library. For statically linking a bar application, we need both sets of linker flags:

pkg-config needs to output both sets of link flags in this case to ensure that the statically linked application will find all the necessary symbols. On the other hand, it will always output all the Cflags.

Another useful option, --exists, can be used to test for a module's availability.

One of the nicest features of pkg-config is providing version checking. It can be used to determine if a sufficient version is available.

Some commands will provide more verbose output when combined with the --print-errors option.

The message above references the PKG_CONFIG_PATH environment variable. This variable is used to augment pkg-config's search path. On a typical Unix system, it will search in the directories /usr/lib/pkgconfig and /usr/share/pkgconfig. This will usually cover system installed modules. However, some local modules may be installed in a different prefix such as /usr/local. In that case, it's necessary to prepend the search path so that pkg-config can locate the .pc files.

A few autoconf macros are also provided to ease integration of pkg-config modules into projects.

  • PKG_PROG_PKG_CONFIG([MIN-VERSION]): Locates the pkg-config tool on the system and checks the version for compatibility.
  • PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]): Checks to see whether a particular set of modules exists.
  • PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]): Checks to see whether a particular set of modules exists. If so, it sets <VARIABLE-PREFIX>_CFLAGS and <VARIABLE-PREFIX>_LIBS according to the output from pkg-config --cflags and pkg-config --libs.

Frequently asked questions

The pkg-config output can easily be used on the compiler command line. Assuming the x library has a x.pc pkg-config file:

The integration can be more robust when used with autoconf and automake. By using the supplied PKG_CHECK_MODULES macro, the metadata is easily accessed in the build process.

If the x module is found, the macro will fill and substitute the X_CFLAGS and X_LIBS variables. If the module is not found, an error will be produced. Optional 3rd and 4th arguments can be supplied to PKG_CHECK_MODULES to control actions when the module is found or not.

If the x library has pkg-config support, add it to the Requires.private field. If it does not, augment the Cflags field with the necessary compiler flags for using the libx headers. In either case, pkg-config will output the compiler flags when --static is used or not.

Again, add the module to Requires.private if it supports pkg-config. In this case, the compiler flags will be emitted unnecessarily, but it ensures that the linker flags will be present when linking statically. If libx does not support pkg-config, add the necessary linker flags to Libs.private.

Copyright (C) 2010 Dan Nicholson.
This document is licensed under the GNU General Public License, Version 2 or any later version.


В Linux все файлы и каталоги связаны с владельцами: пользователь и группа. На файлы и каталоги назначенны разрешения, определяющие права доступа, такие как чтение, запись и выполнение, которые в конечном итоге определяют, кто имеет какие права на доступ к ним.

В этой статье мы рассмотрим, как изменить группу-владельца на файл или каталог с помощью команды chgrp. Команда chgrp (change group) используется для изменения группы, которой принадлежит файл или директория. В отличие от команды chown, которая требует указать как имя пользователя, так и имя группы, в chgrp требуется только группа.

Синтаксис команды chgrp

Синтаксис для изменения группы, к которой принадлежит файл, довольно прост. Просто напишите команду chgrp и после нее укажите имя группы, а за ним имя объекта.

Атрибут group_name представляет собой имя группы, которая станет владельцем файла или каталога (/path). Кроме того, можно указать GID (идентификатор группы) вместо имени группы. В этом случае вам нужно добавить GID со знаком плюс (+).

Изменение группы-владельца файла с помощью команды chgrp

Перед изменением группы, которая является владельцем файла, рекомендуется с помощью команды ls проверить текущую группу, которой принадлежит файл file.

Далее, чтобы установить собственником определенную группу (например, mygroup) выполните следующую команду:

При изменении группы, которая владеет файлом или каталогом Вы можете столкнуться с ошибкой chgrp operation not permitted. Эта ошибка указывает на то, что пользователь, от которого Вы выполняете команду, не имеет достаточных прав для изменения владельца файла.


Решенением этой проблемы будет запуск команды с sudo (конечно, Ваш пользователь должен обладать такими привелегиями):

Введите пароль пользователя, когда у Вас его спросит система, и в итоге права применятся.

Кроме того, Вы можете указать несколько файлов в качестве аргументов при использовании команды chgrp следующим образом:

Как рекурсивно изменить группу-владельца на файл или директорию в Linux

Иногда может потребоваться рекурсивно изменить группу у всех файлов и субдиректорий в определенном каталоге. Чтобы это сделать, используйте -R, как показано в приведенном ниже примере.

Изменение группы-владельца у символических ссылок

Использование опции -R (рекурсивно) не назначает прав на символические ссылки, и поэтому у них сохранятся прежняя группа. Чтобы установить новую группу и на символические ссылки, передайте параметр -h:

Заключение

В этой статье мы показали Вам, как с помощью команду chgrp в Linux можно применить новую группу-владельца к файлу или директории. Хотя можно то же самое сделать и командой chown, но команда chgrp предлагает гораздо более простой способ сделать это. Команда chgrp была создана намного раньше, когда chown еще не мог работать с группами.

Спасибо за чтение и, пожалуйста, если у Вас есть какие-либо дополнения, пишите в комменариях.

Иногда может возникнуть вопрос: чьих этот файл, откуда вообще взялась эта библиотека? Удобный менеджер пакетов решает очень многие проблемы ОС. Можно с уверенностью сказать, что если вы подружитесь с МП, то подружитесь и с дистрибутивом как таковым. Причем важно освоить именно набор основных команд, и знать где найти дополнительную информацию.

Управление пакетами

Далее следует джентльменский набор необходимых для повседневной рутины команд основных Linux дистрибутивов: установить, обновить и удалить пакет, накатить обновления, проверить зависимости, установить принадлежность файла пакету и пр.

Debian и родственные

Популярность и образ дружественного к пользователю Linux дистрибутива сыграли с Ubuntu злую шутку. Некоторым новичкам кажется, что можно на нем делать все, что угодно без помощи командной строки. Это заблуждение и лучше от него поскорее избавиться.

То, что в примерах aptitude не значит, что он правильнее, чем apt-get . Для меня это всего лишь дело привычки.

Некоторые функции доступны с дополнительным МП dpkg .

Есть еще такое чудо — wajig. Несмотря на странное звучание, вполне годный МП с человеко-читабельным выводом информации на экран.

Настройка репозиториев производится правкой файла /etc/apt/sources.list

В целом ПМ Debian один из лучших, с которыми мне доводилось иметь дело.

Redhat и другие RPM дистрибутивы

RPM нельзя назвать образцовым пакетным менеджером, скорее это был кактус, который мыши употребляли в пищу со слезами на глазах. Затем появились более или менее вменяемые МП: yum , dnf , zypper и другие. Только что на сервере RHEL 7.4 yum за раз обновил более 700 пакетов и ничего при этом не сломал, неплохой результат я считаю.

Команды rpm на те случаи, когда использовать yum не с руки.

Чтобы настроить репозитории Yum , откройте файл /etc/yum.repos.d/*.repo , или используйте команду yum-config-manager .

Zypper

На SuSE Linux используется Zypper / YaST для управления пакетами, движок ZYpp крутится поверх RPM.

Можно использовать операторы и регулярные выражения.

Управление репозиториями производится командой zypper mr .

Pacman

Этот МП используется в Арче и Manjaro.

Движок поиска в базе данных поддерживает регулярные выражения.

Настройка репозиториев и зеркал производится из файла /etc/pacman.conf

Gentoo emerge

Конечно же это скорее умозрительный сценарий, чем реальный, так как сложно предположить, что красноглазый пользователь Gentoo Linux не знает необходимых опций emerge . Тем не менее, без этого альманах был бы неполным.

С дополнительными утилитами можно получить больше информации о файлах, ненужных пакетах и т. д.

Операционная система OpenWrt обычно используется как прошивка для роутеров. Типичное применение заключается в том, чтобы установить и забыть. Но если вдруг вам чего-то не хватит, то придётся разбираться в устройстве дистрибутива.


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

Мне захотелось запатчить LUCI (этого в статье не будет), но адекватного быстрого введения я не нашёл, пришлось самостоятельно собирать отрывки сведений из разрозненной документации, статей и примеров, поглядывая в код и на результаты работы. Бонусом собрал примитивный (но бесполезный на практике) пакет, которого ещё нет в репозитории. Собранным ликбезом делюсь ниже.

Устройство репозитория

В файловой системе OpenWrt есть файл /etc/opkg/distfeeds.conf , в нём указывается системный (предоставленный разработчиками OpenWrt и opkg) список репозиториев. Собственные и сторонние репозитории можно указать в /etc/opkg/customfeeds.conf . Формат однострочный, состоит из трёх слов:

  1. src или src/gz , от этого зависит, будет качаться файл Packages или Packages.gz . Судя по коду, есть другие опции для первого слова, но я не нашёл репозиториев, для которых это было бы актуально. Несмотря на src в названии, это репозиторий для бинарных пакетов. Специального формата репозиториев для пакетов с исходным кодом, аналогичного тому, что используется в Debian/APT, у opkg не предусмотрено.
  2. Название репозитория или «фида» в терминологии opkg/OpenWrt.
  3. URL, внутри которого лежит файл Packages / Packages.gz .
  1. При перезагрузке кэш очистится. На встроенных системах вроде роутеров это абсолютно разумно.
  2. В /etc/opkg/customfeeds.conf можно оверрайдить системные фиды своими собственными, дав им такое же название. opkg ругнётся, но проглотит оверрайд, сложив нужный файлик вместо загруженного ранее.
  • Package , имя пакета;
  • Version , версия, при наличии нескольких пакетов с одинаковым именем можно выбрать версию, по умолчанию установится самая свежая;
  • Depends , зависимости от других пакетов, пакетный менеджер доустановит перечисленные пакеты в случае их отсутствия в системе;
  • Filename , путь к файлу относительно базового URL репозитория, обычно репозиторий плоский и всё лежит там же, где и `Packages.gz`;
  • SHA256sum , заявленный репозиторием хэш пакета.

Бинарные пакеты

Бинарные пакеты почти аналогичны пакетам Debian. Разница следующая:

  1. Расширении .ipk вместо .deb .
  2. Упаковывается всё с помощью `tar` и сжимается с помощью gzip , это же справедливо для вложенных архивов. В Debian архив верхнего уровня упаковывается более примитивным ar , а вложенные архивы чаще всего имеют расширение .tar.xz , инструменты используются соответствующие.

Архив data.tar.gz содержит исполняемые файлы, файлы конфигурации и всё, ради чего устанавливается пакет. Если распаковать его в корень ФС, вы получите все ожидаемые файлы на нужных местах, в /usr/bin/ , /etc/ и так далее.

А в control.tar.gz находятся вспомогательные файлы для пакетного менеджера. Это скрипты, которые должны выполняться до или после установки и удаления ( preinst , postinst , prerm , postrm ), сведения о файлах, являющихся конфигурационными, и метаинформация о пакете, во многом повторяющая ту, что содержится в Packages .

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

Сборочная система (она же SDK) выполнена в виде Make-фреймворка. Фреймворк не подразумевает, что вы будете собирать пакеты по отдельности, его основная задача заключается в сборке целых репозиториев.

SDK для x86_64 лежит в git. Есть архив (ссылка скоро устареет, но найти свежий несложно), который сэкономит вам время на компиляции тулчейна для сборки. Внутри особый интерес представляет файл feeds.conf.default . Формат несложный, через пробел:

  1. Ключевое слово src-git . Поддерживается не только git, но сейчас репозиториев в иных VCS нет.
  2. Название фида.
  3. URL git-репозитория, в котором можно указать коммит или тег. Если вы знаете, как называется такая спецификация, подскажите, пожалуйста.

Тестовая сборка

Я попробовал собрать GNU Hello, чтобы проверить, как работает SDK. Это сравнительно монструозный Hello World, написанный в строгом соответствии с гайдлайнами проекта GNU, его единственная задача заключается в иллюстрации этих гайдлайнов. Отдельный репозиторий для него не создавал, а вместо этого «подсунул» в базовые пакеты SDK, откуда и скомпилировал.

Для работы самого SDK в окружениии Debian понадобятся пакеты libncurses-dev (для меню сборки), build-essential (GCC и прочие стандартные зависимости программ на C), gawk , unzip , file , rsync и python3 . Также для создания репозитория из собранных пакетов, потребуется утилита для генерации ключей usign . Её в репозитории нет, поэтому дополнительно потребуется `cmake` для сборки. Этот инструмент можно заменить как на GPG, так и на signify-openbsd , но она рекомендуется и разрабатывается проектом OpenWrt, а также гораздо приятней в использовании.

Компилируем и устанавливаем usign :


Вместо установки ( sudo make install ) можете просто запомнить, где находится бинарь, чтобы в дальнейшем дёргать его руками.

Теперь базовая настройка SDK:


Напоминаю, что вместо клонирования из git, можете скачать и распаковать архив с прекомпилированным тулчейном. Не забудьте только скачать свежую версию!

Выполняя ./scripts/feeds update -a мы клонируем/обновляем все репозитории из feeds.conf(.default), проверяем зависимости и готовим директорию staging_dir/host/bin с исполняемыми файлами (в основном это симлинки на системные утилиты). Следующая команда, ./scripts/feeds install -a , рассовывает симлинки в package/feeds , откуда они и будут браться для компиляции. Эти две команды не обязательны для сборки моего кастомного пакета.

Далее выполняется make menuconfig . Можно пропустить, но при компиляции пакета всё равно выдаст соответствующее окошко. В нём достаточно поменять таргет и сабтаргет, чтобы всё скомпилировалось под x86_64 и выйти, согласившись с сохранением конфига. Также потребуется собрать вспомогательный инструментарий для сборки ( make tools/install ) и тулчейн ( make toolchain/install ). Если вы качали SDK из архива, то make menuconfig вам не покажет опций для выбора таргета, а сборка инструментария и тулчейна не требуется — всё уже есть на месте.

Теперь я создаю директорию package/devel/hello , в которой размещаю Makefile следующего содержания:

В основном всё должно быть понятно без пояснений. Подключаются файлы фреймворка, описываются основные параметры пакета, @GNU подменяется на зеркала проекта GNU (определены во фреймворке), а путь состоит из двух частей: PKG_SOURCE_URL , в котором указывается базовый URL для всех версий и расширяется конкатенацией именем файла из PKG_SOURCE через слэш. В Package/hello/install содержатся инструкции по сборке бинарей в архив data.tar.gz . Дополнительные опции для сборки, если потребуются, доступны в документации. Кстати, не забудьте, что make очень требователен к отступам, у меня вместо начальных пробелов были одиночные табы.

Снова вызываете make menuconfig , проверяете, что в обозначенной секции (Development в моём случае) отмечен пакет hello и выходим сохранив конфиг. Наконец, собираем пакет в три этапа; скачивание, распаковка и собственно компиляция:


В результате я получил пакет bin/packages/x86_64/base/hello_2.9-1_x86_64.ipk . Можно собирать репозиторий. Генерируем пару ключей ( usign -G -c 'openwrt test repo' -s key-build -p key-build.pub , приватный ключ обязательно должен называться `key-build`), и собираем репозиторий: make package/index . На этом этапе сборка может ругнуться на отсутствие usign в директории со вспомогательными утилитами, я решил проблему симлинком: ln -s `which usign` staging_dir/host/bin/usign . Теперь рядом с пакетом лежит полный набор, необходимый для репозитория.

Проверяем репозиторий вместе с пакетом

Вы можете проверить всё на настоящем роутере (не забудьте только выбрать правильный таргет), но я воспользовался Докером. В Докерхабе есть образ OpenWrt для x86_84, который можно запустив, пробросив внутрь контейнера директорию с SDK: sudo docker run -it --name openwrt_test -v $PWD:/opt openwrtorg/rootfs . Потыкайте кнопку ввода пока не появится приглашение Баша.

Копирую ключ из проброшенной директории ( cp /opt/key-build.pub /etc/opkg/keys/usign -F -p /opt/key-build.pub , название ключа обязательно должно совпадать с идентификатором), добавляю свой локальный репозиторий ( echo src/gz local file:///opt/bin/packages/x86_64/base >> /etc/opkg/customfeeds.conf ), обновляю репозиторий ( opkg update ). Вывод начинается с обнадёживающего текста, всё подписано верно:


Осталось только установить и проверить:


Ура, готово! Несмотря на разбросанную по статьям документацию, процесс сборки пакетов довольно прост.

Читайте также: