Using Autotools
Adding a new library in a autotools project could be more or less easy depending on how the library is packaged. To take an example, imagine that we want to read an xml file using libxml2 (see its homepage at www.xmlsoft.org)
-
Open the old tutorial project and replace main.c by the following.
Example 4-1 main.c using libxml2:#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 start with the easiest.
- 4.1.1. With pkg-config
- 4.1.2. With an Autoconf macro
- 4.1.3. With hardcoded library path
4.1.1. With pkg-config
pkg-config is tools for developers providing a unified interface for querying installed libraries with their version and all options needed to compile and link it. It comes with an Autoconf macro named PKG_CHECK_MODULES allowing to check the existence of the library and set all necessary flags.
-
Add the following line in configure.ac.
PKG_CHECK_MODULES(XML, libxml-2.0 >= 2.4)
This macro will check the existence of libxml2 with a version higher or equal to 2.4 and create 2 variable XML_CFLAGS and XML_LIBS containing respectively, the flags for the C compiler and the linker. XML is an user defined name. libxml-2.0 is the name of the library. You can run pkg-config --list-all to get a list of all installed libraries.
-
Add the following lines in Makefile.am.
tut_prog_CPPFLAGS = $(XML_CFLAGS) tut_prog_LDFLAGS= $(XML_LIBS)
This will use the options found by configure when the macro PKG_CHECK_MODULES is executed for compiling your program.
-
That's all. You can run make again.
cd . && /bin/sh /home/seb2008.1/Projects/tutprog/missing --run aclocal-1.10 cd . && /bin/sh /home/seb2008.1/Projects/tutprog/missing --run automake-1.10 --foreign cd . && /bin/sh /home/seb2008.1/Projects/tutprog/missing --run autoconf /bin/sh ./config.status --recheck running CONFIG_SHELL=/bin/sh /bin/sh ./configure --no-create --no-recursion checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking whether to enable maintainer-specific portions of Makefiles... yes checking for style of include used by make... GNU checking for gcc... gcc checking for C compiler default output file name... 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 ISO C89... none needed checking dependency style of gcc... gcc3 checking for library containing strerror... none required checking for gcc... (cached) gcc checking whether we are using the GNU C compiler... (cached) yes checking whether gcc accepts -g... (cached) yes checking for gcc option to accept ISO C89... (cached) none needed checking dependency style of gcc... (cached) gcc3 checking for gcc... (cached) gcc checking whether we are using the GNU C compiler... (cached) yes checking whether gcc accepts -g... (cached) yes checking for gcc option to accept ISO C89... (cached) none needed checking dependency style of gcc... (cached) gcc3 checking how to run the C preprocessor... gcc -E checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for ANSI C header files... yes checking for pkg-config... /usr/bin/pkg-config checking pkg-config is at least version 0.9.0... yes checking for XML... yes configure: creating ./config.status /bin/sh ./config.status config.status: creating Makefile config.status: creating config.h config.status: config.h is unchanged config.status: executing depfiles commands cd . && /bin/sh /home/seb2008.1/Projects/tutprog/missing --run autoheader rm -f stamp-h1 touch config.h.in cd . && /bin/sh ./config.status config.h config.status: creating config.h config.status: config.h is unchanged make all-am make[1]: Entering directory `/home/seb/Projects/tutprog' gcc -DHAVE_CONFIG_H -I. -DPACKAGE_DATA_DIR=\""/usr/local/share"\" -I/usr/include/libxml2 \ -Wall -g -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c mv -f .deps/main.Tpo .deps/main.Po gcc -Wall -g -g -O2 -o tutprog main.o -lxml2 make[1]: Leaving directory `/home/seb/Projects/tutprog'
There is no need to rerun Autoconf or Automake because the Makefile generated by it already contains some rules to do it.
When installed, each library supporting pkg-config copy a small text file, with .pc extension, in a system directory; normally /usr/lib/pkgconfig. If you install a library from source it will be by default in /usr/local/lib/pkgconfig. You can ask pkg-config to search in this directory too, by defining the environment variable PKG_CONFIG_PATH=/usr/local/lib/pkgconfig.
4.1.2. With an Autoconf macro
If the library does not support pkg-config: it does not appear in the list returned by pkg-config --list-all. You need a Autoconf macro:
- Check if the library author shipped a M4 macro, and use it if present. It is a text file named like the library with a .m4 extension often installed in /usr/share/aclocal.
- If your library is a basic one, it might be checked by the standard Autoconf macros (see the list here).
- Perhaps the M4 macro 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!
When, you have this macro, you can copy it in /usr/share/aclocal, so aclocal will find it. Then, you just need to look in the macro file to see how to use it. libxml2 installs a macro named AM_PATH_XML2 which is in /usr/share/aclocal/libxml.m4.
-
Add the following line in configure.ac.
AM_PATH_XML2(2.4.0)
This macro will check the existence of the library with a version higher or equal to 2.4 and create 2 variable XML_CPPFLAGS and XML_LIBS containing respectively, the flags for the C compiler and the linker. You get these information from the comments in the macro file.
-
Add the following lines in Makefile.am.
tut_prog_CPPFLAGS = $(XML_CPPFLAGS) tut_prog_LDFLAGS= $(XML_LIBS)
This will use the options found by configure for compiling your program. Note that the macro defined XML_CPPFLAGS instead of XML_CFLAGS with pkg-config. Using CPPFLAGS makes more sense, because these flags are used by the C preprocessor, most of the time only to setup the path of the include files.
-
That's all. You can run make again. The generated Makefile is almost the same.
4.1.3. With hardcoded library path
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).
-
Add the following lines in Makefile.am.
tut_prog_CPPFLAGS = -I /usr/include/libxml2 tut_prog_LDFLAGS= -lxml2
There is no need to change configure.ac because you don't check anything and just assume that all host system will have the right library in the same place than you.
-
You can run make and it should work if you have the same system than me.
cd . && /bin/sh /home/seb2008.1/Projects/tutprog/missing --run automake-1.10 --foreign Makefile cd . && /bin/sh ./config.status Makefile depfiles config.status: creating Makefile config.status: executing depfiles commands make all-am make[1]: Entering directory `/home/seb/Projects/tutprog' gcc -DHAVE_CONFIG_H -I. -DPACKAGE_DATA_DIR=\""/usr/local/share"\" -I /usr/include/libxml2 \ -Wall -g -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c mv -f .deps/main.Tpo .deps/main.Po gcc -Wall -g -g -O2 -o tutprog main.o -lxml2 make[1]: Leaving directory `/home/seb/Projects/tutprog'
I have described this here to show that it is possible to do simple thing using Autotools. But this approach has several drawbacks:
- It is not portable to various linuxes: perhaps on other distribution the include path is different.
- If the next versions of libxml have different paths, or different needed libraries, we will need to update the project.
- We don't test whether the system of the packager/user has the library.
- We cannot check the version of the libxml2 we use.