From the course: Building, Maintaining, and Distributing RPM Packages

Package metadata and spec files

- [Instructor] If you look at many prepackaged products in the real world, there are three major kinds of information on the label. There's the name and information about the product, directions for its use, and a list of ingredients. Take, for example, a bottle of cold brewed coffee. The label shows us what the product is and who made it, and there's probably a description about the bright notes and satisfying smoothness, the futures we expect to experience when using the product. There's some directions or information telling us how to use the product, as well, maybe telling us to mix it with equal parts water or oat milk. And there's a list of specific things the product contains, things like water, 100% Arabica coffee, and maybe a little bit of sugar. Package builders provide this meta data for packages they create and they define how package-building software uses or assembles the files a package contains by creating a spec file. For software developers, the most important part of a package is probably the code they crafted in order to make something new. But for packagers, a role that often falls to system administrators, the most important part of a package is the spec file. The spec file is a text file that's divided into two parts called the preamble and the body. In the preamble, we can define macros or variables that we'll use throughout the body and this is where some of the user-facing information about the package is defined. The body contains a series of sections, each starting with a percent sign. For the most part, these sections act as instructions for the software that reads the spec file and builds the package, though some of it is intended for use by the user and by later package maintainers. Let's focus on the preamble for a moment. The name of a package is very important and so are the version number and release. The package manager uses this information to determine if a package is installed and whether it can be updated, so the name of the package should not change over time. Otherwise, the package manager will consider it an entirely different package. That's why we separate the name from the version and why it's really important to consider the name of your package and ensure that it can remain the same, and that it doesn't conflict with other packages that your users are likely to use. The version number indicates the progress of work done on the programmer package. Version numbers for packages are generally two or three number separated by dots, usually called the major, minor, and patch versions going left to right. Most of the time, it's up to a package developer or software developer to decide what meaning to give each of these levels, and what the criteria are for incrementing the numbers. As new functionality is added to a package, the numbers should be incremented or rolled over, as necessary, before the package is rebuilt. The release indicates how many times the current version has been released. For example, if you fixed a bug in your package, that might not merit a change to the version number because you haven't added new features. The first release of a new version of the package will be labeled one. The second, after you fix a bug or update something minor would be two, and so on. And the release often uses a macro, as we'll see here, to indicate the platform for which the package is built. These macros act as variables that we can use throughout the spec file, wherever we need a predefined value. Using macros saves typing and dramatically reduces the opportunity for errors, especially as a spec file becomes more complex. For example, you've just update the version of the package at the top of the spec file, and wherever else in the file the version macro's called, it'll reflect the new version. There are a few different kinds of macro, some of which come from the system or package manager, things like dist and others we'll see later, and we can also define our own. For more information about macros, I encourage you to take a look at the RPM user documentation, here. We can use the RPM tool to explore what value macros have on a given system. One we'll see a lot is percent, opening curly brace, question mark, dist, closing curly brace and it stands for the distribution code. Here, on the terminal, I'll run RPM--eval and the macro and I can see that I get EL8, short for enterprise linux 8 because I'm running sim files 8. If you're in fedora, you'd see FC and a number. Packages are built for specific platforms and that's what this dist variable represents. In the preamble, the Summary field gives us a place to provide a short, one line description of the package. The License and URL fields are where we indicate the license and informational website for the package, and the Source directive gives us a place to provide links to the source code that a package is built from. BuildArch is where we define what process or architecture our package targets and if it's a binary package that doesn't involve executables, we can set this to Noarch, for no architecture. BuildRequires is where we tell the package building software what it will need to have in order to compile the source code we provide. And Requires is where we tell the package manager what software the package will need in order to run successfully on target systems. BuildRequires and Requires can be repeated as many times as necessary to provide additional package names. And Source, as we can begin to see with the first invocation can be extended with numbers to provide links for additional source files. Moving into the body, the description directive gives us an opportunity to write a longer narrative about what the package does. This will show up along with the summary, name, and version when a user searches for a package, or uses tools like RPM to investigate a package. Following the description, we get into sections that tell the package building software what to do. Generally speaking, these are sections named prep, build, and install. Prep tells the package building software how to set up the build environment in order to compile our software. Build provides the instructions to build the software. And install tells the package building software where to put files in the directory tree of the buildroot system, which is what ultimately is copied into place on the client or user's file system, and the files section provides a list of all the files that the package will install and be responsible for. It's common to use macros here, to save typing and avoid errors. The file paths come from the buildroot directory and correspond to where files will be placed relative to the root file system on target machines. There is also a changelog section where the package maintainer can provide information about what has changed between versions or releases of the software. We'll see more about these sections when we go to build packages and also when we explore existing packages. Where the spec file and therefore, the metadata for a package are critical, the bulk of the RPM package is the archive of included files. But unlike with the spec files, the creation of the archive is handled for us so we really don't have to worry too much about what's going on there. When we compose a package, the RPM dev tools will create this archive which will either contain a compressed part file, other assets, and a spec file in the case of a source package, or a copy of the buildroot system in the case of a binary package. In either case, the RPM package manager can extract files from the archive at the time of installation. And as we'll see in a little bit, we can extract the contents of packages, ourselves, too. There's a lot to know about spec files and macros and for our purposes here, we'll stick to pretty basic spec files using commonly used macros. Spec files are extremely flexible, though, so as your packaging needs become more complex be sure to spend some time with the RPM documentation to find out how to do what you need.

Contents