Gnome Hello is a simple Perl application showing how to create a Gnome project using the Perl language, the Gtk/Gnome Perl bindings and some autotools-fu in order to build and maintain the project.
1. Tree Initialization
First of all, create a directory using the name of your project (not mandatory, but useful):
$ mkdir my-project
Then, move inside it, and begin creating some sub-directories, in order to split up the files, and building a more reliable source tree:
$ cd my-project $ mkdir docs icons lib tests
Directories Layout
my-project | Root | |||
docs | Documentation | |||
data | Miscellaneous data | |||
icons | Theme icons | |||
lib | Base module directory | |||
… | Modules | |||
tests | Miscellaneous tests |
Explanation:
- docs will contain the documentation of your project, both auto-generated and hand-written files (e.g. the manual or some description of a protocol used by your application);
- data will contain the miscellaneous data used by your application, such as the GConf schemas, the .desktop entry for the menu launcher, the main program icon, the Glade interface definition files, etc.
- icons will contain the stock icons, the window icons or just the pixmaps used by your applications; if you plan to ship icons of different sizes, you should consider the creation of two sub-directories inside the
icons
directory:large
andsmall
; - lib will contain the modules needed by your application. Since we want to create a self-contained application, these modules will not be made publicly available;
- tests will contain the test units for your code (you should really use those).
2. Auto-tools
Autotools are the product of the same people that brought you Emacs, so you should keep this in mind when you decide to use them. Perl developers usually use the ExtUtils::MakeMaker
module in order to create a Perl-friendly build enviroment. Unfortunately, in order to create a build environment for a Gnome project using MakeMaker would result in a great deal of code replication from the autotools land (or the creation of a specific module doing the translation back and forth from autotools macros to Perl code) that all that would be gained by using a Perl-ish environment would soon be lost.
For this reason, we’ll be using the widely known configure-make-makeinstall
triad - that is, we’ll use autoconf
to generate a (hopefully) platform-independent build environment, and automake
to create the relative makefiles for our project.
In order to understand the auto* tools, you’d better off reading the autotools tutorial; what follows next is based on the assumption that you read the tutorial, and understood it.
2.1. Autoconf
The autoconf tool is a program which takes in input a script, written using a language much like the shell scripting language (plus macros) and generates as output a complex shell script which usually takes care of setting up a build environment based on the host configuration. Basically, it’s what makes your program build on every machine other than the developer’s.
But how does the input script (saved as configure.ac
) look like, for a GTK+Perl program?
It’s really like a normal configure.ac script, as built for a C-based project; it has the usual preamble:
dnl -*- Mode: autoconf -*- dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) AC_INIT(gnome-hello-perl, 0.6, http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-perl) AC_CONFIG_SRCDIR(gnome-hello-perl.in) AM_INIT_AUTOMAKE(1.7) AM_MAINTAINER_MODE
And the usual declaration of requirements:
dnl required packages version m4_define(REQUIRED_GTK, 2.8.0) m4_define(REQUIRED_GTK2PERL, 1.100) m4_define(REQUIRED_GNOME2PERL, 1.020) m4_define(REQUIRED_GNOME2VFSPERL, 1.020) m4_define(REQUIRED_GNOME2GCONFPERL, 1.020)
Note: While you could just require every version you like of the GTK library, you should always require the latest stable version of the Perl bindings module.
Since we are building a Perl program, it makes sense to explicitely require the Perl interpreter to be found, and give the user a switch in order to specify a non-standard location (useful for non-Un*x platforms - yes, they do exist):
dnl check for perl binary AC_PATH_PROG(PERL, perl, no) AC_ARG_WITH(perl, [ --with-perl=[perl]] Perl binary path) if test x"$PERL" = xno; then if ! x$with_perl; then AC_MSG_ERROR([No perl binary found]) else PERL = $with_perl fi fi AC_SUBST(PERL)
The code above also gives us the ability to use the @PERL@
variable inside files to be parsed out by the configure script.
Next, we check that the user actually has the packages we require - also, he has the right versions installed onto his system; checking for a library using PkgConfig is practically painless, thanks to the macros provided system-wide:
dnl check for a specific C library version PKG_CHECK_MODULES(GTK2, gtk+-2.0 >= REQUIRED_GTK)
On the other hand, checking for a Perl module using the autotools might be a little trickier; usually, it boils down to checking that the module is present inside the @INC array (the include paths) by simply loading that module; if it’s found, the Perl interpreter will exit successfully, otherwise it won’t. Unfortunately, we also require a minimum version; thus, we need a little script, checking the VERSION
value against the required version:
dnl check for Perl modules dnl gtk2-perl AC_MSG_CHECKING(for Gtk2 >= REQUIRED_GTK2PERL) prog=" exit 0 if Gtk2->VERSION >= REQUIRED_GTK2PERL; exit 1; " if $PERL -MGtk2 -e $prog >&AC_FD_CC 2>&AC_FD_CC; then AC_MSG_RESULT(found) else AC_MSG_RESULT(not found) AC_MSG_ERROR(required gtk2-perl version not found) fi
… to be continued…
2.2. Automake
2.3. Autogen
3. The application launcher
Since we are creating an application in an object-oriented fashion, with the entire application code inside a class, we also need a simple perl program that instantiates that class, and launch the Gtk main loop.
The launcher script will reside in the default binary directory, and will most ikely consists of a few lines, telling the Perl interpreter where to find the application modules (remember: we are creating a self-contained application, with its modules stored outside Perl’s @INC
), the actual object instatiation, and the mainloop call.
Something along these lines will probably be enough for every project:
#!@PERL@ use warnings; use strict; use lib '@PKGLIBDIR@'; use Project; my $app = Project::App->new; $app->show; Project->main; 0;
Both the @PERL@
and @PKGLIBDIR@
placeholders will be substituted by the autotools with the corresponding values, that is the full path of the Perl interpreter and the package library directory, respectively.
Save the launcher script with the .in
suffix, in order to remember that you must “filter” it in order to create a valid launcher.
Inside you Makefile.am
file, you’ll need to add a specific section for the application launcher:
bin_in_files = project-application.in bin_SCRIPTS = project-application project-application: $(bin_in_files) sed -e "s|\@PERL\@|@PERL@|" \ -e "s|@PKGLIBDIR@|$(pkglibdir)|" \ $< > $@ && \ chmod a+x $@
This code will expand the placeholders, will mark it as executable, and will install the launcher script inside the binary directory.
4. Configuration
To Do…
5. Extra files
To Do…