There are numerous Linux distributions, and packaging applications for different Linux distributions is quite time consuming and difficult task. Packaging applications is not that easy for everyone. Luckily, there is an alternative and easiest way to build packages. Meet Fpm (Effing package management), a command-line program that helps to easily build Linux packages.
Using Fpm, you can easily convert a package to different format and install it using the distribution's default package manager.
And yes, Ubuntu's Snaps and flatpaks are rapidly growing and they can be installed on most Linux distributions. But, just in case you want to package an application which is not yet available to your distribution, Fpm is one way to do it.
And, it is lot easier than traditional packaging methods. Fpm is completely free, open source tool written using Ruby programming language.
In this guide, we will be discussing how to build a package using Fpm in Linux.
Table of Contents
Install Fpm in Linux
Since fpm is written using Ruby, you must install Ruby first. Ruby comes pre-installed with some some operating systems. If it is not installed already, run the following commands depending upon the distribution you use.
On Arch Linux and its variants:
$ sudo pacman -S ruby
On Red Hat systems (Fedora 22 or older, CentOS, etc):
$ sudo yum install ruby-devel gcc make rpm-build
On Fedora 23 or newer:
$ sudo dnf install ruby-devel gcc make rpm-build
On Debian-derived systems (Debian, Ubuntu, etc):
$ sudo apt-get install ruby ruby-dev rubygems gcc make rpm
You can also install Ruby using Linuxbrew package manager. To install Linuxbrew on Linux, refer the following guide.
After installing Linuxbrew, run this command to install Ruby.
$ brew install ruby
Once you have installed Ruby, run the following command to install FPM:
$ sudo gem install --no-ri --no-rdoc fpm
You will see an output something like below.
Fetching: cabin-0.9.0.gem (100%) Successfully installed cabin-0.9.0 Fetching: backports-3.6.8.gem (100%) Successfully installed backports-3.6.8 Fetching: arr-pm-0.0.10.gem (100%) Successfully installed arr-pm-0.0.10 Fetching: clamp-1.0.1.gem (100%) Successfully installed clamp-1.0.1 Fetching: ffi-1.9.17.gem (100%) Building native extensions. This could take a while... Successfully installed ffi-1.9.17 Fetching: childprocess-0.6.1.gem (100%) Successfully installed childprocess-0.6.1 Fetching: archive-tar-minitar-0.5.2.gem (100%) Successfully installed archive-tar-minitar-0.5.2 Fetching: io-like-0.3.0.gem (100%) Successfully installed io-like-0.3.0 Fetching: ruby-xz-0.2.3.gem (100%) Successfully installed ruby-xz-0.2.3 Fetching: stud-0.0.22.gem (100%) Successfully installed stud-0.0.22 Fetching: mustache-0.99.8.gem (100%) Successfully installed mustache-0.99.8 Fetching: insist-1.0.0.gem (100%) Successfully installed insist-1.0.0 Fetching: dotenv-2.2.0.gem (100%) Successfully installed dotenv-2.2.0 Fetching: pleaserun-0.0.28.gem (100%) Successfully installed pleaserun-0.0.28 Fetching: fpm-1.8.1.gem (100%) Successfully installed fpm-1.8.1 15 gems installed
To make sure if Fpm is installed correctly, run the following command.
$ fpm --version
Or,
$ fpm --v
Sample output would be:
1.8.1
If you see an output like above, congratulations! Fpm is ready to use.
Build Linux Packages Using Fpm
The typical command to use FPM to build a package is given below:
$ fpm -s <source type> -t <target type> [list of sources]...
Here,
- -s <source type> - The type of the source package. It would be a directory (dir), a rubygem (gem), an rpm (rpm), a python package (python), a php pear module (pear), etc.
- -t <target_type> - type of your output package, like .rpm, .deb etc.
Here is the complete list of source and target file types.
Sources:
- gem
- python modules
- pear
- directories
- tar(.gz) archives
- rpm
- deb
- node packages (npm)
- pacman (ArchLinux) packages
Targets:
- deb
- rpm
- solaris
- freebsd
- tar
- directories
- Mac OS X .pkg files
- pacman (ArchLinux) packages
You can also bring up the help section at any time by typing the following command from the Terminal.
$ fpm --help
Build a RPM package
I am going to show you some examples to understand better. The following command will download latest json gem and convert it to a .rpm package:
$ fpm -s gem -t rpm json
Sample output:
Created package {:path=>"rubygem-json-2.0.3-1.x86_64.rpm"}
The above command will download the latest ‘json’ rubygem from rubygems.org and convert it to a .rpm
package. As you see in the above output, this command has created a package named ‘rubygem-json-VERSION_ARCH.rpm’
with appropriate version/arch in place. Quite easy, isn't it? Of course, it is!
It just took one minute to build this .rpm
package. The packages will be stored in the current working directory. Now, you can install this rpm package on any rpm-based distributions like RHEL, CentOS, Fedora etc as shown below.
$ sudo rpm -ivh rubygem-json-2.0.3-1.x86_64.rpm
You check the details of newly created .rpm package as below.
$ sudo rpm -qip rubygem-json-2.0.3-1.x86_64.rpm
Sample output:
Name : rubygem-json Version : 2.0.3 Release : 1 Architecture: x86_64 Install Date: (not installed) Group : Languages/Development/Ruby Size : 1487109 License : Ruby Signature : (none) Source RPM : rubygem-json-2.0.3-1.src.rpm Build Date : Tue 21 Feb 2017 03:45:50 PM IST Build Host : server1.ostechnix.local Relocations : / Packager : <root@server1.ostechnix.local> Vendor : Florian Frank URL : http://flori.github.com/json Summary : This is a JSON implementation as a Ruby extension in C. Description : This is a JSON implementation as a Ruby extension in C.
As you can see in the above output, fpm automatically picked the package name, version, architecture, install date, maintainer, homepage, and description all from the ruby package itself. You don't need to add anything manually. Fpm will take care of everything.
To view the dependencies, just run:
$ rpm -qRp rubygem-json-2.0.3-1.x86_64.rpm
Sample output
rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) <= 3.0.4-1
Let us see another example.
Build a DEB package
In the above example, we have build json gem and convert it to a .rpm package using:
$ fpm -s gem -t rpm json
Similarly, to make deb a package, just replace the word rpm
with deb
.
$ fpm -s gem -t deb json
Sample output:
Debian packaging tools generally labels all files in /etc as config files, as mandated by policy, so fpm defaults to this behavior for deb packages. You can disable this default behavior with --deb-no-default-config-files flag {:level=>:warn} Debian packaging tools generally labels all files in /etc as config files, as mandated by policy, so fpm defaults to this behavior for deb packages. You can disable this default behavior with --deb-no-default-config-files flag {:level=>:warn} Created package {:path=>"rubygem-json_2.0.3_amd64.deb"}
To check the details of the newly created package, run:
$ dpkg --info rubygem-json_2.0.3_amd64.deb
Sample output:
new debian package, version 2.0. size 581592 bytes: control archive=4018 bytes. 327 bytes, 12 lines control 11986 bytes, 126 lines md5sums Package: rubygem-json Version: 2.0.3 License: Ruby Vendor: Florian Frank Architecture: amd64 Maintainer: <sk@ubuntuserver> Installed-Size: 1640 Provides: rubygem-json Section: Languages/Development/Ruby Priority: extra Homepage: http://flori.github.com/json Description: This is a JSON implementation as a Ruby extension in C
To view the dependencies of the above package, run:
$ dpkg -c ./rubygem-json_2.0.3_amd64.deb
Build a specific version package
All of the previous commands have created the latest stable versions. In case you need to build a specific version package, you can do this using command:
$ fpm -s gem -t deb -v 2.0.0 json
The above command will download rubyjson verion 2.0.0 and convert it to .deb
package.
Sample output:
[...] Created package {:path=>"rubygem-json_2.0.0_amd64.deb"}
Similarly, you can assign a specific name to a package like below.
$ fpm -s gem -t deb -n my_json -v 2.0.0 json
Sample output:
[...] Created package {:path=>"my-json_2.0.0_amd64.deb"}
As you see in the above output, I have assigned a custom name to the package i.e my-json_2.0.0_amd64.deb
.
Convert RPM to DEB packages and vice versa
You don't have to create packages for different platforms. Simply convert them from one format to another. The following command will convert a rpm package into deb package.
$ fpm -t deb -s rpm rubygem-json-2.0.3-1.x86_64.rpm
Please note that I have changed the syntax a little bit. the target type (-t) comes first and source type goes next.
Sample output:
[..] Created package {:path=>"rubygem-json_2.0.3-1_amd64.deb"}
Build packages from a source directory
Here is the simple steps to create an rpm of 'hello' program.
$ wget http://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz
$ tar -zxvf hello-2.10.tar.gz
$ cd hello-2.10/
$ ./configure --prefix=/usr
$ make
Next, install it to a temporary directory as shown below:
$ mkdir /tmp/installdir
$ make install DESTDIR=/tmp/installdir/
Now, make the rpm package using Fpm as below.
$ fpm -s dir -t rpm -n hello -v 2.10 -C /tmp/installdir
Here,
-s
indicates the source file type (directory),-t
is the type of package (rpm),-n
indiactes the name of the package-v
is the version;-C
is the directory (E.g/tmp/installdir
) where fpm will look for the files.
Sample output:
Created package {:path=>"hello-2.10-1.x86_64.rpm"}
To create deb package, run the following command:
$ fpm -s dir -t deb -n hello -v 2.10 -C /tmp/installdir
Similarly, you can build any package from a directory.
Conclusion
Fpm simplifies the process of building packages for multiple distributions without having much programming knowledge. Even an intermediate Linux user can easily build any packages for any platform in no time.
Resources:
1 comment
Hi,
Very useful article
Thanks a lot