📜 ⬆️ ⬇️

Build library packages for rpm-based Linux distributions

Many of our projects use open-source libraries. When development is carried out under one specific platform, it makes no sense to collect the same libraries from source codes each time a new developer joins the project. In addition, installing libraries a la make && sudo make install is considered bad form because the system is clogged with orphan files that are not listed in the RPM package manager database.

As a solution, it is proposed to compile RPM packages from compiled libraries and store them in a single repository accessible to all developers. Below are instructions and some tips for building packages.

The tutorial will be based on the example of Red Hat Enterprise Linux 6, but with minor changes it can be adapted for other distributions. For example, we will build a package from the zeromq library.

Before building the package


The first thing to do before assembling is to make sure that the package you need is not collected by someone before you. Often you can find what you need on resources such as rpmfind.net and rpm.pbone.net . But if the necessary version of the library was not found or if there is no assembly for your platform, then you will have to build the package yourself.
')
rpmbuild

Packages are built using the rpmbuild utility. Before using it, you must configure the build environment. Create the necessary directory tree, for example, in the ~ / rpmbuild directory:

 $ mkdir ~/rpmbuild $ mkdir ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} 

Create the rpmbuild utility configuration file so that it finds out where the created directory tree is:

 $ echo '%_topdir %(echo $HOME)/rpmbuild' >~/.rpmmacros 

rpmbuild at startup will search for package files in the ~ / rpmbuild / BUILDROOT / <package_name> directory. Let's look at how RPM packages are named, using the zeromq example:

zeromq-3.2.4-1.rhel6.x86_64.rpm

Here:

Notice the signs separating the package name fields. They should be exactly as in the example.

So, create a directory for zeromq in BUILDROOT:

 $ mkdir ~/rpmbuild/BUILDROOT/zeromq-3.2.4-1.rhel6.x86_64 

Build a library

Of course, before building a binary package, you need to compile the library itself. If the library uses the GNU Autotools build system, then this is usually done with the commands:

 $ ./configure $ make 

Now install the library in the directory we created in BUILDROOT:

 $ make install DESTDIR="$HOME/rpmbuild/BUILDROOT/zeromq-3.2.4-1.rhel6.x86_64" 

The DESTDIR parameter is not always processed in makefiles. For example, qmake generates makefiles that ignore this parameter. If the library uses an assembly system other than GNU Autotools, then read in the appropriate manual what parameters need to be passed during assembly to install the library in the specified directory.

package spec file


In RPM-packages in addition to the archived tree of files is stored meta-information about this package. When building, it should be specified in a spec file, which is located in the ~ / rpmbuild / SPECS folder. Consider an example zmq.spec file for the zeromq library:

 Name: zeromq Version: 3.2.4 Release: 1.rhel6 Summary: Software library for fast, message-based applications Packager: My organization Group: System Environment/libraries License: LGPLv3+ with exceptions %description The 0MQ lightweight messaging kernel is a library which extends the standard socket interfaces with features traditionally provided by specialized messaging middle-ware products. 0MQ sockets provide an abstraction of asynchronous message queues, multiple messaging patterns, message filtering (subscriptions), seamless access to multiple transport protocols and more. This package contains the ZeroMQ shared library for versions 3.x. %post /sbin/ldconfig %postun /sbin/ldconfig %files %defattr(-,root,root) /usr/lib64/libzmq.so.3 /usr/lib64/libzmq.so.3.0.0 %package devel Summary: Development files for zeromq3 Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description devel The zeromq3-devel package contains libraries and header files for developing applications that use zeromq3 3.x. %files devel %defattr(-,root,root) /usr/include /usr/share /usr/lib64/pkgconfig /usr/lib64/libzmq.so /usr/lib64/libzmq.a /usr/lib64/libzmq.la 

At the beginning of the file indicates the minimum set of fields with information about the package. From the values ​​of the first three fields ( Name , Version , Release ) the name of the package is formed, so it is important that the correct values ​​are indicated there. If the values ​​do not match the name of the directory with the file tree of the package being built, rpmbuild will generate an error. The License field is also required - without it, rpmbuild will refuse to build the package.

The purpose of the % description section is obvious. The % post and % postun sections contain scripts that run after installing the package files into the system and after removing the package files from the system, respectively. This is useful if the package installs dynamic libraries (.so) in non-standard directories (that is, not in / lib, / usr / lib, / lib64 or / usr / lib64). In this case, the package must provide a configuration file for ldconfig and install it in /etc/ld.so.conf.d. The ldconfig command refreshes the dynamic loader cache by adding all the libraries found in the directories specified in the configuration files.

The % files section contains a list of files that are packaged in rpm. The % defattr directive specifies the default file attributes in the format:

% defattr (<file mode>, <user>, <group>, <dir mode>)

<file mode> is indicated in octal, for example, "644" for rw-r - r--. The attribute <dir mode> may be omitted. Instead of attributes that should not change for the files to be installed, you can specify a hyphen. The directories specified in the % files section will be included in the package along with all their contents.

Next is the most interesting. In fact, there are two types of library RPMs. Some of them contain the actual dynamic library files themselves, which are necessary for the work of programs that are linked with these libraries. For example, the zeromq-3.2.4-1.rhel6.x86_64.rpm package provides only two files: /usr/lib64/libzmq.so.3.0.0 and a symbolic link to it, /usr/lib64/libzmq.so.3. Another type of package contains the files necessary for developing applications using the provided library. The suffix "-devel" is added to the name of such packages, for example, zeromq-devel-3.2.4-1.el6.x86_64.rpm. Such packages usually contain C / C ++ header files, documentation, static libraries (.a), and these packages are dependent on packages of the first type.

In the spec file above, the % package directive allows you to build a “child” package with one single run of rpmbuild. The values ​​of the header fields of the child package are inherited from the parent, but they can be overridden. The Requires field defines an additional dependency on the parent package. Note that the % files section of the zeromq-devel package contains the file /usr/lib64/libzmq.so. This is a symbolic link to a real dynamic library file. It is necessary for the ld linker at the stage of building an application using the library, since it searches for dynamic library files starting with “lib” and ending with “.so”.

Assembly


Two things to keep in mind before assembling.
First, if the rpmbuild package is successfully built, it will clear the BUILDROOT directory. So just in case, back up the packaged files.
Second: never build packages as root. It explains why you should not do this.

Now everything is ready to build the package. Run rpmbuild:

 $ cd ~/rpmbuild/SPECS $ rpmbuild -bb zmq.spec 

The -bb parameter means “build binary”, that is, build a binary package. In addition to binary packages, there are also source packages, but they are not discussed here.

If successful, the resulting rpm-package will be saved in the RPMS folder.

Couple of tips


If you don’t know what to write in the header fields of the spec file for the library being packaged, you can take an RPM package for another distribution from the above resources and see what they write there:

 $ rpm -qip package.rpm 

Here "q" means "query mode (query)", "i" - getting information about the package, "p" - getting information about the specified package file (without this option you will get information about the package installed in the system, if it is installed) .

If you do not know which files belong to the devel package and which ones belong to the library package, but you have both packages for another distribution, you can unpack the tree of files provided by this package into the current directory:

 $ rpm2cpio package.rpm | cpio -di 

The rpm2cpio utility writes a standard cpio archive stored in an rpm package; The cpio utility unpacks the archive taken from the standard input. The “i” parameter turns on decompression mode, and “d” creates the necessary directories.

You can see which files are provided by the package without unpacking it using the “l” option:

 $ rpm -qlp package.rpm 

Total


Packing the used libraries in RPM, you can save your colleagues from having to download the source code of the required version of the library each time, save them from problems during the build (if, for example, you need to apply a patch to the downloaded library sources) and generally unify the process of adding the library in the project. The article does not describe all the subtleties of building packages and writing spec files (for example, the separation of configuration files, documentation, etc.), but to build library packages this, by and large, is not necessary.

Source: https://habr.com/ru/post/246177/


All Articles