
Building library packages for rpm-based Linux distributions
Many of our projects use open-source libraries. When development is carried out for one specific platform, it makes no sense to collect the same libraries from the source every time a new developer connects to the project. In addition, installing libraries a la
As a solution, it is proposed to compile RPM packages from compiled libraries and store them in a single repository, accessible to all developers. Following is instructions and some tips for building packages.
The instruction 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 collect the package from the zeromq library.
The first thing to do before assembly is to make sure that the package you need was not collected by someone before you. Often on resources such as rpmfind.net and rpm.pbone.net you can find what you need. But if you did not find the necessary version of the library or if there is no assembly for your platform, you will have to assemble the package yourself.
Packages are built using the rpmbuild utility . Before using it, you must configure the environment of the assembly. Create the necessary directory tree, for example, in the ~ / rpmbuild directory:
We create the rpmbuild utility configuration file so that it finds out where the created directory tree is located:
rpmbuild at startup will look for package files in the ~ / rpmbuild / BUILDROOT / <package_name> directory. Let's see how RPM packages are named, using the zeromq example:
Here:
Pay attention to the characters separating the fields of the package name. They should be exactly the same as in the example.
So, create a directory for zeromq in BUILDROOT:
Of course, before assembling the binary package, you need to compile the library itself. If the library uses the GNU Autotools build system, this is usually done with the commands:
Now install the library in the directory we created in BUILDROOT:
The DESTDIR parameter is not always processed in the 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 corresponding manual what parameters you need to pass during the assembly in order to install the library in the specified directory.
In RPM packages, in addition to the archived file tree, meta-information about this package is stored. During assembly, it must be specified in the spec-file, which is located in the ~ / rpmbuild / SPECS folder. Consider an example zmq.spec file for the zeromq library:
At the beginning of the file, the minimum set of fields with information about the package is indicated. The name of the package is formed from the values of the first three fields ( Name , Version , Release ), 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 throw 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. Section % post and % postuncontain scripts that are executed 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 (i.e. not in / lib, / usr / lib, / lib64 or / usr / lib64). In this case, the package should provide a configuration file for ldconfig and install it in /etc/ld.so.conf.d. The ldconfig command updates the dynamic loader cache by adding to it all the libraries found in the directories specified in the configuration files.
The % files section lists the files that are packaged in rpm. The % defattr directive specifies default file attributes in the format:
% defattr (, , , )
indicated in octal form, for example, “644” for rw-r - r--. Attributemay be omitted. Instead of attributes that should not change for installed files, you can specify a hyphen. The directories specified in the % files section will be included in the package along with all their contents.
Then the most interesting. In fact, there are two types of library RPM packages. Some of them contain the actual dynamic library files themselves, which are necessary for the programs that are linked with these libraries to work. 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 directiveallows you to build a "child" package with a single run of rpmbuild. The values of the header fields of the child package are inherited from the parent, but you can override them. The Requires field specifies 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. The ld linker needs it at the build stage of the application using the library, because it searches for dynamic library files starting with "lib" and ending with ".so".
There are two things to keep in mind before assembly.
First: if you build the package successfully, rpmbuild will clear the BUILDROOT directory. So just in case, back up your packaged files.
Second: never compile packages with root privileges. It explains why this should not be done.
Now you are ready to build the package. Run rpmbuild:
The -bb option 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.
If you do not know what to write in the header fields of the spec file for the library to be packaged, you can take the RPM package for another distribution package from the above resources and see what they write there:
Here, “q” means “query mode”, “i” means receiving information about the package, “p” means receiving information about the specified package file (without this option, information about the package installed in the system will be received, if installed) .
If you don’t know which files belong to the devel package and which files 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:
The rpm2cpio utility writes to the standard output a cpio archive stored in the rpm package; cpio utility decompresses the archive accepted from standard input. Parameter “i” enables unpacking mode, and “d” creates the necessary directories.
You can see what files the package provides without having to unpack it using the “l” option:
By packing used libraries in RPM, you can save your colleagues from having to download the source code of the necessary version of the library each time, save them from assembly problems (if, for example, you need to apply some patch to the downloaded library sources) and generally unify the process of adding a library into the project. The article does not describe all the intricacies of assembling packages and writing spec-files (such as separating configuration files, documentation, etc.), but by and large this is not necessary for assembling library packages.
make && sudo make install
is considered bad form, because the system is clogged with "ownerless" files, about which there is no information 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. Following is instructions and some tips for building packages.
The instruction 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 collect the package from the zeromq library.
Before assembling the package
The first thing to do before assembly is to make sure that the package you need was not collected by someone before you. Often on resources such as rpmfind.net and rpm.pbone.net you can find what you need. But if you did not find the necessary version of the library or if there is no assembly for your platform, you will have to assemble the package yourself.
rpmbuild
Packages are built using the rpmbuild utility . Before using it, you must configure the environment of the assembly. Create the necessary directory tree, for example, in the ~ / rpmbuild directory:
$ mkdir ~/rpmbuild
$ mkdir ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
We create the rpmbuild utility configuration file so that it finds out where the created directory tree is located:
$ echo '%_topdir %(echo $HOME)/rpmbuild' >~/.rpmmacros
rpmbuild at startup will look for package files in the ~ / rpmbuild / BUILDROOT / <package_name> directory. Let's see how RPM packages are named, using the zeromq example:
zeromq-3.2.4-1.rhel6.x86_64.rpm
Here:
zeromq
- in fact, the name of the packaged software;3.2.4
- software version;1.rhel6
- package build number (release number) - how many times this version of the software was assembled into an rpm package. The rhel6 or el6 suffix is usually provided by packages for Red Hat Enterprise Linux 6;x86_64
- processor architecture for which software is compiled.
Pay attention to the characters separating the fields of the package name. They should be exactly the same as in the example.
So, create a directory for zeromq in BUILDROOT:
$ mkdir ~/rpmbuild/BUILDROOT/zeromq-3.2.4-1.rhel6.x86_64
Library assembly
Of course, before assembling the binary package, you need to compile the library itself. If the library uses the GNU Autotools build system, 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 the 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 corresponding manual what parameters you need to pass during the assembly in order to install the library in the specified directory.
spec file for building the package
In RPM packages, in addition to the archived file tree, meta-information about this package is stored. During assembly, it must be specified in the 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, the minimum set of fields with information about the package is indicated. The name of the package is formed from the values of the first three fields ( Name , Version , Release ), 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 throw 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. Section % post and % postuncontain scripts that are executed 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 (i.e. not in / lib, / usr / lib, / lib64 or / usr / lib64). In this case, the package should provide a configuration file for ldconfig and install it in /etc/ld.so.conf.d. The ldconfig command updates the dynamic loader cache by adding to it all the libraries found in the directories specified in the configuration files.
The % files section lists the files that are packaged in rpm. The % defattr directive specifies default file attributes in the format:
% defattr (
Then the most interesting. In fact, there are two types of library RPM packages. Some of them contain the actual dynamic library files themselves, which are necessary for the programs that are linked with these libraries to work. 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 directiveallows you to build a "child" package with a single run of rpmbuild. The values of the header fields of the child package are inherited from the parent, but you can override them. The Requires field specifies 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. The ld linker needs it at the build stage of the application using the library, because it searches for dynamic library files starting with "lib" and ending with ".so".
Assembly
There are two things to keep in mind before assembly.
First: if you build the package successfully, rpmbuild will clear the BUILDROOT directory. So just in case, back up your packaged files.
Second: never compile packages with root privileges. It explains why this should not be done.
Now you are ready to build the package. Run rpmbuild:
$ cd ~/rpmbuild/SPECS
$ rpmbuild -bb zmq.spec
The -bb option 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 do not know what to write in the header fields of the spec file for the library to be packaged, you can take the RPM package for another distribution package from the above resources and see what they write there:
$ rpm -qip package.rpm
Here, “q” means “query mode”, “i” means receiving information about the package, “p” means receiving information about the specified package file (without this option, information about the package installed in the system will be received, if installed) .
If you don’t know which files belong to the devel package and which files 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 to the standard output a cpio archive stored in the rpm package; cpio utility decompresses the archive accepted from standard input. Parameter “i” enables unpacking mode, and “d” creates the necessary directories.
You can see what files the package provides without having to unpack it using the “l” option:
$ rpm -qlp package.rpm
Total
By packing used libraries in RPM, you can save your colleagues from having to download the source code of the necessary version of the library each time, save them from assembly problems (if, for example, you need to apply some patch to the downloaded library sources) and generally unify the process of adding a library into the project. The article does not describe all the intricacies of assembling packages and writing spec-files (such as separating configuration files, documentation, etc.), but by and large this is not necessary for assembling library packages.