Creating the Debian Package – Ubuntu
*******************************************************************************
I will go through 2 different ways – from source code and from Installation directory – of creating Debian Package which based on the software complexity either way might be more apprpriate.
In general regardless of the way we choose for creating the debian package, we need to test and install the software to be sure that everything is Ok. For this purpose we can follow the specific software manual which usually includes following 3 steps:
a) ./configure:
Its a script which is responsible to make your system ready for installation which includes detecting all the dependencies that the software needs (like the system compiler which is usually c/c++) and plus specific requirements like the Installation directory, or different options/configurations of installing the software.
Usually we can see the different configuration options with using help “./configure –help“. It is usually the case that after executing the command, we will see a file configure.* which includes all the options for installing the package. The outcome of the above command is a Makefile which has been written based on our specific configuration.
b) make
Here we can build the software which basically means compiling the program. This runs a series of script (commands) which is inside “Makefile“. Usually by default when we download the source code, we do not have any Makefile, but running the ./configure script will create a customized one for us as I mentioned previously.
In order to use more cores of the system we can use make with -j4 for 4 cores as an example.
c) make install
So here the command will copy all created files (binaries or document) to their final destination based on the default system dir (PATH & MANPATH) or what we have chosen during the ./configure process.
We need to remember where the software files will be installed (copied) which usually can be seen here or at the end of ./configure command.
a. Manually from Source Code
in this way we create a complete debian package completely from source code. We need to copy the software to the proper directory and extract it. We go to the directory that extracted our software. Here I use a simple c program example that you can also easily create.
Mkdir -p /usr/local/testsoftware/testsoftware-2.0
It is very important that our software directory (testsoftware-2.0) has version number which seperated with “-“.
- root@hrouhani:/usr/local/testsoftware/testsoftware-2.0# cat main.c
- #include
- int main (int argc, char *argv[]) {
- printf(“Hi Hossein\n”);
- return 0;
- }
- root@hrouhani:/usr/local/testsoftware/testsoftware-2.0# cat Makefile
- helloworld:
- gcc main.c -o helloworld
- install: helloworld
- install -m 0755 helloworld /usr/local/bin
we can test if all works by first running “make“ and then “make install“.
- root@hrouhani:/usr/local/testsoftware-1.0/bin# ./helloworld
- Hi Hossein
so now we remove the helloword binary files. In case of complex packages, the best is to remove completely the source code and copy/extract again.
Important: In our example, I wrote explicitly the Makefile which is needed to compile our c program. There are lots of packages that do not have Makfile in their source code directory but instead have executable Configure file which automatically create Makefile for us (by using different tools which is listed inside the file). For those packages that has Configure file, we have 2 different possibilities:
a. We create the Makefile ourself manually by executing the ./configure command which enable us to configure specifically and as a result create special Makefile.
b. During package creation, the commands such as dpkg-buildpackage or debuild will call Configure command and will create a Makefile based on default Configuration options which has been listed in Configure command.
First step for creating Deb Package:
We need to create a directory called debian in the source code directory and create different files in it like control, changelog and rules. We can do it manually or we can use a tool like “dh-make“ which does this automatically and we can modify it afterward. [We can install it if we don‘ t have it: apt install dh-make].
Following is an example of running dh-make command which I recommend for beginners:
- root@hrouhani:/usr/local/testsoftware-1.0# dh_make -e hossein.rouhani@hrouhani.org -f ../testsoftware-1.0.tar.gz
Here I create the needed files in debian directory by myself. I create a debian directory inside the software dir and create 3 files which are control, changelog and rules file. Based on the needs and packaging requirements we might need to create other files which I explain later.
- root@hrouhani:/usr/local/testsoftware/testsoftware-2.0# ls
- debian main.c Makefile
Control File
The first file which we need to create is control file:
- root@hrouhani:/usr/local/testsoftware/testsoftware-2.0/debian# cat control
- Source: testsoftware
- Section: utils
- Priority: optional
- Maintainer: Hossein Rouhani Zeidanloo <hossein.rouhani@hrouhani.org>
- Build-Depends: debhelper (>=9)
- Standards-Version: 3.9.6
- Package: testsoftware
- Architecture: any
- Depends: ${shlibs:Depends}, ${misc:Depends}
- Description: simple c program
Description:
Every control file needs to have 2 parts, source and package(binary). Here I have chosen Utils for Section part among many options that is possible. You can find the list of options for Section part easily in Internet.
${shlibs:Depends}: this will automatically figure out the “run time“ dependencies which is important for us when we deploy our package to other systems. It is something like ldd but in more advanced way. For Build dependencies we need to figure it out manually and this is the reason we test completely our package by following the 3 first steps “./configure“, “make & make install“.
${misc:Depends}: Some debheler commands may cause the generated package to depend on some additional packages. All such commands generate a list of required packages for each binary package. This list is used for substituting ${misc:Depends}
Even we can add some more dependencies here at the end of the line:
Depends: ${shlibs:Depends}, ${misc:Depends}, tar, gzip, 7z
We can also specify the Build dependencies in the control file by adding a line in Source part. As an example, we can have following line:
Build-Depends: debhelper (>= 9~), libc….. (the list of all dependencies)
Priority is usually Optional unless it has a conflict with another package and as a result we change the priority to extra.
Changelog
changelog: this file can be created automatically with following command:
root@hrouhani:/usr/local/testsoftware/testsoftware-2.0/ dch –create
and we can modify the content or just create it manually.
- root@hrouhani:/usr/local/testsoftware/testsoftware-2.0/debian# cat changelog
- testsoftware (2.0-1) unstable; urgency=medium
- * Initial release
- — Hossein Rouhani <hossein.rouhani@hrouhani.org> Mon, 29 May 2017 16:44:38 +0200
The important part is “unstable“ instead of “unrealsed“ if it was still there and removing the rest of line “Initial release“ as can be seen above.
Rules:
root@hrouhani:/usr/local/testsoftware-2.0/debian# cat rules
#!/usr/bin/make -f
%:
dh $@
override_dh_usrlocal:
This is very important file which tells debian how to build the package. What I have here is the most simple one which tell pass all calls to the original Makefile which exist/created in the one directory up. There is a tab (space) between dh $@ line
Here I added “override_dh_usrlocal“ in order to overwrite the local directory due to the following error that I had during debian package creation:
dh_usrlocal: debian/testsoftware/usr/local/bin/helloworld is not a directory
Description:
The debian rules is a Make file, and this is the reason we have #!/usr/bin/make -f at the begining of the file. dh command is part of dephelper. We also need to make the rules file executable: chmod +x rules
We also can overwrite the directory that package will be installed (which is usually in Makefile which in our case is inside bin directory of the source code) by defining a rule here:
- root@hrouhani:/usr/local/testsoftware-1.0/debian# cat rules
- #!/usr/bin/make -f
override_dh_auto_configure:
dh_auto_configure — –bindirc=/usr/bin
%:
dh $@
or another way of writting it:
root@hrouhani:/usr/local/testsoftware-1.0/debian# cat rules
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_install:
install -D -m 0755 helloworld $$(pwd)/debian/helloworld/usr/local/bin/helloworld
Compat
root@hrouhani:/usr/local/testsoftware/testsoftware-2.0/debian# cat compat
9
We insert 9 to the compat file in order to tell debhelper to use the lastest version of it.
Install
This is really important in order to include all needed stuff (binary in our case) in debian package. There are 2 ways of doing it:
- Include it in Makefile
- Create a install file in debian directory which I do here
root@hrouhani:/usr/local/testsoftware/testsoftware-2.0/debian# cat install
helloworld /usr/local/bin
Here we tell to debian package creation procedure to include the “hellowold“ from current source code directory (created during Makefile execution) into /usr/local/bin directory during the deb package installation.
If we don‘t run one of the above options, we will get the error of No Binary Package by running lintian as I show later. (W: testsoftware: empty-binary-package).
Creating Debina Package
We have different commands to use in this step. I use “debuild -us -uc“ which will create automatically the tar file of source-code if does not exist in one directory above source code as can be seen here:
testsoftware_2.0-1.tar.gz
another option is to use “dpkg-buildpackage“ command which need to have the tar file already in the above directory.
root@hrouhani:/usr/local/testsoftware/testsoftware-2.0# debuild -us -uc
This package has a Debian revision number but there does not seem to be
an appropriate original tar file or .orig directory in the parent directory;
(expected one of testsoftware_2.0.orig.tar.gz, testsoftware_2.0.orig.tar.bz2,
testsoftware_2.0.orig.tar.lzma, testsoftware_2.0.orig.tar.xz or testsoftware-2.0.orig)
continue anyway? (y/n) y
..
..
Finished running lintian.
We need to take into consideration that above command will install the package in our system beside creating a debian package. It also create several other files as can be seen in the bottom that can be used by other developer to recreate the binary packge such as a debian source code (.dsc) which is useful to figure out all build dependencies.
root@hrouhani:/usr/local/testsoftware# ls
debian testsoftware-2.0 testsoftware_2.0-1_amd64.build testsoftware_2.0-1_amd64.changes testsoftware_2.0-1_amd64.deb testsoftware_2.0-1.dsc testsoftware_2.0-1.tar.gz
we need to make sure that our created debian package has all needed files and directory:
root@hrouhani:/usr/local/testsoftware# dpkg –contents testsoftware_2.0-1_amd64.deb
drwxr-xr-x root/root 0 2017-05-29 19:14 ./
drwxr-xr-x root/root 0 2017-05-29 19:14 ./usr/
drwxr-xr-x root/root 0 2017-05-29 19:14 ./usr/local/
drwxr-xr-x root/root 0 2017-05-29 19:14 ./usr/local/bin/
-rwxr-xr-x root/root 6192 2017-05-29 19:14 ./usr/local/bin/helloworld
drwxr-xr-x root/root 0 2017-05-29 19:14 ./usr/share/
drwxr-xr-x root/root 0 2017-05-29 19:14 ./usr/share/doc/
drwxr-xr-x root/root 0 2017-05-29 19:14 ./usr/share/doc/testsoftware/
-rw-r–r– root/root 153 2017-05-29 16:45 ./usr/share/doc/testsoftware/changelog.Debian.gz
and we can also test it if it can install our binary helloworld in /usr/local/bin directory
root@hrouhani:/usr/local/testsoftware# dpkg -i testsoftware_2.0-1_amd64.deb
#################################################################################
#################################################################################
b. Creating debian Package from Installation directory
Example 1: Qt version 5.8 (https://www.qt.io/download/)
1. we need to install the software in a directory of our interest in a normal way. So this means we will build and install the software completely following 3 steps of Configure, Make and Make install on a specific directory like /urs/local. For this part, I will use qt5.8 package to be installed on Ubuntu 14.04.
Therefore as usuall we do “./configure“ to be used by default configuration options and default installation directory which is /usr/local/Qt-5.8.0. And then “make“ and “make install“. Make sure both make and make install finishes without any Error.
The first step for creating debian package from Installation directory is to create DEBIAN (capital) directory and create a control file inside it. In contrast to creating debian package from source code, here we have only control file which is good enough.
root@hrouhani:/usr/local/Qt-5.8.0/DEBIAN# cat control
Package: qt
Version: 5.8.0
Section: utils
Priority: extra
Maintainer: hrouhani<hossein@hrouhani.org>
Architecture: amd64
Depends: build-essential, flex, gperf, libgstreamer-plugins-base0.10-dev, libasound2-dev, libatkmm-1.6-dev, libbz2-dev, libcap-dev, libcups2-dev, libdrm-dev, libegl1-mesa-dev, libfontconfig1-dev, libfreetype6-dev, libgcrypt11-dev, libglu1-mesa-dev, libgstreamer0.10-dev, libicu-dev, libnss3-dev, libpci-dev, libpulse-dev, libssl-dev, libudev-dev, libx11-dev, libx11-xcb-dev, libxcb-composite0, libxcb-composite0-dev, libxcb-cursor-dev, libxcb-cursor0, libxcb-damage0, libxcb-damage0-dev, libxcb-dpms0, libxcb-dpms0-dev, libxcb-dri2-0, libxcb-dri2-0-dev, libxcb-dri3-0, libxcb-dri3-dev, libxcb-ewmh-dev, libxcb-ewmh2, libxcb-glx0, libxcb-glx0-dev, libxcb-icccm4, libxcb-icccm4-dev, libxcb-image0, libxcb-image0-dev, libxcb-keysyms1, libxcb-keysyms1-dev, libxcb-present-dev, libxcb-present0, libxcb-randr0, libxcb-randr0-dev, libxcb-record0, libxcb-record0-dev, libxcb-render-util0, libxcb-render-util0-dev, libxcb-render0, libxcb-render0-dev, libxcb-res0, libxcb-res0-dev, libxcb-screensaver0, libxcb-screensaver0-dev, libxcb-shape0, libxcb-shape0-dev, libxcb-shm0, libxcb-shm0-dev, libxcb-sync-dev, libxcb-sync1, libxcb-util0-dev, libxcb-xevie0, libxcb-xevie0-dev, libxcb-xf86dri0, libxcb-xf86dri0-dev, libxcb-xfixes0, libxcb-xfixes0-dev, libxcb-xinerama0, libxcb-xinerama0-dev, libxcb-xkb-dev, libxcb-xkb1, libxcb-xprint0, libxcb-xprint0-dev, libxcb-xtest0, libxcb-xtest0-dev, libxcb-xv0, libxcb-xv0-dev, libxcb-xvmc0, libxcb-xvmc0-dev, libxcb1, libxcb1-dev, libxcomposite-dev, libxcursor-dev, libxdamage-dev, libxext-dev, libxfixes-dev, libxi-dev, libxrandr-dev, libxrender-dev, libxslt1-dev, libxss-dev, libxtst-dev, gir1.2-gst-plugins-base-0.10, gir1.2-gstreamer-0.10, libnspr4-dev, x11proto-record-dev
Description: This is a qt5.8 version
As can be seen, the control file only has a Package section. The depends part are all packages that need to be installed on my system before the packed directories of debian package being copied on the destination as I explain later.
So far it looks like this:
root@hrouhani:/usr/local/Qt-5.8.0# ls
bin DEBIAN doc examples include lib libexec mkspecs phrasebooks plugins qml resources translations
In my case, the system has different version of qt and still the qt version that I installed has not appeared in the outcome of following command:
root@hrouhani:/usr/local/Qt-5.8.0# qtchooser -list-versions
default
qt4-i386-linux-gnu
qt4-x86_64-linux-gnu
qt4
qt5-i386-linux-gnu
qt5-x86_64-linux-gnu
qt5
and we can check the default system qt by following command:
root@hrouhani:/usr/local/Qt-5.8.0# qmake -v
QMake version 3.0
Using Qt version 5.2.1 in /usr/lib/x86_64-linux-gnu
to solve the problem we can write a file and put it in /usr/share/qtchooser that let the user to choose it by qtchooser command. Therefore I will create a directory inside Qt-5.8.0 dir that refere to /usr/share/qtchooser directory as can be seen here:
- root@hrouhani:/usr/local/Qt-5.8.0# cat usr/share/qtchooser/qt5.8-x86_64-linux-gnu.conf
- /usr/local/Qt-5.8.0/bin
- /usr/local/Qt-5.8.0/lib
- so now the user has the option of choosing qt5.8 by:
- export QT_SELECT=qt5.8-x86_64-linux-gnu
- and now if we use “qmake -v“ command, we will see
- root@hrouhani:/home/hrouhan# qmake -v
- QMake version 3.1
- Using Qt version 5.8.0 in /usr/local/Qt-5.8.0/lib
OK, let‘s get back to the packing our qt5.8 software into debian package. We can go to the /usr/local/ directory and do following command to create our debian package:
root@hrouhani:/usr/local# dpkg -b Qt-5.8.0/ qt-5.8.0.deb
If you don‘t have root access you can use “fakeroot“ command at the beginning of the above command.
If we install above created debian package in any system, all contents of the package will be installed directly in / directory. Basically from the location that DEBIAN directory is located, everything will be installed based on the created directory from root. In my case, I would like the created debian package will be installed exactly in /usr/local/QT-5.8.0/. So what I need is to create usr/local/QT-5.8.0/ inside the directory that DEBIAN directory is located and rsync all our installation stuff inside.
- root@hrouhani:/usr/local/Qt-5.8.0$ ls
- DEBIAN usr
root@hrouhani:/usr/local/Qt-5.8.0$ cd usr/local/Qt-5.8.0/
so all our installation stuff rsync from /usr/local/Qt-5.8.0 to /usr/local/Qt-5.8.0/usr/local/Qt-5-8.0
so now we can go to /usr/local/ directory and use following command:
root@hrouhani:/usr/local# dpkg -b Qt-5.8.0/ qt-5.8.0.deb
take into consideration that “usr/share/qtchooser/qt5.8-x86_64-linux-gnu.conf“ is inside /usr/local/Qt-5.8.0/usr/local/Qt-5.8.0/usr/share…“, however we can put directly inside /usr/local/Qt-5.8.0/usr/share…“ (both way is working). Which means our new created usr directory has local/Qt-5.8.0/.. and share/.. directory.
Example 2: cloudcompare (https://github.com/cloudcompare/cloudcompare)
Here we do normal installation by following cloudcompare installation guide (/usr/local/cmake/3.2.2/bin/cmake-gui) and then Make and Make Install to create installation directory which is in our case in /usr/local/cloudcompare/2.7
Same as before we create a DEBIAN directory and write a short control file for it as can be seen here.
- root@hrouhani:/usr/local/cloudcompare/2.7/DEBIAN$ cat control
- Package: CloudCompare
- Version: 2.7
- Section: utils
- Priority: extra
- Maintainer: hrouhani<hossein@hrouhani.org>
- Architecture: amd64
- Depends: qt (>= 5.8.0)
- Description: CloudCompare
In order cloudcompare works, we need to have qt also being installed. Therefore we have written qt package as dependency of cloudcompare package.
Similar as before we need to create a debian package that install the cloudcompare on /usr/local/cloudcompare/2.7 directory of the destination systems. So we need to create usr/local/cloudcompare/2.7 directory inside where we have installed our software (/usr/local/cloudcompare/2.7) and move everything (rsync) to the new directory. Beside that we have an executable scripts that need to configure the environment in order cloudcompare works properly. This is just an idea that we have packed the script inside the debian package that being called by running cloudcompare software. (we can also put it somewhere else like in .bashrc or profile.d)
- root@hrouhani:/usr/local/cloudcompare/2.7$ cat usr/bin/CloudCompare
- #!/bin/bash
- export LD_LIBRARY_PATH=/usr/local/QT-5.8.0/lib:/lib/cloudcompare/
- export QT_SELECT=qt5.8-x86_64-linux-gnu
- export QT_QPA_PLATFORM_PLUGIN_PATH=/usr/local/QT-5.8.0/plugins/
- exec /usr/local/cloudcompare/bin/CloudCompare
The libraries that we have referred in above script also being copied into debian package and will be installed together with that.
- root@hrouhani:/usr/local/cloudcompare/2.7$ ls
- DEBIAN lib usr
- root@hrouhani:/usr/local/cloudcompare/2.7$ ls -la lib/cloudcompare/
- total 8284
- drwxrwxr-x 2 hrouhan sundc 4096 May 30 14:19 .
- drwxrwxr-x 3 hrouhan sundc 4096 May 30 15:55 ..
- -rw-r–r– 1 hrouhan sundc 1926736 May 30 14:13 libCC_CORE_LIB.so
- -rw-r–r– 1 hrouhan sundc 3962287 May 30 14:14 libQCC_DB_LIB.so
- -rw-r–r– 1 hrouhan sundc 2542533 May 30 14:15 libQCC_IO_LIB.so
and at the end we can create the debian package by:
root@hrouhani:/usr/local/cloudcompare/ dpkg -b 2.7/ cloudcompare-2.7.deb