A brief introduction to the Xfce Developer Tools
Benedikt Meurer, 9 Jul 2005
Overview
The Xfce Developer Tools - xfce4-dev-tools
for short - provide an
easy way to handle the setup and maintaince of a projects build framework. They
currently consist of a bunch of M4 macros for commonly used checks and the
xdt-autogen
script, which examines the projects configure.ac
or configure.in
file(s) and calls the appropriate autotools in the
correct order.
As the name suggests, the Xfce Developer Tools are mainly useful for application developers to maintain their build environment. But users will also be required to install them if they plan to build software straight from CVS or SVN checkouts.
Preparing the project
In this section I will describe how to use the developer tools with your project.
We will therefore examine a sample project and discuss the various steps. Our
sample project will contain only a single binary, which does nothing useful. The project
itself will be named sample
, and will depend on libxfcegui4
and can optionally use D-BUS (this is only to demonstrate the usage of some of
the M4 macros). And our project will be translatable to other languages.
We start off with the Makefile.am
's and the source code. First, we
create the projects directory layout:
mkdir sample mkdir sample/po mkdir sample/sample
Next the sample/main.c
source file:
#ifdef HAVE_CONFIG_H #include <config.h> #endif #include <libxfcegui4/libxfcegui4.h> #ifdef HAVE_DBUS #include <dbus/dbus.h> #endif int main (int argc, char **argv) { xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8"); g_print (_("Hello World!\n")); return 0; }
As you can see, we conditionally include dbus/dbus.h
only if the
HAVE_DBUS
preprocessor macro is defined. The check for D-BUS is
made in the configure.ac
file, which is discussed below. Besides
that, the only thing we do here is to print the string "Hello World!"
in a translatable manner, after setting up the proper textdomain for gettext.
We continue with the sample/Makefile.am
, which contains instructions
about how to compile the sample/main.c
file:
INCLUDES = \ -DDBUS_API_SUBJECT_TO_CHANGE \ -DG_LOG_DOMAIN=\"sample\" \ -DPACKAGE_LOCALE_DIR=\"$(localedir)\" \ -I$(top_srcdir) bin_PROGRAMS = \ sample sample_SOURCES = \ main.c sample_CFLAGS = \ $(DBUS_CFLAGS) \ $(LIBXFCEGUI4_CFLAGS) sample_LDFLAGS = \ $(DBUS_LIBS) \ $(LIBXFCEGUI4_LIBS)
The $(localedir)
make variable is set by the XDT_I18N()
macro and will point to the location where the translations are installed (e.g.
/usr/local/share/locale
). The $(DBUS_CFLAGS)
,
$(DBUS_LIBS)
, $(LIBXFCEGUI4_CFLAGS)
and
$(LIBXFCEGUI4_LIBS)
variables are set by the appropriate calls
to XDT_CHECK_OPTIONAL_PACKAGE()
and XDT_CHECK_PACKAGE()
,
which will be discussed below. Note that $(DBUS_CFLAGS)
and
$(DBUS_LIBS)
will be empty if D-BUS was not found or disabled
by the user.
We also need to define DBUS_API_SUBJECT_TO_CHANGE
because the D-BUS
API is not yet frozen, but that's an unimportant detail in the context of this
article.
Furthermore we will also need a toplevel Makefile.am
, which should
look like this:
SUBDIRS = \ po \ sample AUTOMAKE_OPTIONS = \ 1.8 \ dist-bzip2
The AUTOMAKE_OPTIONS
variable is used by automake
to
enable or disable special behaviour. In this case, the 1.8
tells
automake
that we need version 1.8 or better. And the dist-bzip2
option tells automake
to generate a dist
target, which
will not only create the gzipped source tarball, but also a bzip2 compressed source
tarball.
Now we are done with the Makefile.am
's. The next step is to take care
of the i18n setup. Therefore we need to create an empty po/ChangeLog
file (the po/Makefile.in.in
generated by glib-gettextize
requires this file)
$ touch po/ChangeLog
and afterwards create the po/POTFILES.in
file, which lists all source
files (and sometimes other files like .desktop
or .xml
files as well) that contain translatable strings. In this case only the
sample/main.c
file contains a translatable string, so the file
looks like this:
sample/main.c
Note that all paths in po/POTFILES.in
must be relative to the projects
toplevel directory. One last step before we go on to the configure.ac
file is to create four required files for GNU projects:
$ touch AUTHORS ChangeLog NEWS README
You should of course add content to these files later on, but for now, we want to
concentrate on the important facts, the contents of configure.ac
:
dnl Version information m4_define([sample_version_major], [0]) m4_define([sample_version_minor], [0]) m4_define([sample_version_micro], [1]) m4_define([sample_version], [sample_version_major().sample_version_minor().sample_version_micro()]) dnl Initialize autoconf AC_COPYRIGHT([Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>]) AC_INIT([sample], [sample_version()], [benny@xfce.org]) dnl Initialize automake AM_INIT_AUTOMAKE([AC_PACKAGE_TARNAME()], [AC_PACKAGE_VERSION()]) AM_CONFIG_HEADER([config.h]) AM_MAINTAINER_MODE() dnl check for basic programs AC_PROG_CC() AC_PROG_INSTALL() AC_PROG_LIBTOOL() dnl Check for i18n support XDT_I18N([de]) dnl Check for required packages XDT_CHECK_PACKAGE([LIBXFCEGUI4], [libxfcegui4-1.0], [4.2.0]) dnl Check for optional packages XDT_CHECK_OPTIONAL_PACKAGE([DBUS], [dbus-1], [0.22], [dbus], [D-BUS support]) AC_OUTPUT([ Makefile po/Makefile.in sample/Makefile ])
You should be familar with most of the above, therefore we will only discuss the
XDT_I18N()
, XDT_CHECK_PACKAGE()
and
XDT_CHECK_OPTIONAL_PACKAGE()
macros here. If you are not familar with the basic autoconf and automake macros,
you should have a look at the GNU
manuals.
XDT_I18N(LINGUAS [, PACKAGE])
This macro takes care of setting up everything for i18n support.
If PACKAGE
isn't specified, it defaults to the package tarname; see
the description of AC_INIT()
for an explanation of what makes up
the package tarname. Normally, you don't need to specify PACKAGE
,
but you can stick with the default.
XDT_CHECK_PACKAGE(VARNAME, PACKAGE, VERSION [, ACTION-IF [, ACTION-IF-NOT]])
Checks if PACKAGE
>= VERSION
is installed on the
target system, using the pkg-config
utility. If the
dependency is met, VARNAME_CFLAGS
, VARNAME_LIBS
,
VARNAME_VERSION
and VARNAME_REQUIRED_VERSION
will be set and marked for substition. For example, if you specify GTK
for the VARNAME
parameter, the variables GTK_CFLAGS
,
GTK_LIBS
, GTK_VERSION
and GTK_REQUIRED_VERSION
will be set appropriately and substituted.
VARNAME_REQUIRED_VERSION
will be set to the value of
VERSION
. This is mostly useful to automatically
place the correct version information into the RPM .spec
file.
In addition, if the dependency is met, ACTION-IF
will
be executed if given.
If the package check fails, ACTION-IF-NOT
will be
executed. If this parameter isn't specified, a diagnostic
message will be printed and the configure script will
be terminated with exit code 1.
XDT_CHECK_OPTIONAL_PACKAGE(VARNAME, PACKAGE, VERSION, OPTIONNAME, HELPSTRING [, DEFAULT])
Checks for an optional dependency on PACKAGE
>= VERSION
.
DEFAULT
can be "yes"
or "no"
(defaults to
"yes"
if not specified) and controls whether configure should check this
dependency by default, or only if the user explicitly enables it using a command line switch.
This macro automatically adds a commandline switch based on the OPTIONNAME
parameter (--enable-optionname
and --disable-optionname
), which
allows the user to explicitly control whether this optional dependency should be
enabled or not. The HELPSTRING
parameter gives a brief(!) description
about this dependency.
If the user chose to enable this dependency and the required package
was found, this macro defines the variable VARNAME_FOUND
and sets it
to the string "yes"
, in addition to the 4 variables set by
XDT_CHECK_PACKAGE()
. But VARNAME_FOUND
will not be marked
for substition. Furthermore, a C preprocessor define HAVE_VARNAME
will be placed in
config.h
(or added to the cc command line, depending on your configure.ac
content) and set to 1.
First run
Now that everything is in place we are ready for the first run. Therefore, go to the toplevel directory of the project and execute the
$ xdt-autogen
command that comes with the developer tools. This will run all the required autotools (in our
case these are glib-gettextize
, libtoolize
, aclocal
,
autoheader
, automake
and autoconf
), and afterwards run
the generated configure
script.
The next thing to do is to generate all language files specified with the XDT_I18N()
macro (we've only specified de
in our configure.ac
). Therefore execute
the following commands:
$ cd po $ make sample.pot $ cp sample.pot de.po
Now if you check po/de.po
, it will contain exactly one translatable string, the one
from sample/main.c
.
That's it, now you can simply run
$ make
in the projects toplevel directory in order to build your project for the first time. Congratulations, you've successfully completed the build framework setup.
The source code for the sample project is available here.
For more details on the internal workings and the other available macros, check the M4 files in the
m4macros/
subdirectory of the Xfce Developer Tools distribution. I also plan to write
further articles about the developer tools, so you may want to keep an eye on the articles page or my weblog.
Feedback
Please send feedback concerning this article to me. If you have questions concerning the developer tools or want to report a bug, use the xfce4-dev mailinglist instead of contacting me directly.