Home Package management How To Easily Build Linux Packages Using Fpm For Multiple Platforms

How To Easily Build Linux Packages Using Fpm For Multiple Platforms

By sk
Published: Last Updated on 6.1K views

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.

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:

You May Also Like

1 comment

Jalal April 20, 2020 - 9:33 am

Hi,
Very useful article
Thanks a lot

Reply

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

This website uses cookies to improve your experience. By using this site, we will assume that you're OK with it. Accept Read More