Create ubuntu packages

Introduction

In this tutorial I will try to explain, how to create a debian package for ubuntu.

Note: Anywhere “mupengui” is used, use your own project name.

1. Install necessary packages.

$ sudo apt-get install build-essential autoconf automake autotools-dev dh-make debhelper devscripts fakeroot xutils lintian pbuilder cdbs

2. Create your project

Inside a directory (say mupengui-0.1) create following files. Use your favorite text editor to create and edit these files (copy-paste following texts).

a. CMakeLists.txt
cmake_minimum_required(VERSION 2.8.9)
project(mupengui)
find_package(Qt5Widgets REQUIRED)
add_executable(mupengui main.cpp)
install(TARGETS mupengui RUNTIME DESTINATION bin)
qt5_use_modules(mupengui Widgets)
Little tip for real Qt creator created projects (you can escape this for this tutorial)
—————————————————————————————————————————————————

If you had other files (e.g ui files, other generated cpp files you would have a line as this one for add_executable)

add_executable(mupengui main.cpp mainwindow.cpp settingsdialog.cpp moc_mainwindow.cpp moc_settingsdialog.cpp)

Note: If you use Qt creator, you generally don’t have moc_yourwindow.cpp file or ui_yourwindow.h files in your source directory. You have to copy them from your build directory to your source directory and adjust the headers in those files.

E.g In moc_mainwindow.cpp I had to change the first line of header to

#include "mainwindow.h"

Warning: After you copy these IDE generated files to your source directory, don’t run “qmake” and “make clean” in these directories, because “make clean” deletes these build generated files. This is very important. Also, make sure there is no executable binary of your application in the source directory.

—————————————————————————————————————————————————

Back to our tutorial. For this tutorial we will use cmake instead of qmake.

b. Create a simple source file (main.cpp)

Note: To make this tutorial easy to follow, I will use very basic source code.

#include <QApplication>
#include <QMessageBox>
int main(int argc, char * argv[])
{
 QApplication app(argc, argv);
 Q_UNUSED(app)
 QMessageBox::information(0, "Example", "Hello, world!");
 return 0;
}

To test if the source code works, create a directory called build, inside your source directory, go inside it and make the application, run it, come back to parent directory and remove the build directory. Here is the process.

$ mkdir build
$ cd build
$ cmake ..
$ make
$ ./mupengui
$ cd ..
$ rm -rf build

build image

3. Add user identification to your build

Write following text at the bottom of ~/.bashrc (/home/username/.bashrc) file.

export DEBFULLNAME="Your Name"
export DEBEMAIL="you@example.com"

Note: This email and name will be used everywhere in this tutorial, choose the one you will use for development.

Run following command or close and open a new terminal

$ source ~/.bashrc

4. Icon and launcher

We will create two more files, before we create an archive file (tar.gz).

a. mupengui.png

Create an icon (image file) using inkscape of size 128×128.

b. mupengui.desktop
[Desktop Entry]
Name=Mupen GUI
Comment=Play Nintendo 64 ROM files
Exec=mupengui
Terminal=false
Type=Application
StartupNotify=true
Icon=mupengui
Categories=GNOME;GTK;Game;
MimeType=application/x-n64-rom;

Most variables in this file are self explanatory. Exec is used to run your application, MimeType is not required for this project (you may remove it for this tutorial).

5. Create a source archive file

At this stage you should have a source file (main.cpp), a cmake file (CMakeLists.txt), an icon (mupengui.png) and a desktop file (mupengui.desktop) in your project working directory.

$ cd ..
$ tar -czf mupengui_0.1.orig.tar.gz mupengui-0.1

Don’t delete this file between subsequent builds.

6. Creating stub files for packaging

Note: DEBFULLNAME and DEBEMAIL variables we created above, will be used here.

Run following commands

 $ cd mupengui-0.1
 $ dh_make

Since we only have a single binary in our application, we will choose “s” as next option. It then shows all the information like Date, Maintainer Name, Email-Address etc, press Enter to confirm.

This command creates a debian sub directory for us. We need to modify certain files inside it, to create our debian files. Before that, we need to remove files that are not important.

$ cd debian/
$ ls
changelog init.d.ex mupengui.cron.d.ex preinst.ex source
compat manpage.1.ex mupengui.default.ex prerm.ex watch.ex
control manpage.sgml.ex mupengui.doc-base.EX README.Debian
copyright manpage.xml.ex postinst.ex README.source
docs menu.ex postrm.ex rules
$ cp postinst.ex /tmp
$ rm *.ex *.EX
$ rm docs README.*
$ mv /tmp/postinst.ex ./postinst

If you need files, that are important for doing extra things during installation, you should keep them. In my particular case, I kept postinst because I had to register application/x-n64-rom mime type (remember MimeType in desktop file?). For this tutorial, you don’t need to keep postinst file. Though, I will later show (7.d) what text goes into postinst (just in case you need one).

Create a file called mupengui.install with following text

mupengui.desktop usr/share/applications
mupengui.png usr/share/pixmaps

7. Configure packaging files.

a. changelog

Your changelog file should already have some information based on DEBFULLNAME and DEBEMAIL variables we created above. However, since qt5 is not present in repository before raring (if we don’t use a ppa), we have to configure some values based on that information. Make changelog file look like this.

mupengui (0.1-1ubuntu1) raring; urgency=low
* Initial release
-- Your Name <you@example.com> Tue, 07 May 2013 11:16:41 -0400

As you progress and add new versions to your project, you will keep on adding similar text at the beginning of changelog file (without removing old ones). Here the suffix to version of our project (ubuntu1) keeps on adding if you upload new packages for the same release. See this link (http://developer.ubuntu.com/packaging/html/debian-dir-overview.html) for more information.

b. control

This file is another important file, that fixes lots of dependency issues.

Change this file to look as following.

Source: mupengui
Section: games
Priority: extra
Maintainer: Your Name <you@example.com>
Build-Depends: debhelper (>= 8.0.0), cmake, qtbase5-dev, cdbs
Standards-Version: 3.9.4
Homepage: http://yourwebsite.com
Package: mupengui
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, mupen64plus-ui-console
Description: Mupen64plus GUI
 Simple mupen64plus GUI to launch z64 (nintendo 64 games)

If you don’t want Homepage to be included, remove that line.  Make sure you add dependency build in Build-Depends section (if you know of), and packages that you want to get installed for your application to run in Depends section (You don’t need mupen64plus-ui-console for this tutorial). Indent long description using space.

c. copyright

I will not go much into copyright beside GPL. For a GPL-2+ license, all you have to do is remove these lines (from File: * and before Files: debian/*)

Files: *
 Copyright: <years> <put author's name and email here>
 <years> <likewise for another author>
 License: <special license>
 <Put the license of the package here indented by 1 space>
 <This follows the format of Description: lines in control file>
 .
 <Including paragraphs>
 # If you want to use GPL v2 or later for the /debian/* files use
 # the following clauses, or change it to suit. Delete these two lines

Note: As I said, these are the lines to be removed, not kept.

d. postinst (You don’t need this if you deleted MimeType in  desktop file above and did not preserve postinst)

Inside ‘case “$1” in configure)’ write whatever command you want get executed once the installation is complete (before ;;). In my case it is

mkdir -p ~/.local/share/mime/packages
echo '<?xml version="1.0" encoding="UTF-8"?><mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"><mime-type type="application/x-n64-rom"><comment xml:lang="en">Nintendo 64 bit games</comment><glob pattern="*.z64"/></mime-type></mime-info>' > ~/.local/share/mime/packages/x-n64-rom.xml
update-mime-database ~/.local/share/mime
e. rules

Comment those two uncommented lines at the bottom and add two more lines. Those 5 lines at bottom looks like this.

#%:
# dh $@
include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/cmake.mk

These lines will tell the package builder to use cmake to build our project.

8. Creating a key for building the debian package.

Note: This key will be used in launchpad too. Make sure you use a good passphrase.

To create a gpg key (for launchpad), run following command in a terminal

$ gpg --fingerprint
Enter: 1
Enter: 2048
0 = key does not expire
Real name:Your Name
Email address:you@example.com

Real name and Email address are the ones, we have been using all along this tutorial. Use same values here too.

Run following commands to generate a copy of your key to Your_Name.gpg

$ gpg -a --output ~/.gnupg/Your_Name.gpg --export 'Your Name'
$ gpg --import ~/.gnupg/Your_Name.gpg
$ gpg --list-keys

9. Building the package with appropriate key.

Before building the package, lets review what we have done till now.

  • Installed necessary packages
  • Created our source code
  • Created a build script (CMakeLists.txt)
  • Exported two environment variables (DEBFULLNAME and DEBEMAIL)
  • Created a source archive from our source code (after adding the desktop file and an icon).
  • Created stub files for debian packaging
  • Removed files we did not need, kept the ones we needed and modified most of them to match our build requirements.
  • Created a gpg key to sign our packages

Go into mupengui-0.1 directory using the terminal, and run following command to find the public key

$ gpg --list-key
/home/username/.gnupg/pubring.gpg
---------------------------------
pub BLAH/OURKEY date
BLAH BLAH...

Note: We are only interested in “OURKEY”. Our key is the part you get in the “pub” line, before “date”.

Run this command to build the package (from inside mupengui-0.1 directory), but before that remember the passphrase you used while creating the key, because a window will popup asking your passphrase.

$ debuild -kOURKEY

At the end of our build (in terminal) a message should be displayed saying “Successfully signed dsc and changes files”. If this message does not show up and you still have the deb built, you might have done something wrong while using your passkey, or gpg import. Redo those processes to get it right. You don’t have to worry about other warning messages.

SignedMessage

If you go into the parent directory (just outside mupengui-0.1 directory) you should have your shiny new deb file ready to be installed. Using archive manager see the contents of this deb file (e.g what’s inside usr directory, bin, share, applications etc). Install this file and see how it goes.

10. Launchpad part

A good way to publish your application is through personal package archive (aka ppa). To do that, you need to login to launchpad, register the project (just enter the project name), import public key (using gpg –fingerprint). Follow a list of commands, follow email messages as launchpad suggests (e.g signing code of conduct) etc and so on. Good thing is everything will be explained once you pass each phase. Once all those online chores are completed, create a ppa in launchpad.

Here is a list of emails I got before online part was complete.

  • Launchpad: Confirm OpenPGP key
  • Launchpad Code Of Conduct (You will have to download the file and decrypt message with your private key).
  • Lots of rejected messages before the source got accepted for build (after I corrected the error). However since it is automated, no one knows you did terribly few times.

Note: See this link (https://help.launchpad.net/Packaging/PPA) for more information.

11. Uploading your key

You also need to register your key to ubuntu key server. It is very easy to do so from your computer.

Open “Passwords and Keys” from unity dash or application menu. Select the key we created earlier through gpg. Go to Remote->Sync And Publish Keys and select hkp://keyserver.ubuntu.com:11371 from the drop down menu in “Publish keys to” and close this window. In “Sync Keys” dialog box press Sync. That is all you need to do to register your key.

Adding_Keys

12. Uploading your code.

Create a file called .dput.cf in your home directory with following text

[mupengui]
fqdn = ppa.launchpad.net
method = ftp
incoming = ~launchpadusername/mupengui/ubuntu
login = anonymous
allow_unsigned_uploads = 0

Change mupengui and launchpadusername to your project and login details.

To publish your code, go to parent directory of mupengui-0.1 and remove all other files except mupengui-0.1 directory and mupengui_0.1.orig.tar.gz (which we created earlier for building deb file). Go inside mupengui-0.1 directory and this time, create source package instead of binary package.

$ rm *.build *.changes *.dsc *ubuntu*.tar.gz *.deb
$ ls
mupengui-0.1 mupengui_0.1.orig.tar.gz
$ cd mupengui-0.1/
$ debuild -S -kOURKEY

Note: Again make sure OURKEY is the part we get from “gpg –list-key” or “gpg –list-keys” command.

Go back to parent directory and upload your code.

$ cd ..
$ dput ppa:launchpadusername/mupengui mupengui_0.1-1ubuntu1_source.changes

That’s all is to get your package built for ubuntu. This command will upload all source files necessary for launchpad to build your package. If you later see the build log in your launchpad page, you will see how a separate build environment is created specially for you package. Even if your build fails, you will have an appropriate build message, which you can use to debug your packaging steps.

Upload Warnings:

  1. It is an error to upload deb file (remove it from your upload directory, if it is there)
  2. It is an error to upload same file twice (make sure, you get it right while uploading, otherwise you will have to delete the ppa and wait at least 1 hour to create a ppa with same name as previous).
  3. It is an error to upload another orig file with same name (because the sha1 key will be different for two different files). If you accidently deleted this file, download it from launchpad.

You will get rejected mail, if your package is not fit for build. Inside the rejected mail there will be a link, that lists what might be the cause for that message. You should investigate the message and your actions. Though I haven’t touched about pbuilder in this article, debian packager often use pbuilder to simulate a chrooted server built environment in their own computer (you should investigate more about pbuilder). You could also fix the installation dependency just by trying to install your package in a fresh virtualbox instance of your target distro (debian or its derivatives) and see, does that dependency you included in the control file (Depends section) fixes all the dependency.

Conclusion:

In this tutorial we created a simple project (if you omitted the postinst and MimeType part) and packaged it for ubuntu. We then uploaded the code to the hosting website lauchpad.net to create a ppa. Ubuntu and many of its derivatives exclusively use launchpad to host and release their software. I hope this tutorial has given you enough recipe to tinker with packaging.

References:

  1. http://www.webupd8.org/2010/01/how-to-create-deb-package-ubuntu-debian.html
  2. http://quickmediasolutions.com/blog/15/creating-debian-packaging-for-a-qt5-application
  3. Mupengui (https://launchpad.net/mupengui)

Thanks for reading, Cheers !!

1 Comment

Filed under Uncategorized

One response to “Create ubuntu packages

  1. Thank you for your great tutorial!
    In my case I had to create a new GPG key with `gpg –gen-key`.
    `gpg –fingerprint` was only showing the currently created ones…

Leave a comment