转自:https://linuxconfig.org/how-to-create-an-rpm-package

Rpm is both the package manager and the package format used by many linux distributions such as Fedora, Red Hat and CentOS, to manage and distribute software in binary form.

In this tutorial we will see how to build and package a simple application.

In this tutorial you will learn:

  • What are the basic concepts behind the rpm building process.
  • What is the build environment.
  • What is a specfile.
  • How to use macros inside a specfile.
  • How to install the build dependencies.
  • How to create a specfile.
  • How to build an rpm package.

Software Requirements and Conventions Used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Fedora 29
Software N/A
Other Privileged access to your Linux system as root or via the sudo command to install needed packages.
Conventions # - requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
$ - requires given linux commands to be executed as a regular non-privileged user

Rpm basic concepts

Installing, removing, updating, (in one word, managing) software is an essential task on every operating system. When package managers weren't a thing, the only way to install a program was compiling its source code, and placing the resulting files in the appropriate places on the filesystem. Keeping track of the dependencies of each piece of code was really difficult and time consuming. Then package managers were introduced, and everything became easier.

Each modern Linux distribution has, nowadays, its package manager: Debian and its derivatives uses dpkg, while rpm is used in the Red Hat family of distributions. Software is provided pre-compiled under the form of packages, which are basically compressed archives containing metadata about the software version, its dependencies and possible conflicts with other packages.


In this tutorial we'll see how to create an rpm package starting from an application source code. The application we will package is feh, a simple command line image viewer: it is quite small and has few dependencies. Before starting to build our first package, there are, however, some essential concepts we should grasp.

The build environment

The root of an rpm build environment tree is the rpmbuild directory, which contains 6 subdirectories: BUILDBUILDROOTRPMSSOURCESSPECS and SRPMS. We will see how is possible to generate this environment by launching a simple command; for now, let's just mention the role of these directories. Here is a representation of the working tree:

  rpmbuild
|-- BUILD
|-- BUILDROOT
|-- RPMS
|-- SOURCES
|-- SPECS
|-- SRPMS

Each of these directories, has a specific role in the building process:

  • The BUILD directory is where the source code of the program we want to package is built
  • The BUILDROOT directory is where the files resulting from the compilation of the software inside the BUILD directory are copied, reflecting the structure of the target system inside a subdirectory with the package name: in our case, the "feh" binary that would be installed in /usr/bin will be reported as BUILDROOT/feh-3.0-1.fc29.x86_64/usr/bin.
  • The RPMS directory, is where rpm packages are generated: each rpm will be placed in a subdirectory named after its architecture, or, noarch if it is not architecture-specific.
  • The SOURCES directory hosts the compressed source code of the software we want to package, often under the form of a tarball of a zip file.
  • The SPECS directory, is where we put the .spec file with the instructions to build our package: we will analyze the structure of this file in a moment.
  • The SRPMS directory is the equivalent of RPMS, but for source rpms. This special packages contain the original source code of the application, eventual patches, and the specfile used to build the package.

The spec file

The file where all the instructions and information needed to build an rpm package are defined is the .spec file. A specfile contains, among the other things, the build dependencies (the software needed to compile the program we want to package), the runtime dependencies (the libraries needed for the program to run correctly) and the commands that should be execute to compile the software.


The file is composed by two macro-sections: a preamble and the body. In each of these sections, different instructions can be specified. Let's see some of them. The preamble section can contain the following instructions:

  • Name: The basename of the package (this should match the name of the spec file)
  • Version: The upstream version of the packaged software
  • Release: The release number of the package
  • License: The license used for the software we want to package
  • Url: The upstream URL of the software
  • Source0: The direct URL or the path of the software's compressed source code (tarball or zipped file)
  • /lib>

  • BuildArch: The architecture of the package: if no architecture is specified the one of the host system will be used
  • BuildRequires: The dependencies needed to build the software
  • Requires: The dependencies needed to run the software

The body section of the specfile, typically contains the following sections:

  • %description: An optionally multi-line description of the software packaged
  • %prep: The command(s) needed to prepare the source code (for example, the commands needed to extract a tarball)
  • %build: The command(s) needed to build the software
  • %install: The command(s) needed to copy the file resulting from the build process to the BUILDROOT directory
  • %files: The list of the files provided by the package, which will be installed on the system

Macros

To ease our job, inside a specfile, we can use some macros which let us reference many useful things and automatically perform certain tasks. First of all we have the RPM directory macros which let use reference the directories of our build environment; we should always use them instead of direct paths:

  • %{_topdir}: This macro references the rpmbuild directory
  • %{_builddir}: References the BUILD directory inside our build tree
  • %{_rpmdir}: References the path of the RPMS directory
  • %{_sourcedir}: This macro is evaluated to the path of the SOURCES directory
  • %{_specdir}: A macro which represents the path of the SPECS directory
  • %{_srcrpmdir}: References the path of SRPMS directory
  • %{_buildrootdir}: References the path of the BUILDROOT directory

Other macros let us reference the most important directories in the our machine filesystem, for example:

  • %{_sysconfigdir}: The /etc directory
  • %{_prefix}: The /usr directory
  • %{_bindir}: The /usr/bin directory
  • %{_mandir}: The path to the /usr/share/man directory

The one above, is not a complete list, but it gives you an idea. Additionally we can also use a set of macros which perform specific tasks. To expand the definition of a macro, and so to see its content, we can use the rpm --eval command, which takes the macro as its argument. Here are some examples of frequently used macros:


  • The %setup macro, is used in the %config section of the specfile, and basically performs the following actions:
    1. Extracts the source code of the program we want to package into the BUILDDIR directory
    2. Switches into the extracted directory
    3. Sets the appropriate file permissions inside of it
  • The %{make_build} macro is used in the %build section of the specfile, and basically runs the make command with a predefined sets of options, to compile the source code of the software. If we expand it, we can check the command it runs:
    $ rpm --eval "%{make_build}"
    /usr/bin/make -O -j4
  • The %{make_install} macro, instead, is used in the %install section of the file and runs make install with the DESTDIR parameter, used to instruct the command to install the compiled files relatively to a given directory instead of the real system /:
    $ rpm --eval "${make_install}"
    /usr/bin/make install DESTDIR=/home/egdoc/rpmbuild/BUILDROOT/%{NAME}-%{VERSION}-%{RELEASE}.x86_64 INSTALL="/usr/bin/install -p"

How to create an rpm package step by step instructionsNow that we learned the basic concept of the package building process, we can see how to create our build environment and our first rpm package. Let's create our package.

Install the build dependencies

As a first thing, we need to install rpmdevtools, plus the dependencies needed to build feh:

$ sudo dnf install rpmdevtools gcc make imlib2-devel libjpeg-devel libpng-devel libXt-devel libXinerama-devel libexif-devel \
perl-Test-Command perl-Test-Harness libcurl-devel

Once the packages are installed, we can generate our build environment. All we have to do is to launch the following command:

$ rpmdev-setuptree

At this point the rpmbuild directory, and all the subdirectories we saw before, should be created. The next step is to write our specfile.

Create the specfile

We create the specfile with our favorite text editor, and save it in the SPECS directory with the same name of the package. Here is how a minimal specfile should look like:

Name:           feh
Version: 3.0
Release: 1%{?dist}
Summary: Fast command line image viewer using Imlib2
License: MIT
URL: http://feh.finalrewind.org
Source0: http://feh.finalrewind.org/feh-%{version}.tar.bz2 BuildRequires: gcc
BuildRequires: imlib2-devel
BuildRequires: libcurl-devel
BuildRequires: libjpeg-devel
BuildRequires: libpng-devel
BuildRequires: libXt-devel
BuildRequires: libXinerama-devel
BuildRequires: libexif-devel
BuildRequires: perl-Test-Command
BuildRequires: perl-Test-Harness %description
Fast command line image viewer using Imlib2 %prep
%setup -q %build
%{make_build} %install
%{make_install} PREFIX=%{_prefix} %files
/usr/bin/feh
/usr/lib/debug/usr/bin/feh-3.0-1.fc29.x86_64.debug
/usr/share/applications/feh.desktop
/usr/share/doc/feh/AUTHORS
/usr/share/doc/feh/ChangeLog
/usr/share/doc/feh/README.md
/usr/share/doc/feh/TODO
/usr/share/doc/feh/examples/buttons
/usr/share/doc/feh/examples/find-lowres
/usr/share/doc/feh/examples/keys
/usr/share/doc/feh/examples/themes
/usr/share/feh/fonts/black.style
/usr/share/feh/fonts/menu.style
/usr/share/feh/fonts/yudit.ttf
/usr/share/feh/images/feh.png
/usr/share/feh/images/feh.svg
/usr/share/feh/images/menubg_default.png
/usr/share/icons/hicolor/48x48/apps/feh.png
/usr/share/icons/hicolor/scalable/apps/feh.svg
/usr/share/man/man1/feh.1.gz

Let's analyze it. First, we specified some basic information about the software we want to package: its name and upstream version, its license, the location of the project main page, and the direct link to the source code tarball, then we declared the build dependencies using BuildRequires. The list of dependencies can be represented as a space or comma separated inline list, but for the sake of readability we declared one dependency per line, repeating the BuildRequires instruction.


After declaring the dependencies needed to build the software, we provided a brief description in the %description section, and than proceeded to the most important part of the specfile: the instructions to prepare, build and install the software, respectively in the %prep%build and %install sections.

In the %prep section, providing the %setup -q macro has been enough: as said before, this macro will run the commands needed to unpack the source tarball and place the extracted directory into the BUILD folder

The %build section is where we specify the commands that should be run to build the source code. Even here, all we had to use was just the %{make_build} macro, which runs the make command with the options we saw before, into the directory hosting the unpacked source code of the application we want to package.

In the %install section, we used another macro, %{make_install}, providing also the PREFIXparameter, setting it to %{_prefix}, which will be expanded into /usr. The resulting command will cause the files produced by the compilation of the source code, to be placed in the "fake root", set with the DESTDIR parameter contained in the macro. Since in the %{make_install} macro, "DESTDIR" is set to /home/egdoc/rpmbuild/BUILDROOT/%{NAME}-%{VERSION}-%{RELEASE}.x86_64, the files will be installed under: /home/egdoc/rpmbuild/BUILDROOT/%{NAME}-%{VERSION}-%{RELEASE}.x86_64/usr.

Finally, we provided, in the %files section, a list of the files which will be installed by our package. This list could be later inspected by running the rpm -qlp /path/to/the/rpm command or, if the package is already installed, by simply running rpm -ql packagename.

Get the sources and build the rpm package

Now that our spec file is finally ready, we can build our rpm. You may notice we didn't download the source tarball of "feh" yet: there is no need to do this manually, since we can use the spectoolcommand:


$ spectool -g -R ~/rpmbuild/SPECS/feh.spec
Getting http://feh.finalrewind.org/feh-3.0.tar.bz2 to /home/egdoc/rpmbuild/SOURCES/feh-3.0.tar.bz2
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 185 100 185 0 0 898 0 --:--:-- --:--:-- --:--:-- 898
100 2057k 100 2057k 0 0 1988k 0 0:00:01 0:00:01 --:--:-- 4191k

This command will download the sources we referenced with a URL inside the specfile, in the appropriate directory of our working tree: ~/rpmbuild/SOURCES. With the sources in place, we can build our rpm: all we have to do is to launch the rpmbuild command, and provide the path to the specfile. When launched with the -bb option, rpmbuild will build only a binary package: if we want to generate also a source rpm, we must use -ba instead (consult the rpmbuild manpage for an overview of the possibile options).

One very important thing to remember is that the rpmbuild command should never be launched with root permissions: when doing so, even a simple error in the specfile could produce unwanted effects on our system. Let's run rpmbuild:

$ rpmbuild -bb ~/rpmbuild/SPECS/feh.spec

The output of the performed operations will be printed onscreen, and, if everything goes as expected, the rpm package will be generated inside the RPMS directory.

ConclusionsIn this tutorial we learned the fundamental concepts involved in the creation of an rpm package. We learned some macros, and how to build a

.spec file, which contains all the needed instructions for the building process. We also provided an actual example, building and packaging feh, a simple command line image viewer. I suggest you to consult the official Red Hat packaging guide to further expand the concepts mentioned in this tutorial.

 
 
 
 

How to create an rpm package的更多相关文章

  1. DIY的RPM包怎么签名呢 How to sign your custom RPM package with GPG key

    https://gist.github.com/fernandoaleman/1376720  How to sign your custom RPM package with GPG key 这是文 ...

  2. YUM安装MONGODB发生Error in PREIN scriptlet in rpm package mongodb-enterprise-server-4.0.2-1.el6.x86_64错误

    YUM安装MONGODB发生Error in PREIN scriptlet in rpm package mongodb-enterprise-server-4.0.2-1.el6.x86_64错误 ...

  3. How to create Web Deployment Package and install the package

    Create Web Deployment Package To configure settings on the Connection tab In the Publish method drop ...

  4. 错误:Could not create the Android package. See the Output (Build) window for more details

    错误:Could not create the Android package. See the Output (Build) window for more details. Mono For An ...

  5. RPM Package Manager

    本文大部分内容来自鸟哥的Linux私房菜,并且由作者根据自己的学习情况做了一些更改,鸟哥原文链接 1. 程序的安装方式 源代码安装:利用厂商释出的Tarball 来进行软件的安装,每次安装程序都需要检 ...

  6. ubuntu install rpm package

    Using command 'alien' instead of 'rpm'. sudo apt-get install alien alien -i tst.rpm 'man alien' for ...

  7. create a inatll package

    gcc -o hell t.c tar -jxf  hell.tar.bz2 [root@localhost ~]# cat install.sh #!/bin/bashlines=7tail -n ...

  8. 【ros】Create a ROS package:package dependencies报错

    $rospack depends1 beginner_tutorials 报错:Erros:could notn call python function 'rosdep2.rospack.init_ ...

  9. yum卸载失败Error in PREUN scriptlet in rpm package postgresql-server

    yum --setopt=tsflags=noscripts remove 参考 https://serverfault.com/questions/613256/yum-error-in-preun ...

随机推荐

  1. 【Core】.NET Core 部署( Docker + CentOS)

    CentOS 下 Docker安装 使用脚本安装 Docker (1)安装docker  sudo yum install docker (2)启动docker systemctl  start do ...

  2. win平台下Path变量消失问题

    解决方法:2019.01.10文章转载自 李北北:https://www.jianshu.com/p/b89f0c99867e 问题描述:修改了path变量,但是环境变量中path消失,于是想再次打开 ...

  3. ES6 新加的类型Symbol()

    Symbol()如果一个对象中的键已经存在,但目前我们目前不知道这个键是存在的,然后我们去给这个键赋值,Symbol()就不会改变这个键对应的值

  4. 【JS】【5】request.getHeader("referer")的作用

    正文: request.getHeader("referer"):获取来访者地址 注意:只有通过链接访问当前页的时候,才能获取上一页的地址,以下情况是获取不到值的: 只有通过链接访 ...

  5. restore not found的错误

    tensorflow保存模型后,restore的时候报参数not found是什么原因呢 一般预测的流程是:建图然后restore参数,很有可能你的变量作用域和train的时候不一样,那么在现在的变量 ...

  6. git创建分支提交到远程分支步骤

    git创建分支提交到远程分支步骤 step1,在本地新建分支() git branch newbranch step2:把本地分支push到远程 git push origin newbranch s ...

  7. IDA Pro安装教程

    1.下载 http://tools.pediy.com/windows/disassemblers.htm 我们这里选择6.8版本下载 2.安装 打开下载的安装包,解压出来进入IDAPro68文件夹, ...

  8. BootCamp 在MacBook 上安装Win10

    首先到网上下载win10的ISO光盘, 制作win10安装盘时,一直停在copy文件.最后文件还是没有copy完整. 需要手工把iso里的文件拷贝到U盘里. 否则提示source\install.wi ...

  9. Vue(五) 购物车案例

    这一篇把之前所学的内容做一个总结,实现一个购物车样例,可以增加或者减少购买数量,可移除商品,并且购物车总价随着你的操作实时变化. 实现效果如图: 代码: <!DOCTYPE html> & ...

  10. php intval 两位小数乘以100后结果少1

    价格处理的时候往往是两位小数需要换算成分,如:16.33元换算为1633分,直接乘以100也就行了的,但是又使用了一个转换为整数类型的函数intval() 这下子结果就不对了,如图:  结果:  可以 ...