How To Build Linux Packages For Multiple Platforms Easily

Build Linux Packages

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, 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 operatings systems. If it is not installed already, run the following commands depending upon the distribution you use.

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, install Ruby as shown below.

brew install gnu-tar

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 For Multiple Platforms Easily 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. 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.

rpm -ivh rubygem-json-2.0.3-1.x86_64.rpm

You check the details of newly created .rpm package as below.

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. How cool is that? 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

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

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

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 packaging building 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 networks and support OSTechNix.

Cheers!

Resources:

Thanks for stopping by!

How can I benefit from this blog:

Have a Good day!!