Copyright © 2004 Olivier Pinçon
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Many of the names used by companies to distinguish their products and services are claimed as trademarks. Where those names appear in any GNOME documentation, and those trademarks are made aware to the members of the GNOME Documentation Project, the names have been printed in caps or initial caps.
When I first launched Anjuta, I told myself : "Hey, that looks like MS Visual C++, as I know it pretty well, understanding Anjuta will be a piece of cake.". As you might have guessed, I come from the Windows world and I was looking for something familiar. Actually, Anjuta differs quite a bit from MSVC or Borland's C++ Builder, essentially in its build system, which is in fact the standard linux build system using autoconf, automake and libtool; these three programs are usually referred to as the autotools.
Here I will try to explain everything that I wanted to know but could'nt directly find when I started using Anjuta. Therefore, this tutorial should be especially suitable to you if you are starting GNU/Linux programming.
I will use Anjuta v1.2.1 here; so things can slightly differ if you have another version. I assume that you have a basic understanding of C or C++ and makefiles.
Let's quickly review the basics before we get a higher-level view.
A typical compilation command:
$gcc -g -Wall -I/usr/include/libxml2/libxml -lxml2 main.c aux.c -o tut_progThis command tells GCC to compile the source files main.c and aux.c, and produce a binary called 'tut_prog' (this stands for 'tutorial program'). The various switches have the following meaning :
| Switch | Meaning |
|---|---|
| -g | tells GCC to include debug info into the binary. |
| -Wall | Warning all : print every warning. |
| -Idir | Look for included header files (like in #include <myheader.h>) in directory dir. |
| -llib | Link to library lib; here libxml2. |
Here, tut_prog can use the libxml2 library to parse some XML.
The -g, -Wall and -I switches are know as CFLAGS (because they are passed to the compiler); -l is a LDFLAG (because it is passed to the linker) or a LIBS flag. Thus, if we suppose CFLAGS=-g -Wall -I/usr/include/libxml2/libxml and LIBS=-Lxml2 then our compilation command is equivalent to $gcc $(CFLAGS) $(LIBS) main.c aux.c -o tut_prog.
Using Anjuta you will never type a compilation command line.
With makefiles you can greatly automate the compilation process (and actually make many more things than just compiling). A Makefile file for our tutorial program could be :
Example 2-1. A simple Makefile file
Makefile: CC=gcc # the C compiler is gcc CFLAGS=-g -Wall -I/usr/include/libxml2 LIBS=-lxml2 tut_prog: main.o aux.o # what we need to have 'tut_prog'... $(CC) $(LIBS) main.o aux.o -o tut_prog # ...and how to get it from the ingredients. main.o: main.c $(CC) -c $(CFLAGS) main.c aux.o: aux.c $(CC) -c $(CFLAGS) aux.c
Makefiles have a dependency approach: to have the 'tut_prog' binary, we must first ensure that the object files main.o and aux.o are present (first line), and then link them (second line) using CC; similarly to have these object files we need the source files main.c and aux.c to be present (first line) and compiled (second line).
Once the Makefile is typed, you only have to run 'make' for your program to be built and up to date.
With Anjuta, you will never have to read or write a makefile.
Anjuta uses the standard GNU build system, that is to say it uses autoconf, automake and libtool, also know as the autotools. You probably have already installed software from source, using the magic combination "./configure; make; make install", and may have noticed that many files are involved in this build process; globally all that stuff seems very complicated. But you must understand the fundamentals of the build system before using it through Anjuta.
The GNU build system is a very flexible framework. Its main goal is portability of your software to various Unices and Windows as well (in my opinion, this is mainly the purpose of autoconf and libtool). It also allows quick generation of very complete makefiles.
What's happening when you compile GNU software ? The configure shell script (invoked by './configure') checks your system (it searches necessary libraries, amongst other things) and adjusts some makefiles (for instance, write the libraries access paths in makefiles). When you launch 'make', makefiles are simply executed to build the software; and 'make install' copies the compiled software on your system, using the make target called 'install'.
You must keep in mind that the configure script or the makefiles are huge files generated by the GNU tools. We will not look inside them here; instead we will create the human-readable templates that are input files for the GNU tools.
Let's see a simple example to start grasping the relationships between the various files.
Create an empty directory called 'tut_prog', and within it a simple 'main.c' C source file :
main.c:
#include <stdio.h>
int main()
{
printf("Hello world!\n");
return 0;
}
Now let's write configure.in, which is the template for the configure script. It is the input file of autoconf and is also used by automake.
configure.in: AC_INIT AM_INIT_AUTOMAKE(tut_prog, 1.0) AC_PROG_CC AC_OUTPUT(Makefile)
AC_INIT, AM_INIT_AUTOMAKE, etc... are m4 macros. m4 is a macro expanding software used by the autotools; we don't need to know about it. When autoconf will process this configure.in, the macros will be expanded and we will get a fresh huge configure script.
AC_INIT expands into the initialization part of the configure script, which, when launched, will perform some basic tests of the system's sanity.
AM_INIT_AUTOMAKE expands into some other initialization code; here we indicate the name of the software and its version.
AC_PROG_CC expands in a code that checks for a decent C compiling environment, that we actually need to build our test program.
AC_OUTPUT indicates what makefiles will be produced by the configure script.
Many other macros are available to check for every kind of program or library. Some of them are standard macros, provided by the autotools, others are software-specific. For instance, if you develop a library called foo, you might want to write an AC_CHECK_FOR_FOO macro so that developers using your library can check for its presence using autoconf. Look at the standard macros list if you like.
So when we will launch autoconf, it will expand the macros. The macros contents were installed on your system when you installed autoconf.
![]() | To locate them, search .m4 files on your system. |
![]() | On my system, I actually get an extra directory called 'autom4te.cache'. That is for autoconf internal purposes; so I won't care about it anymore. |
It's now time to deal with automake and makefiles. automake's input is a file called 'Makefile.am' which describes the software to build in a very global way. Create the following Makefile.am :
Makefile.am: bin_PROGRAMS = tut_prog tut_prog_SOURCES = main.c
In Makefile.am are the very essential data needed to build the project: the target program, called tut_prog, will be put in a $prefix/bin/ directory; to build it we need main.c. Note that we don't specify how that will be built: automake will figure it out. We have'nt even mentioned the compiler in this pre-makefile.
Makefile.am will be processed by automake; the result will be a Makefile.in. This Makefile.in is close to being a real makefile, but it contains variable names which will be replaced when the configure script will run, resulting in a real makefile (called Makefile). For instance, 'configure' will write in the final Makefile what compiler to use (it is the compiler it found using the AC_PROG_CC macro).
It's now time to run 'automake'. But first create some empty files: NEWS, README, AUTHORS and ChangeLog:
$touch NEWS README AUTHORS ChangeLogbecause automake complains if they are absent. Now run 'automake -a' (-a stands for --add-missing: some files needed internally are not present in the directory.).
Now look inside your directory. Makefile.in is here, OK, but many other files have appeared. They are not essential. Keep in mind the 4 really important ones : configure.in, configure, Makefile.am, and Makefile.in (and main.c of course).
![]() | Note that the two .in files don't have the same "type": configure.in is a file written by yourself (and so, small) processed by autoconf; but Makefile.in is a big file generated by automake and that will be processed by 'configure'. I think that extension is quite misleading. |
Everything is now ready for configure to run. Run './configure'.
$ ./configure checking for a BSD-compatible install... /usr//bin/install -c checking whether build environment is sane... yes checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for gcc... gcc checking for C compiler default output... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for style of include used by make... GNU checking dependency style of gcc... gcc3 configure: creating ./config.status config.status: creating Makefile config.status: executing depfiles commandsAs planned, configure checked various things, like the compiler. Using the data it acquired from that scanning, it created 'Makefile' from Makefile.in. You can compare these two big files : they are really similar.
You can now Run 'make'.
$ make if gcc -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" \ -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"tut_prog\" -DVERSION=\"1.0\" -I. -I. -g -O2 -MT main.o \ -MD -MP -MF ".deps/main.Tpo" \ -c -o main.o `test -f 'main.c' || echo './'`main.c; \ then mv -f ".deps/main.Tpo" ".deps/main.Po"; \ else rm -f ".deps/main.Tpo"; exit 1; \ fi gcc -g -O2 -o tut_prog main.oQuite complicated, but it works. Launch the binary 'tut_prog' if you like. Note the -D switches passed to gcc: they correspond to #define in a C program. For instance, thanks to -DPACKAGE=\"tut_prog\" everything is as if main.c contained:
#define PACKAGE "tut_prog"Thus, you can add the following line to main.c:
printf("This package is %s\n", PACKAGE);
Then re-run make and re-run tut_prog:
$ make -- make output cut -- $ ./tut_prog Hello world! This package is tut_progHow did that string 'tut_prog' come from configure.in's AM_INIT_AUTOMAKE ? A 'PACKAGE' variable containing "tut_prog" has been created in 'configure', and put in Makefile while configure processed Makefile.in. Many communications between 'configure' and your program work that way.
Take a look at your directory again. It's a real mess (and there's even a hidden directory inside on my system). But now you are not afraid of it anymore :)
For things to be even clearer, you can take a look at the dependencies amongst the various files in this chapter of the Autobook.
Let's see how does Anjuta handle a very simple project containing only the main.c file we used in the previous section. Launch Anjuta, create a new project of type 'Generic/Terminal project.'
Call it 'tut_prog' and let it be a C-only project. Enter no comment, uncheck copyright statement and gettext support since we want to keep things as simple as possible.
Complete the remaining steps of the application wizard; the project is now created. The default behaviour of Anjuta is to create a directory 'tut_prog' in $HOME/Projects, to add a src/ subdirectory and a sample main.c file in it. The project is configured immediately. Here is some simplified output:
**Warning**: I am going to run `configure' with no arguments. If you wish to pass any to it, please specify them on the `./autogen.sh' command line. processing . Running libtoolize... Running aclocal ... Running autoheader... --- some warnings from autoheader --- Running automake --gnu ... Running autoconf ... Running ./configure ... --- various tests run by configure --- creating libtool configure: creating ./config.status config.status: creating Makefile config.status: creating src/Makefile config.status: creating config.h config.status: config.h is unchanged config.status: executing depfiles commands Now type `make' to compile the package.
In fact, Anjuta runs a script called 'autogen.sh', provided by Anjuta itself (that is, it is not part of the autotools) which runs : libtoolize, aclocal, autoheader, automake, autoconf and finally ./configure. We already know about aclocal, automake, autoconf and configure, let's look at libtoolize and autoheader.
libtoolize is provided by libtool. Its goal is to make library using easier, we will look at it later.
autoheader creates a 'config.h.in' file which, like Makefile.in, is processed later by configure, resulting in a 'config.h'. This C header file contains various #defines, all set by configure; you could take a look at it now. You can see:
-- various #defines -- /* Define to 1 if you have the <stdlib.h> header file. */ /* -- this value is a result of a test by configure -- */ #define HAVE_STDLIB_H 1 -- various other #defines -- /* Name of package */ /* -- this is from configure.in -- */ #define PACKAGE "tut_prog" -- various other #defines --
Do you remember how configure communicated with C files by using several -Dxxxx flags in the previous section ? In fact, this config.h is another mean of communication : by including 'config.h', a C source file can know everything that configure determined.
Now you can build the project (that is, run 'make') by pressing F11 and run the binary with F3 (both are in the 'Build' menu).
Just like we typed configure.in and Makefile.am in the previous section, Anjuta created these files automatically. They are indeed more complicated, while being very understandable: configure.in specifies more checks and more variables; moreover Makefile.am must manage the recursion in src/ (actually, there is a Makefile.am in src/ too). You can look at these files and thus expand your knowledge about autoconf and automake.
Here are some links to reference documents dealing with the autotools in general, and autoconf and automake in particular.
The Autobook explains in details how the autotools work.
Here is a tutorial about using autoconf alone.
Amongst the various GNU development tools you are told about here are autoconf and automake.
Here are some slides by a teacher from Ecole Nationale Supérieure des Télecoms about the autotools.
Please e-mail me /* how can that be done ? */ if one of these links is broken, or if you know other ones.
When producing real-life software, you will need libraries. If you want to parse some XML, you might want to use libxml2; if you're programming a game you could link your program to SDL or OpenGL.
In this chapter you will learn how to use shared libraries with Anjuta.
libtool is a portability layer which makes library access easier, since it hides the differences between the various Unix variants in this particular domain.
Using libtool is transparent for the Anjuta user, that is why I won't tell you much about it. However you can look at libtool's manual to understand its ins and outs.
libxml2 allows you to parse and produce XML files, which can be very useful nowadays (see its homepage at www.xmlsoft.org). Let's see how to use it with Anjuta.
Open our tut_prog project, and replace main.c by this one :
main.c:
#include <libxml/parser.h>
#include <stdio.h>
int main()
{
xmlDocPtr doc;
doc = xmlParseFile ("testfile.xml");
if (doc == NULL) {
printf ("Document not parsed successfully. \n");
return -1;
}
else {
printf ("Document parsed successfully.\n");
xmlFreeDoc(doc);
return 0;
}
}
Our goal is now to compile it and make it work correctly. For that purpose, we must
tell gcc two things: where to find libxml/parser.h (that is to say, give gcc
the right include path) and what library (i.e. shared object) it should link
our project against. There are several ways to do that, I will mention two of them.
It is the approach one could naturally have: let's give gcc the stuff it needs directly ! On my system, libxml/parser.h is in /usr/include/libxml2, and the shared object is 'libxml.so', located in /usr/lib. (I will assume it's all the same for you). Let's indicate it to Anjuta.
In the 'Settings' menu, select 'Compiler and Linker Settings...'. Select the 'Include Paths' tab, and add '/usr/include/libxml2' (or your corresponding include path) in the list.
Likewise, if the shared object is in an unusual directory, we should add it in the 'Library Paths' tab. It is not the case here since gcc always look in /usr/lib.
Finally we must indicate the shared object itself in the 'Libraries' tab. You can enter 'xml2' by hand or select it in the list if present.
What we have just typed is now reflected in src/Makefile.am. Indeed, take a look at it: you will see something like:
INCLUDES =\ -I/usr/include/libxml2and like:
tut_prog_LDADD = \ -lxml2
For changes to be taken into account, you must re-run automake; in Anjuta you can run 'Auto generate' in the Build menu. Then, building should work; that's done, you can parse XML files.
This approach works, but it has several drawbacks:
It is not portable to various linuxes: perhaps on other distros the include path is different.
If the next versions of libxml have different paths, or different needed libraries, we will have to keep track of it in Anjuta.
We don't test whether the system of the packager/user has the library.
We cannot check the version if the libxml2 we use.
It's ugly !
As you might have guessed, using the autotools will be far better.
We will now use autoconf's capabilities. Undo what you have just done (that is to say, remove what you typed in the 'Compiler and Linker Settings' dialog box).Open 'Configure Project' in the 'Project' menu. Here we can tweak the interaction between Anjuta and the autotools. Select the 'Configuration' tab. In these subtabs you can type things to add in configure.in, in different sections delimited by comments (take a look at configure.in to see that). Type the following in 'Libraries':


So what happened ? First, libxml2 is handled by pkg-config which provides m4 macros for autoconf, like PKG_CHECK_MODULES (see pkg-config man page for details on this macro and others). With this macro, configure will check for a minimal version of libxml2 and set the shell variables xml_CFLAGS and xml_LIBS (since the first parameter of the macro is 'xml') to the C flags and library switches needed by gcc. Look at the output of 'configure':
checking for pkg-config... /usr/bin/pkg-config checking for libxml-2.0 >= 2.4... yes checking xml_CFLAGS... -I/usr/include/libxml2 checking xml_LIBS... -lxml2 -lpthread -lz -lm
AC_SUBST(xml_CFLAGS) tells configure to replace ocurrences of @xml_CFLAGS@ in the various Makefile.in by the the contents of the shell variable xml_CFLAGS (i.e. "-I/usr/include/libxml2").
Let's recap: in src/Makefile.am we have a $(xml_CFLAGS) (which is from the 'Compiler and linker setting' dialog). When automake is run, it produces src/Makefile.in and we get @xml_CFLAGS@. Finally, configure transforms @xml_CFLAGS@ in its true value : -I/usr/include/libxml2. Of course, the same reasoning holds for xml_LIBS.
Now we have a flexible and robust way to use libxml2.
lib3ds allows you to handle 3DS files. We will try to build and run the following code :
main.c:
#include <lib3ds/types.h>
#include <lib3ds/file.h>
#include <stdio.h>
int main()
{
Lib3dsFile* file;
file = lib3ds_file_load ("testfile.3ds");
if (file == NULL) {
printf ("3DS file not read successfully. \n");
return -1;
}
else {
printf ("3DS file parsed successfully.\n");
lib3ds_file_free(file);
return 0;
}
}
This library does not use pkg-config. However, when I installed the lib3ds-devel package on my distro, I noticed a lib3ds.m4 file copied in /usr/share/aclocal/. I will now assume you have this package installed.
Take a look at this .m4 file. A comment note at the top explains how to use the macro it defines : AM_PATH_LIB3DS. Look around the end of the file : its seems to use AC_SUBST with variables LIB3DS_CFLAGS and LIB3DS_LIBS. We know that !
Given this, it seems reasonable to use the macro the following way :
And given the AC_SUBST the following should work (I added -lm which stands for the math library; lib3ds' author seems to have forgotten it):

Regenerate the project and rebuild : that should work. In fact, 'aclocal' looked in /usr/share/aclocal/ (or the corresponding directory on your distro) for the .m4 files it needed, and found lib3ds.m4.
More generally, to use a library with the help of autoconf, check the following:
If the library is handled by pkg-config, just use the PKG_CHECK_MODULES macros as we did in the section above.
Check if the library author shipped a .m4 macro, and use it if present.
If your library is a basic one, it might be checked by the standard autoconf macros (see the list here).
Perhaps the m4 you need has already be programmed by someone else. Look at the contributions here.
If all that fail, go deeper in m4, make your own macro, and donate it to the library's author !