How To Easily Build Linux Packages For Multiple Platforms

There are numerous Linux distributions, and packaging applications for different Linux distributions are quite time consuming and difficult task. Packaging applications is not a piece of cake 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 packages. You can also convert a package to different format, so that the packages can be installed on different kind of Linux operating systems. 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.

Install Fpm

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.

Build Linux Packages For Multiple Platforms Easily Using Fpm

-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. As you see in the above output, this command has created a package named ‘rubygem-json-VERSION_ARCH.deb’ 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.

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. How cool is that? You don’t need to add anything manually. Fpm will take care of everything.

Build a DEB package

To make a DEB package, just replace the word ‘.rpm’ with ‘.deb’. 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, run:

$ 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"}

Build a specific version package

The commands we have seen so far 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

Where -s indicates the source file type (directory), -t is the type of package (rpm), -n indiactes the name of the package and -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.

Also, check a similar tool called ‘Checkinstall’, which is used to build packages from source.

Conclusion

Fpm simplifies the process of building packages a lot easier for multiple distributions without having much programming knowledge. Even an intermediate Linux user can easily build any packages for any platform in no time.

Hope this helps. And that’s all for now. If you find this guide useful, please share it on your social, professional networks and support OSTechNix.