Documentation/Maemo 5 Developer Guide/GNU Build System

(Specifying Default Goal)
 
(26 intermediate revisions not shown)
Line 1: Line 1:
-
= GNU Build System =
 
-
 
The following code examples are used in this chapter:
The following code examples are used in this chapter:
-
* [https://garage.maemo.org/svn/maemoexamples/trunk/simple-make-files/ simple-make-files]
+
* [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/ simple-make-files]
-
* [https://garage.maemo.org/svn/maemoexamples/trunk/autoconf-automake/ autoconf-automake]
+
* [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/ autoconf-automake]
-
+
 
-
= GNU Make and Makefiles =
+
== GNU Make and Makefiles ==
-
The ''make'' program from the GNU project is a powerful tool to aid implementing automation in the software building process. Beside this, it can be used to automate any task that uses files and in which these files are transformed into some other form. Make by itself does not know what the files contain or what they represent, but using a simple syntax it can be taught how to handle them.
+
The <code>make</code> program from the GNU project is a powerful tool to aid implementing automation in the software building process. Beside this, it can be used to automate any task that uses files and in which these files are transformed into some other form. Make by itself does not know what the files contain or what they represent, but using a simple syntax it can be taught how to handle them.
When developing software with gcc (and other tools), gcc is often invoked repeatedly with the same parameters and flags. After changing one source file, it is noticed that other output files need to be rebuilt, and even the whole application if some interface has changed between the functions. This might happen whenever declarations change, new parameters are added to function prototypes, and so on.
When developing software with gcc (and other tools), gcc is often invoked repeatedly with the same parameters and flags. After changing one source file, it is noticed that other output files need to be rebuilt, and even the whole application if some interface has changed between the functions. This might happen whenever declarations change, new parameters are added to function prototypes, and so on.
-
These tasks could, of course, be always performed manually, but after a while a nicer way is more desirable.
+
These tasks can always be performed manually, but after a while a nicer way is more desirable.
GNU make is a software building automation tool that will execute repetitive tasks. It is controlled via a '''Makefile''' that contains lists of dependencies between different source files and output files. It also contains lists of commands that should be executed to satisfy these dependencies. Make uses the '''timestamps''' of files and the information of the files' existence to automate the rebuilding of applications (targets in make), as well as the rules that are specified in the Makefile.
GNU make is a software building automation tool that will execute repetitive tasks. It is controlled via a '''Makefile''' that contains lists of dependencies between different source files and output files. It also contains lists of commands that should be executed to satisfy these dependencies. Make uses the '''timestamps''' of files and the information of the files' existence to automate the rebuilding of applications (targets in make), as well as the rules that are specified in the Makefile.
Line 18: Line 16:
Make can be used for other purposes as well. A target can easily be created for installing the built software on a destination computer, a target for generating documentation by using some automatic documentation generation tool, and so on. Some people use make to keep multiple Linux systems up to date with the newest software and various system configuration changes. In short, make is flexible enough to be generally useful.
Make can be used for other purposes as well. A target can easily be created for installing the built software on a destination computer, a target for generating documentation by using some automatic documentation generation tool, and so on. Some people use make to keep multiple Linux systems up to date with the newest software and various system configuration changes. In short, make is flexible enough to be generally useful.
-
The dependencies between different files making up a software project:
+
[[Image:make.png|center|frame|alt=Diagram of project dependencies|The dependencies between different files making up a software project]]
-
<div align="CENTER">[[Image:make.png|Image make]]</div>
+
The aim of make is to satisfy the target. Each target has its own dependencies. A user generally selects a target for make to satisfy by supplying the target name on the command line. Make starts by checking whether all of the dependencies exist and have an older timestamp than the target. If so, make  does nothing, because nothing has changed. However, because a header file (that an application is not dependent on directly) can change, make propagates the changes to the 'root' of the target as shown in the picture above.
-
 
+
-
The aim of make is to satisfy the target. Each target has its own dependencies. A user generally selects a target for make to satisfy by supplying the target name on the command line. Make starts by checking whether all of the dependencies exist and have an older timestamp than the target. If so, make  does nothing, as nothing has changed. However, because a header file (that an application is not dependent on directly) can change, make propagates the changes to the 'root' of the target as shown in the picture above.
+
Make rebuilds all of the necessary dependencies and targets on the way towards the target. This way, make only rebuilds those dependencies that actually affect something, and thus, saves time and effort. In big projects, the amount of time saved is significant.
Make rebuilds all of the necessary dependencies and targets on the way towards the target. This way, make only rebuilds those dependencies that actually affect something, and thus, saves time and effort. In big projects, the amount of time saved is significant.
Line 28: Line 24:
To illustrate this, suppose that '''file3.c''' in the above picture is modified. After that, make is run, and it will automatically rebuild the necessary targets ('''file3.o''', '''libutil.a''' and '''app'''):
To illustrate this, suppose that '''file3.c''' in the above picture is modified. After that, make is run, and it will automatically rebuild the necessary targets ('''file3.o''', '''libutil.a''' and '''app'''):
-
<div align="CENTER">[[Image:make-mod1.png|Image make-mod1]]</div>
+
[[Image:make-mod1.png|center|frame|alt=Diagram of project files that need to be rebuilt|Project files that need to be rebuilt after file3.c is modified]]
Now suppose that another function is added to '''file1.c'''. Then also '''util.h''' needs to be modified accordingly. The picture shows that quite a few objects and targets depend on this header file, so a sizable number of objects need to be rebuilt (but not all):
Now suppose that another function is added to '''file1.c'''. Then also '''util.h''' needs to be modified accordingly. The picture shows that quite a few objects and targets depend on this header file, so a sizable number of objects need to be rebuilt (but not all):
-
<div align="CENTER">[[Image:make-mod2.png|Image make-mod2]]</div>
+
[[Image:make-mod2.png|center|frame|alt=Diagram of project files that need to be rebuilt|Project files that need to be rebuilt after file1.c and util.h are modified]]
N.B. In the example pictures, there is a project with a custom static library, which is linked against the test application.
N.B. In the example pictures, there is a project with a custom static library, which is linked against the test application.
-
== Simple Real Example ==
+
=== Simple Real Example ===
Before delving too deeply into the syntax of makefiles, it is instructive to first see make in action. For this, a simple project will be used, written in the C language.
Before delving too deeply into the syntax of makefiles, it is instructive to first see make in action. For this, a simple project will be used, written in the C language.
Line 42: Line 38:
In C, it is customary to write "header" files (conventional suffix for them is '''.h''') and regular source files ('''.c'''). The header files describe calling conventions, APIs and structures that are to be made usable for the outside world. The .c files contain the implementation of these interfaces.
In C, it is customary to write "header" files (conventional suffix for them is '''.h''') and regular source files ('''.c'''). The header files describe calling conventions, APIs and structures that are to be made usable for the outside world. The .c files contain the implementation of these interfaces.
-
The first rule in this is: if something is changed in the interface file, then the binary file containing the code implementation (and other files that use the same interface) must be regenerated. Regeneration in this case means invoking gcc to create the binary file out of the C-language source file.
+
The first rule in this is: if something is changed in the interface file, the binary file containing the code implementation (and other files that use the same interface) must be regenerated. Regeneration in this case means invoking gcc to create the binary file out of the C-language source file.
Make needs to be told two things at this point:
Make needs to be told two things at this point:
Line 49: Line 45:
* What are the commands to regenerate the resulting files when the need arises?
* What are the commands to regenerate the resulting files when the need arises?
-
This example deals with that as simply as possible. There is a project that consists of two source files and one header file. The contents of these files are listed below: simple-make-files/hello.c
+
This example deals with that as simply as possible. There is a project that consists of two source files and one header file. The contents of these files are listed below: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/hello.c simple-make-files/hello.c]
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
<source lang="c">
-
  <span>''<span><font color="#9A1900"> * The old faithful hello world.</font></span>''</span>
+
/**
-
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
+
  * The old faithful hello world.
-
  <span>''<span><font color="#9A1900"> * This maemo code example is licensed under a MIT-style license,</font></span>''</span>
+
  *
-
  <span>''<span><font color="#9A1900"> * that can be found in the file called "License" in the same</font></span>''</span>
+
  * This maemo code example is licensed under a MIT-style license,
-
  <span>''<span><font color="#9A1900"> * directory as this file.</font></span>''</span>
+
  * that can be found in the file called "License" in the same
-
  <span>''<span><font color="#9A1900"> * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.</font></span>''</span>
+
  * directory as this file.
-
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
+
  * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;stdlib.h&gt;</font></span>    <span>''<span><font color="#9A1900">/* EXIT_* */</font></span>''</span>
+
  */
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">"hello_api.h"</font></span> <span>''<span><font color="#9A1900">/* sayhello */</font></span>''</span>
+
#include <stdlib.h>    /* EXIT_* */
-
<span><font color="#009900">int</font></span> <span>'''<span><font color="#000000">main</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#009900">int</font></span> argc<span><font color="#990000">,</font></span> <span><font color="#009900">char</font></span> <span><font color="#990000"><nowiki>**</nowiki></font></span>argv<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
+
#include "hello_api.h" /* sayhello */
-
  <span>'''<span><font color="#000000">sayhello</font></span>'''</span><span><font color="#990000">();</font></span>
+
int main(int argc, char **argv) {
-
  <span>'''<span><font color="#0000FF">return</font></span>'''</span> EXIT_SUCCESS<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
  sayhello();
-
<span><font color="#FF0000">}</font></span>
+
  return EXIT_SUCCESS;
-
</tt>
+
}
 +
</source>
-
simple-make-files/hello_func.c
+
[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/hello_func.c simple-make-files/hello_func.c]
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
<source lang="c">
-
  <span>''<span><font color="#9A1900"> * Implementation of sayhello.</font></span>''</span>
+
/**
-
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
+
  * Implementation of sayhello.
-
  <span>''<span><font color="#9A1900"> * This maemo code example is licensed under a MIT-style license,</font></span>''</span>
+
  *
-
  <span>''<span><font color="#9A1900"> * that can be found in the file called "License" in the same</font></span>''</span>
+
  * This maemo code example is licensed under a MIT-style license,
-
  <span>''<span><font color="#9A1900"> * directory as this file.</font></span>''</span>
+
  * that can be found in the file called "License" in the same
-
  <span>''<span><font color="#9A1900"> * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.</font></span>''</span>
+
  * directory as this file.
-
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
+
  * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
-
+
  */
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;stdio.h&gt;</font></span>    <span>''<span><font color="#9A1900">/* printf */</font></span>''</span>
+
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">"hello_api.h"</font></span> <span>''<span><font color="#9A1900">/* sayhello declaration */</font></span>''</span>
+
-
+
-
<span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">sayhello</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#009900">void</font></span><span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
+
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Hello world!</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
-
<span><font color="#FF0000">}</font></span>
+
-
</tt>
+
-
simple-make-files/hello_api.h
+
#include <stdio.h>    /* printf */
 +
#include "hello_api.h" /* sayhello declaration */
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
void sayhello(void) {
-
<span>''<span><font color="#9A1900"> * Interface description for the hello_func module.</font></span>''</span>
+
  printf("Hello world!\n");
-
  <span>''<span><font color="#9A1900"> *</font></span>''</span>
+
}
-
  <span>''<span><font color="#9A1900"> * This maemo code example is licensed under a MIT-style license,</font></span>''</span>
+
</source>
-
  <span>''<span><font color="#9A1900"> * that can be found in the file called "License" in the same</font></span>''</span>
+
 
-
  <span>''<span><font color="#9A1900"> * directory as this file.</font></span>''</span>
+
[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/hello_api.h simple-make-files/hello_api.h]
-
  <span>''<span><font color="#9A1900"> * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.</font></span>''</span>
+
 
-
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
+
<source lang="c">
-
+
/**
-
<span>'''<span><font color="#000080"><nowiki>#ifndef</nowiki></font></span>'''</span> INCLUDE_HELLO_API_H
+
* Interface description for the hello_func module.
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> INCLUDE_HELLO_API_H
+
  *
-
<span>''<span><font color="#9A1900">/* The above is protection against circular header inclusion. */</font></span>''</span>
+
  * This maemo code example is licensed under a MIT-style license,
-
+
  * that can be found in the file called "License" in the same
-
<span>''<span><font color="#9A1900">/* Function to print out "Hello world!\n". */</font></span>''</span>
+
  * directory as this file.
-
<span>'''<span><font color="#0000FF">extern</font></span>'''</span> <span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">sayhello</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#009900">void</font></span><span><font color="#990000">);</font></span>
+
  * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
-
+
  */
-
<span>'''<span><font color="#000080"><nowiki>#endif</nowiki></font></span>'''</span>
+
 
-
<span>''<span><font color="#9A1900">/* ifndef INCLUDE_HELLO_API_H */</font></span>''</span>
+
#ifndef INCLUDE_HELLO_API_H
-
</tt>
+
#define INCLUDE_HELLO_API_H
 +
/* The above is protection against circular header inclusion. */
 +
 
 +
/* Function to print out "Hello world!\n". */
 +
extern void sayhello(void);
 +
 
 +
#endif
 +
/* ifndef INCLUDE_HELLO_API_H */
 +
</source>
So, in effect, there is the main application in '''hello.c''', which uses a function that is implemented in '''hello_func.c''' and declared in '''hello_api.h'''. Building an application out of these files can be performed manually like this:
So, in effect, there is the main application in '''hello.c''', which uses a function that is implemented in '''hello_func.c''' and declared in '''hello_api.h'''. Building an application out of these files can be performed manually like this:
Line 112: Line 111:
  gcc -Wall hello.c hello_func.c -o hello
  gcc -Wall hello.c hello_func.c -o hello
-
Or, it could be done in three stages:
+
Or, it can be done in three stages:
  gcc -Wall -c hello.c -o hello.o
  gcc -Wall -c hello.c -o hello.o
Line 124: Line 123:
In the second case, gcc is instructed to create a binary object file for each of the source files. After that, gcc is instructed to link these output files ('''hello.o''' and '''hello_func.o''') together, and store the linked code into '''hello'''.
In the second case, gcc is instructed to create a binary object file for each of the source files. After that, gcc is instructed to link these output files ('''hello.o''' and '''hello_func.o''') together, and store the linked code into '''hello'''.
-
N.B. When gcc reads through the C source files, it also reads in the header files, because the C code uses the #include -preprocessor directive. This is because gcc internally runs all files ending with .c through cpp (the preprocessor) first.
+
{{ambox|text=When gcc reads through the C source files, it also reads in the header files, because the C code uses the <code>#include</code> preprocessor directive. This is because gcc internally runs all files ending with .c through cpp (the preprocessor) first.}}
-
The file describing this situation to make is as follows: simple-make-files/Makefile
+
The file describing this situation to make is as follows: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile simple-make-files/Makefile]
-
<tt><span>''<span><font color="#9A1900"><nowiki># define default target (first target = default)</nowiki></font></span>''</span>
+
<source lang="make">
-
<span>''<span><font color="#9A1900"><nowiki># it depends on 'hello.o' (which will be created if necessary)</nowiki></font></span>''</span>
+
# define default target (first target = default)
-
<span>''<span><font color="#9A1900"><nowiki># and hello_func.o (same as hello.o)</nowiki></font></span>''</span>
+
# it depends on 'hello.o' (which will be created if necessary)
-
hello<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
# and hello_func.o (same as hello.o)
-
        gcc -Wall hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o -o hello
+
hello: hello.o hello_func.o
-
<span>''<span><font color="#9A1900"><nowiki># define hello.o target</nowiki></font></span>''</span>
+
        gcc -Wall hello.o hello_func.o -o hello
-
<span>''<span><font color="#9A1900"><nowiki># it depends on hello.c (and is created from it)</nowiki></font></span>''</span>
+
# define hello.o target
-
<span>''<span><font color="#9A1900"><nowiki># also depends on hello_api.h which would mean that</nowiki></font></span>''</span>
+
# it depends on hello.c (and is created from it)
-
<span>''<span><font color="#9A1900"><nowiki># changing the hello.h api would force make to rebuild</nowiki></font></span>''</span>
+
# also depends on hello_api.h which would mean that
-
<span>''<span><font color="#9A1900"><nowiki># this target (hello.o).</nowiki></font></span>''</span>
+
# changing the hello.h api would force make to rebuild
-
<span>''<span><font color="#9A1900"><nowiki># gcc -c: compile only, do not link</nowiki></font></span>''</span>
+
# this target (hello.o).
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
# gcc -c: compile only, do not link
-
        gcc -Wall -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
<span>''<span><font color="#9A1900"><nowiki># define hello_func.o target</nowiki></font></span>''</span>
+
        gcc -Wall -c hello.c -o hello.o
-
<span>''<span><font color="#9A1900"><nowiki># it depends on hello_func.c (and is created from)</nowiki></font></span>''</span>
+
# define hello_func.o target
-
<span>''<span><font color="#9A1900"><nowiki># and hello_api.h (since that's its declaration)</nowiki></font></span>''</span>
+
# it depends on hello_func.c (and is created from)
-
hello_func<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello_func<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
# and hello_api.h (since that's its declaration)
-
        gcc -Wall -c hello_func<span><font color="#990000">.</font></span>c -o hello_func<span><font color="#990000">.</font></span>o
+
hello_func.o: hello_func.c hello_api.h
-
<span>''<span><font color="#9A1900"><nowiki># </nowiki></font></span>''</span></tt>
+
        gcc -Wall -c hello_func.c -o hello_func.o
 +
#  
 +
</source>
This file is in the simplest form without using any variables or relying on built-in magic in GNU make. Later it will be shown that the same rules can be written in a much shorter way.
This file is in the simplest form without using any variables or relying on built-in magic in GNU make. Later it will be shown that the same rules can be written in a much shorter way.
Line 175: Line 176:
  Hello world!
  Hello world!
-
== Anatomy of Makefile ==
+
=== Anatomy of Makefile ===
-
From the simple example above, some of syntax of 'make' can be deduced.
+
From the simple example above, some of the syntax of 'make' can be deduced.
Here are the rules that can be learned:
Here are the rules that can be learned:
Line 195: Line 196:
* If either '''hello_func.c''' or '''hello_api.h''' change, make regenerates <br />'''hello_func.o'''.
* If either '''hello_func.c''' or '''hello_api.h''' change, make regenerates <br />'''hello_func.o'''.
-
== Default Goal ==
+
=== Default Goal ===
Note that make was not explicitly told what it should do by default when run without any command line parameters (as was done above). How does it know that creating '''hello''' is the target for the run?
Note that make was not explicitly told what it should do by default when run without any command line parameters (as was done above). How does it know that creating '''hello''' is the target for the run?
Line 205: Line 206:
N.B. Make automatically learns the dependencies between the various components and deduces that to create '''hello''', it also needs to create '''hello.o''' and '''hello_func.o'''. Make regenerates the missing prerequisites when necessary. In fact, this is a quality that causes make do its magic.
N.B. Make automatically learns the dependencies between the various components and deduces that to create '''hello''', it also needs to create '''hello.o''' and '''hello_func.o'''. Make regenerates the missing prerequisites when necessary. In fact, this is a quality that causes make do its magic.
-
Since the prerequisites for hello (hello.o and hello_func.o) do not exist, and hello is the default goal, make first creates the files that the hello target needs. This can be evidenced from the screen capture of make running without command line parameters. It shows the execution of each command in the order that make decides is necessary to satisfy the default goal's prerequisites, and finally create the hello.
+
Because the prerequisites for hello (hello.o and hello_func.o) do not exist, and hello is the default goal, make first creates the files that the hello target needs. This can be evidenced from the screen capture of make running without command line parameters. It shows the execution of each command in the order that make decides is necessary to satisfy the default goal's prerequisites, and finally create the hello.
  user@system:~$ make
  user@system:~$ make
Line 212: Line 213:
  gcc -Wall hello.o hello_func.o -o hello
  gcc -Wall hello.o hello_func.o -o hello
-
 
+
=== Names of Makefiles ===
-
== Names of Makefiles ==
+
The recommended name for the makefile is '''Makefile'''. This is not the first filename that GNU make tries to open, but it is the most portable one. In fact, the order of filenames that make attempts to open is: '''GNUMakefile''', '''Makefile''' and finally '''makefile'''.
The recommended name for the makefile is '''Makefile'''. This is not the first filename that GNU make tries to open, but it is the most portable one. In fact, the order of filenames that make attempts to open is: '''GNUMakefile''', '''Makefile''' and finally '''makefile'''.
-
Unless you are sure that your makefile does not work on other make systems (not GNU), you should refrain from using GNUMakefile. Makefile will be used here for the most of this material. The idea behind using Makefile instead of makefile is related to how shells and commands sort filenames, when contents of directories are requested. Because in ASCII the uppercase letters come before the lowercase letters, the important files are listed first. Makefiles are considered important, because they are the basis for building the project. (The collation order might be different in your locale and your environment.)
+
Unless you are sure that your makefile does not work on other make systems (not GNU), refrain from using GNUMakefile. Makefile will be used here for the most of this material. The idea behind using Makefile instead of makefile is related to how shells and commands sort filenames, when contents of directories are requested. Because in ASCII the uppercase letters come before the lowercase letters, the important files are listed first. Makefiles are considered important, because they are the basis for building the project. (The collation order might be different in your locale and your environment.)
Make can explicitly be told which file to read by using the -f command line option. This option is used in the next example.
Make can explicitly be told which file to read by using the -f command line option. This option is used in the next example.
-
== Questions ==
+
=== Questions ===
Based on common sense, what should make do when it is run after:
Based on common sense, what should make do when it is run after:
Line 234: Line 234:
What would be done when writing the commands manually?
What would be done when writing the commands manually?
-
== Adding Make Goals ==
+
=== Adding Make Goals ===
Sometimes it is useful to add targets, whose execution does not result in a file, but instead causes some commands to be run. This is commonly used in makefiles of software projects to get rid of the binary files, so that building can be attempted from a clean state. These kinds of targets can also be justifiably called goals. GNU documentation uses the name "phony target" for these kinds of targets, because they do not result in creating a file, like normal targets do.
Sometimes it is useful to add targets, whose execution does not result in a file, but instead causes some commands to be run. This is commonly used in makefiles of software projects to get rid of the binary files, so that building can be attempted from a clean state. These kinds of targets can also be justifiably called goals. GNU documentation uses the name "phony target" for these kinds of targets, because they do not result in creating a file, like normal targets do.
The next step is to create a copy of the original makefile, and add a goal that removes the binary object files and the application.  
The next step is to create a copy of the original makefile, and add a goal that removes the binary object files and the application.  
-
N.B. Other parts of the makefile do not change. simple-make-files/Makefile.2
+
N.B. Other parts of the makefile do not change. [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.2 simple-make-files/Makefile.2]
-
<tt><span>''<span><font color="#9A1900"><nowiki># add a cleaning target (to get rid of the binaries)</nowiki></font></span>''</span>
+
<source lang="make">
-
<span>''<span><font color="#9A1900"><nowiki># define default target (first target = default)</nowiki></font></span>''</span>
+
# add a cleaning target (to get rid of the binaries)
-
<span>''<span><font color="#9A1900"><nowiki># it depends on 'hello.o' (which must exist)</nowiki></font></span>''</span>
+
# define default target (first target = default)
-
<span>''<span><font color="#9A1900"><nowiki># and hello_func.o</nowiki></font></span>''</span>
+
# it depends on 'hello.o' (which must exist)
-
hello<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
# and hello_func.o
-
        gcc -Wall hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o -o hello
+
hello: hello.o hello_func.o
-
<span>''<span><font color="#9A1900"><nowiki># define hello.o target</nowiki></font></span>''</span>
+
        gcc -Wall hello.o hello_func.o -o hello
-
<span>''<span><font color="#9A1900"><nowiki># it depends on hello.c (and is created from)</nowiki></font></span>''</span>
+
# define hello.o target
-
<span>''<span><font color="#9A1900"><nowiki># also depends on hello_api.h which would mean that</nowiki></font></span>''</span>
+
# it depends on hello.c (and is created from)
-
<span>''<span><font color="#9A1900"><nowiki># changing the hello.h api would force make to rebuild</nowiki></font></span>''</span>
+
# also depends on hello_api.h which would mean that
-
<span>''<span><font color="#9A1900"><nowiki># this target (hello.o).</nowiki></font></span>''</span>
+
# changing the hello.h api would force make to rebuild
-
<span>''<span><font color="#9A1900"><nowiki># gcc -c: compile only, do not link</nowiki></font></span>''</span>
+
# this target (hello.o).
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
# gcc -c: compile only, do not link
-
        gcc -Wall -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
<span>''<span><font color="#9A1900"><nowiki># define hello_func.o target</nowiki></font></span>''</span>
+
        gcc -Wall -c hello.c -o hello.o
-
<span>''<span><font color="#9A1900"><nowiki># it depends on hello_func.c (and is created from)</nowiki></font></span>''</span>
+
# define hello_func.o target
-
<span>''<span><font color="#9A1900"><nowiki># and hello_api.h (since that's it's declaration)</nowiki></font></span>''</span>
+
# it depends on hello_func.c (and is created from)
-
hello_func<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello_func<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
# and hello_api.h (since that's it's declaration)
-
        gcc -Wall -c hello_func<span><font color="#990000">.</font></span>c -o hello_func<span><font color="#990000">.</font></span>o
+
hello_func.o: hello_func.c hello_api.h
-
<span>''<span><font color="#9A1900"><nowiki># This is the definition of the target 'clean'</nowiki></font></span>''</span>
+
        gcc -Wall -c hello_func.c -o hello_func.o
-
<span>''<span><font color="#9A1900"><nowiki># Here we'll remove all the built binaries and</nowiki></font></span>''</span>
+
# This is the definition of the target 'clean'
-
<span>''<span><font color="#9A1900"><nowiki># all the object files that we might have generated</nowiki></font></span>''</span>
+
# Here we'll remove all the built binaries and
-
<span>''<span><font color="#9A1900"><nowiki># Notice the -f flag for rm, it means "force" which</nowiki></font></span>''</span>
+
# all the object files that we might have generated
-
<span>''<span><font color="#9A1900"><nowiki># in turn means that rm will try to remove the given</nowiki></font></span>''</span>
+
# Notice the -f flag for rm, it means "force" which
-
<span>''<span><font color="#9A1900"><nowiki># files, and if there are none, then that's ok. Also</nowiki></font></span>''</span>
+
# in turn means that rm will try to remove the given
-
<span>''<span><font color="#9A1900"><nowiki># it means that we have no writing permission to that</nowiki></font></span>''</span>
+
# files, and if there are none, then that's ok. Also
-
<span>''<span><font color="#9A1900"><nowiki># file and have writing permission to the directory</nowiki></font></span>''</span>
+
# it means that we have no writing permission to that
-
<span>''<span><font color="#9A1900"><nowiki># holding the file, rm will not then ask for permission</nowiki></font></span>''</span>
+
# file and have writing permission to the directory
-
<span>''<span><font color="#9A1900"><nowiki># interactivelly.</nowiki></font></span>''</span>
+
# holding the file, rm will not then ask for permission
-
clean<span><font color="#990000"><nowiki>:</nowiki></font></span>
+
# interactivelly.
-
        rm -f hello hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
clean:
-
</tt>
+
        rm -f hello hello.o hello_func.o
 +
</source>
To get make to use this file instead of the default Makefile, use the -f command line parameter as follows:
To get make to use this file instead of the default Makefile, use the -f command line parameter as follows:
Line 296: Line 297:
  -rw-r--r-- 1  user user 130  Jun 1  14:48 hello_func.c
  -rw-r--r-- 1  user user 130  Jun 1  14:48 hello_func.c
-
== Making One Target at a Time ==
+
=== Making One Target at a Time ===
Sometimes it is useful to ask make to process only one target. Similar to the clean case, it just needs the target name to be given on the command line:
Sometimes it is useful to ask make to process only one target. Similar to the clean case, it just needs the target name to be given on the command line:
Line 309: Line 310:
  gcc -Wall hello.o hello_func.o -o hello
  gcc -Wall hello.o hello_func.o -o hello
-
This can be done with any number of targets, even phony ones. Make tries to complete all of them in the order that they are on the command line. Should any of the commands within the targets fail, make aborts at that point, and does not pursue the rest of the targets.
+
This can be done with any number of targets, even phony ones. Make tries to complete all of them in the order that they are on the command line. If any of the commands within the targets fail, make aborts at that point, and does not pursue the rest of the targets.
-
==PHONY Keyword ==
+
=== PHONY Keyword ===
Suppose that for some reason a file called '''clean''' appears in the directory in which make is run with clean as the target. In this case, make probably decides that because clean already exists, there is no need to run the commands leading to the target, and in this case, make does not run the rm command at all. Clearly this is something that needs to be avoided.
Suppose that for some reason a file called '''clean''' appears in the directory in which make is run with clean as the target. In this case, make probably decides that because clean already exists, there is no need to run the commands leading to the target, and in this case, make does not run the rm command at all. Clearly this is something that needs to be avoided.
-
For these cases, GNU make provides a special target called '''.PHONY''' (note the leading dot). The real phony targets (clean) will be listed as a dependency to .PHONY. This will signal to make that it should never consider a file called clean to be the result of the phony target.
+
For these cases, GNU make provides a special target called <code>.PHONY</code> (note the leading dot). The real phony targets (clean) will be listed as a dependency to <code>.PHONY</code>. This signals to make that it should never consider a file called clean to be the result of the phony target.
In fact, this is what most open source projects that use make do.
In fact, this is what most open source projects that use make do.
-
This leads in the following makefile (comments omitted for brevity): simple-make-files/Makefile.3
+
This leads in the following makefile (comments omitted for brevity): [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.3 simple-make-files/Makefile.3]
-
<tt>hello<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
<source lang="make">
-
        gcc -Wall hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o -o hello
+
hello: hello.o hello_func.o
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        gcc -Wall hello.o hello_func.o -o hello
-
        gcc -Wall -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
hello_func<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello_func<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        gcc -Wall -c hello.c -o hello.o
-
        gcc -Wall -c hello_func<span><font color="#990000">.</font></span>c -o hello_func<span><font color="#990000">.</font></span>o
+
hello_func.o: hello_func.c hello_api.h
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> clean
+
        gcc -Wall -c hello_func.c -o hello_func.o
-
clean<span><font color="#990000"><nowiki>:</nowiki></font></span>
+
.PHONY: clean
-
        rm -f hello hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
clean:
-
</tt>
+
        rm -f hello hello.o hello_func.o
 +
</source>
-
== Specifying Default Goal ==
+
=== Specifying Default Goal ===
Make uses the first target in a makefile as its default goal. What if there is a need to explicitly set the default goal instead? Because it is not possible to actually change the "first target is the default goal" setting in make, this needs to be taken into account. So, a new target has to be added, and made sure that it will be processed as the first target in a makefile.
Make uses the first target in a makefile as its default goal. What if there is a need to explicitly set the default goal instead? Because it is not possible to actually change the "first target is the default goal" setting in make, this needs to be taken into account. So, a new target has to be added, and made sure that it will be processed as the first target in a makefile.
-
To achieve this, a new phony target should be created, and the wanted targets should be listed as the phony target's prerequisites. Any name can be used for the target, but all is a very common name for this use. The only thing that needs to be rememberd is that this target needs to be the first one in the makefile. simple-make-files/Makefile.4
+
To achieve this, a new phony target must be created, and the wanted targets should be listed as the phony target's prerequisites. Any name can be used for the target, but all is a very common name for this use. The only thing that needs to be rememberd is that this target needs to be the first one in the makefile. [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.4 simple-make-files/Makefile.4]
-
<tt><span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> all
+
<source lang="make">
-
all<span><font color="#990000"><nowiki>:</nowiki></font></span> hello
+
.PHONY: all
-
hello<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
all: hello
-
        gcc -Wall hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o -o hello
+
hello: hello.o hello_func.o
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        gcc -Wall hello.o hello_func.o -o hello
-
        gcc -Wall -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
hello_func<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello_func<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        gcc -Wall -c hello.c -o hello.o
-
        gcc -Wall -c hello_func<span><font color="#990000">.</font></span>c -o hello_func<span><font color="#990000">.</font></span>o
+
hello_func.o: hello_func.c hello_api.h
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> clean
+
        gcc -Wall -c hello_func.c -o hello_func.o
-
clean<span><font color="#990000"><nowiki>:</nowiki></font></span>
+
.PHONY: clean
-
        rm -f hello hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
clean:
-
</tt>
+
        rm -f hello hello.o hello_func.o
 +
</source>
-
Something peculiar can be seen in the listing above. Because the first target is the default goal for make, would that not make .PHONY now to be the default target? Because .PHONY is a special target in GNU make, this is safe. Also, because of compatibility reasons, GNU make ignores any targets that start with a leading dot (.) when looking for the default goal.
+
Something peculiar can be seen in the listing above. Because the first target is the default goal for make, would that not make <code>.PHONY</code> now to be the default target? Because <code>.PHONY</code> is a special target in GNU make, this is safe. Also, because of compatibility reasons, GNU make ignores any targets that start with a leading dot (.) when looking for the default goal.
-
== Other Common Phony Goals ==
+
=== Other Common Phony Goals ===
-
Many other phony goals will be encountered in makefiles that projects use.
+
Many other phony goals are encountered in makefiles that projects use.
Some of the more common ones include:
Some of the more common ones include:
-
* install: Prerequisites for install is the software application binary (or binaries). The commands (normally ''install'' is used on Linux) will specify which binary file to place under which directory on the system (/usr/bin, /usr/local/bin, etc).
+
* install: Prerequisites for install is the software application binary (or binaries). The commands (normally ''install'' is used on Linux) will specify which binary file to place under which directory on the system (<code>/usr/bin</code>, <code>/usr/local/bin</code>, etc).
* distclean: Similar to clean; removes object files and such, but removes other files as well (sounds scary). Normally this is used to implement the removal of Makefile in the case that it was created by some automatic tool (''configure'' for example).
* distclean: Similar to clean; removes object files and such, but removes other files as well (sounds scary). Normally this is used to implement the removal of Makefile in the case that it was created by some automatic tool (''configure'' for example).
* package: Prerequisites are as in install, but instead of installing, creates an archive file (''tar'') with the files in question. This archive can then be used to distribute the software.
* package: Prerequisites are as in install, but instead of installing, creates an archive file (''tar'') with the files in question. This archive can then be used to distribute the software.
-
Other common phony targets can be found in the [http://www.gnu.org/software/make/manual/make.html GNU make manual].
+
For information on other common phony targets, see [http://www.gnu.org/software/make/manual/make.html GNU make manual].
-
== Variables in Makefiles ==
+
=== Variables in Makefiles ===
So far these files have been listing filenames explicitly. Writing makefiles this way can get rather tedious, if not error prone.
So far these files have been listing filenames explicitly. Writing makefiles this way can get rather tedious, if not error prone.
Line 373: Line 376:
Variables work almost as they do inside regular UNIX command shells. They are a simple mechanism, by which a piece of text can be associated with a name that can be referenced later on in multiple places in the makefiles. Make variables are based on text replacement, just like shell variables are.
Variables work almost as they do inside regular UNIX command shells. They are a simple mechanism, by which a piece of text can be associated with a name that can be referenced later on in multiple places in the makefiles. Make variables are based on text replacement, just like shell variables are.
-
== Variable Flavors ==
+
==== Variable Flavors ====
The variables that can be used in makefiles come in two basic styles or flavors.
The variables that can be used in makefiles come in two basic styles or flavors.
-
The default flavor is where referencing a variable will cause make to expand the variable contents at the point of reference. This means that if the value of the variable is some text in which other variables are referenced, their contents will also be replaced automatically. This flavor is called recursive.
+
The default flavor is where referencing a variable causes make to expand the variable contents at the point of reference. This means that if the value of the variable is some text in which other variables are referenced, their contents is also replaced automatically. This flavor is called recursive.
The other flavor is simple, meaning that the content of a variable is evaluated only once, when the variable is defined.
The other flavor is simple, meaning that the content of a variable is evaluated only once, when the variable is defined.
-
Deciding on which flavor to use might be important, when the evaluation of variable contents needs to be repeatable and fast. In these cases, simple variables are often the correct solution.
+
Deciding on which flavor to use is important, when the evaluation of variable contents needs to be repeatable and fast. In these cases, simple variables are often the correct solution.
-
== Recursive Variables ==
+
===== Recursive Variables =====
Here are the rules for creating recursive variables:
Here are the rules for creating recursive variables:
* Names must contain only ASCII alphanumerics and underscores (to preserve portability).
* Names must contain only ASCII alphanumerics and underscores (to preserve portability).
-
* Only lowercase letters should be used in the names of the variables. Make is case sensitive, and variable names written in capital letters are used when it is necessary to communicate the variables outside make, or their origin is from outside (environment variables). This is, however, only a convention, and there will also be variables that are local to the makefile, but still written in uppercase.
+
* Use only lowercase letters in the names of the variables. Make is case sensitive, and variable names written in capital letters are used when it is necessary to communicate the variables outside make, or their origin is from outside (environment variables). This is, however, only a convention, and there will also be variables that are local to the makefile, but still written in uppercase.
-
* Values may contain any text. The text will be evaluated by make when the variable is used, not when it is defined.
+
* Values can contain any text. The text is evaluated by make when the variable is used, not when it is defined.
-
* Long lines may be broken up with a backslash character (<code>\</code>) and newline combination. This same mechanism can be used to continue other long lines as well (not just variables). Do not put any whitespace after the backslash.
+
* Break up long lines with a backslash character (<code>\</code>) and newline combination. Use this same mechanism to continue other long lines as well (not just variables). Do not put any whitespace after the backslash.
-
* A variable that is being defined should not be referenced in its text portion. This would result in an endless loop whenever this variable is used. If this happens GNU make will stop to an error.
+
* Do not reference a variable that is being defined in its text portion. This results in an endless loop whenever this variable is used. If this happens GNU make stops to an error.
-
Now the previously used makefile will be reused, but some variables will be introduced. This also shows the syntax of defining the variables, and how to use them (reference them): simple-make-files/Makefile.5
+
Now the previously used makefile is reused, but some variables are introduced. This also shows the syntax of defining the variables, and how to use them (reference them): [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.5 simple-make-files/Makefile.5]
-
<tt><span>''<span><font color="#9A1900"><nowiki># define the command that we use for compilation</nowiki></font></span>''</span>
+
<source lang="make">
-
CC <span><font color="#990000"><nowiki>=</nowiki></font></span> gcc -Wall
+
# define the command that we use for compilation
-
<span>''<span><font color="#9A1900"><nowiki># which targets do we want to build by default?</nowiki></font></span>''</span>
+
CC = gcc -Wall
-
<span>''<span><font color="#9A1900"><nowiki># note that 'targets' is just a variable, its name</nowiki></font></span>''</span>
+
# which targets do we want to build by default?
-
<span>''<span><font color="#9A1900"><nowiki># does not have any special meaning to make</nowiki></font></span>''</span>
+
# note that 'targets' is just a variable, its name
-
targets <span><font color="#990000"><nowiki>=</nowiki></font></span> hello
+
# does not have any special meaning to make
-
<span>''<span><font color="#9A1900"><nowiki># first target defined will be the default target</nowiki></font></span>''</span>
+
targets = hello
-
<span>''<span><font color="#9A1900"><nowiki># we use the variable to hold the dependencies</nowiki></font></span>''</span>
+
# first target defined will be the default target
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> all
+
# we use the variable to hold the dependencies
-
all<span><font color="#990000"><nowiki>:</nowiki></font></span> <span><font color="#009900">$(targets)</font></span>
+
.PHONY: all
-
hello<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
all: $(targets)
-
        <span><font color="#009900">$(CC)</font></span> hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o -o hello
+
hello: hello.o hello_func.o
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        $(CC) hello.o hello_func.o -o hello
-
        <span><font color="#009900">$(CC)</font></span> -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
hello_func<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello_func<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        $(CC) -c hello.c -o hello.o
-
        <span><font color="#009900">$(CC)</font></span> -c hello_func<span><font color="#990000">.</font></span>c -o hello_func<span><font color="#990000">.</font></span>o
+
hello_func.o: hello_func.c hello_api.h
-
<span>''<span><font color="#9A1900"><nowiki># we'll make our cleaning target more powerful</nowiki></font></span>''</span>
+
        $(CC) -c hello_func.c -o hello_func.o
-
<span>''<span><font color="#9A1900"><nowiki># we remove the targets that we build by default and also</nowiki></font></span>''</span>
+
# we'll make our cleaning target more powerful
-
<span>''<span><font color="#9A1900"><nowiki># remove all object files</nowiki></font></span>''</span>
+
# we remove the targets that we build by default and also
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> clean
+
# remove all object files
-
clean<span><font color="#990000"><nowiki>:</nowiki></font></span>
+
.PHONY: clean
-
        rm -f <span><font color="#009900">$(targets)</font></span> <span><font color="#990000"><nowiki>*.</nowiki></font></span>o
+
clean:
-
</tt>
+
        rm -f $(targets) *.o
 +
</source>
-
The CC variable is the standard variable to hold the name of the C compiler executable. GNU make comes preloaded with a list of tools that can be accessed in similar way (as will be shown with $(RM) shortly, but there are others). Most UNIX tools related to building software already have similar pre-defined variables in GNU make. Here one of them will be overridden for no other reason than to demonstrate how it is done. Overriding variables like this is not recommended, since the user running make later might want to use some other compiler, and would have to edit the makefile to do so.
+
The CC variable is the standard variable to hold the name of the C compiler executable. GNU make comes preloaded with a list of tools that can be accessed in similar way (as will be shown with $(RM) shortly, but there are others). Most UNIX tools related to building software already have similar pre-defined variables in GNU make. Here one of them is overridden to demonstrate how it is done. Overriding variables like this is not recommended, because the user running make later might want to use some other compiler, and would have to edit the makefile to do so.
-
== Simple Variables ==
+
===== Simple Variables =====
-
Suppose you have a makefile like this: simple-make-files/Makefile.6
+
Suppose you have a makefile like this: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.6 simple-make-files/Makefile.6]
-
<tt>CC <span><font color="#990000"><nowiki>=</nowiki></font></span> gcc -Wall
+
<source lang="make">
-
<span>''<span><font color="#9A1900"><nowiki># we want to add something to the end of the variable</nowiki></font></span>''</span>
+
CC = gcc -Wall
-
CC <span><font color="#990000"><nowiki>=</nowiki></font></span> <span><font color="#009900">$(CC)</font></span> -g
+
# we want to add something to the end of the variable
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
CC = $(CC) -g
-
        <span><font color="#009900">$(CC)</font></span> -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
</tt>
+
        $(CC) -c hello.c -o hello.o
 +
</source>
-
What might seem quite logical to a human reader, will not seem very logical to make.
+
What might seem quite logical to a human reader, does not seem very logical to make.
-
Since the contents of recursive variables are evaluated when they are referenced, it can be seen that the above fragment will lead to an infinite loop.
+
Because the contents of recursive variables are evaluated when they are referenced, it can be seen that the above fragment will lead to an infinite loop.
-
How can this be corrected? Make actually provides two mechanisms for this. This is the solution with simple variables: simple-make-files/Makefile.7
+
How can this be corrected? Make actually provides two mechanisms for this. This is the solution with simple variables: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.7 simple-make-files/Makefile.7]
-
<tt>CC <span><font color="#990000"><nowiki>:=</nowiki></font></span> gcc -Wall
+
<source lang="make">
-
<span>''<span><font color="#9A1900"><nowiki># we want to add something to the end of the variable</nowiki></font></span>''</span>
+
CC := gcc -Wall
-
CC <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(CC)</font></span> -g
+
# we want to add something to the end of the variable
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
CC := $(CC) -g
-
        <span><font color="#009900">$(CC)</font></span> -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
</tt>
+
        $(CC) -c hello.c -o hello.o
 +
</source>
Notice that the equals character (=) has been changed into := .
Notice that the equals character (=) has been changed into := .
-
This is how simple variables are created. Whenever a simple variable is referenced, make will just replace the text that is contained in the variable without evaluating it. It will do the evaluation only when the variable is defined. In the above example, CC is created with the content of gcc -Wall (which is evaluated, but is just plain text), and when the CC variable is defined next time, make will evaluate $(CC) -g which will be replaced with gcc -Wall -g, as one might expect.
+
This is how simple variables are created. Whenever a simple variable is referenced, make just replaces the text that the variable contains without evaluating it. It does the evaluation only when the variable is defined. In the above example, <code>CC</code> is created with the content of <code>gcc -Wall</code> (which is evaluated, but is just plain text), and when the <code>CC</code> variable is defined next time, make evaluates <code>$(CC) -g</code> which is replaced with <code>gcc -Wall -g</code>.
So, the only two differences between the variable flavors are:
So, the only two differences between the variable flavors are:
Line 454: Line 460:
* make evaluates the contents, when the simple variable is defined, not when it is referenced later.
* make evaluates the contents, when the simple variable is defined, not when it is referenced later.
-
Most of the time it is advisable to use the recursive variable flavor, since it does what is wanted.
+
Most of the time it is advisable to use the recursive variable flavor, because it does what is wanted.
-
There was a mention about two ways of appending text to an existing variable. The other mechanism is the += operation as follows: simple-make-files/Makefile.8
+
Two ways of appending text to an existing variable were mentioned. The other mechanism is the += operation as follows: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.8 simple-make-files/Makefile.8]
-
<tt>CC <span><font color="#990000"><nowiki>=</nowiki></font></span> gcc -Wall
+
<source lang="make">
-
<span>''<span><font color="#9A1900"><nowiki># we want to add something to the end of the variable</nowiki></font></span>''</span>
+
CC = gcc -Wall
-
CC <span><font color="#990000">+=</font></span> -g
+
# we want to add something to the end of the variable
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
CC += -g
-
        <span><font color="#009900">$(CC)</font></span> -c hello<span><font color="#990000">.</font></span>c -o hello<span><font color="#990000">.</font></span>o
+
hello.o: hello.c hello_api.h
-
</tt>
+
        $(CC) -c hello.c -o hello.o
 +
</source>
The prepending operation can also be used with simple variables. Make will not change the type of variable on the left side of the += operator.
The prepending operation can also be used with simple variables. Make will not change the type of variable on the left side of the += operator.
-
== Automatic Variables ==
+
===== Automatic Variables =====
There is a pre-defined set of variables inside make that can be used to avoid repetitive typing, when writing out the commands in a rule.
There is a pre-defined set of variables inside make that can be used to avoid repetitive typing, when writing out the commands in a rule.
Line 478: Line 485:
* <code>$?</code> : list of prerequisites that are newer than the target is (if target does not exist, they are all considered newer).
* <code>$?</code> : list of prerequisites that are newer than the target is (if target does not exist, they are all considered newer).
-
By rewriting the makefile using automatic variables, the result is: simple-make-files/Makefile.9
+
By rewriting the makefile using automatic variables, the result is: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.9 simple-make-files/Makefile.9]
-
<tt><span>''<span><font color="#9A1900"><nowiki># add the warning flag to CFLAGS-variable</nowiki></font></span>''</span>
+
<source lang="make">
-
CFLAGS <span><font color="#990000">+=</font></span> -Wall
+
# add the warning flag to CFLAGS-variable
-
targets <span><font color="#990000"><nowiki>=</nowiki></font></span> hello
+
CFLAGS += -Wall
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> all
+
targets = hello
-
all<span><font color="#990000"><nowiki>:</nowiki></font></span> <span><font color="#009900">$(targets)</font></span>
+
.PHONY: all
-
hello<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>o hello_func<span><font color="#990000">.</font></span>o
+
all: $(targets)
-
        <span><font color="#009900">$(CC)</font></span> <span><font color="#009900">$^</font></span> -o <span><font color="#009900">$@</font></span>
+
hello: hello.o hello_func.o
-
hello<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        $(CC) $^ -o $@
-
        <span><font color="#009900">$(CC)</font></span> <span><font color="#009900">$(CFLAGS)</font></span> -c <span><font color="#009900">$&lt;</font></span> -o <span><font color="#009900">$@</font></span>
+
hello.o: hello.c hello_api.h
-
hello_func<span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hello_func<span><font color="#990000">.</font></span>c hello_api<span><font color="#990000">.</font></span>h
+
        $(CC) $(CFLAGS) -c $< -o $@
-
        <span><font color="#009900">$(CC)</font></span> <span><font color="#009900">$(CFLAGS)</font></span> -c <span><font color="#009900">$&lt;</font></span> -o <span><font color="#009900">$@</font></span>
+
hello_func.o: hello_func.c hello_api.h
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> clean
+
        $(CC) $(CFLAGS) -c $< -o $@
-
clean<span><font color="#990000"><nowiki>:</nowiki></font></span>
+
.PHONY: clean
-
        <span><font color="#009900">$(RM)</font></span> <span><font color="#009900">$(targets)</font></span> <span><font color="#990000"><nowiki>*.</nowiki></font></span>o
+
clean:
-
</tt>
+
        $(RM) $(targets) *.o
 +
</source>
-
Notice the cases when <code>$^</code> is used instead of <code>$&lt;</code> in the above snippet. It is not desired to pass the header files for compilation to the compiler, since the source file already includes the header files. For this reason, <code>$&lt;</code> is used. On the other hand, when linking programs and there are multiple files to put into the executable, <code>$^</code> would normally be used.
+
Notice the cases when <code>$^</code> is used instead of <code>$&lt;</code> in the above snippet. It is not desired to pass the header files for compilation to the compiler, because the source file already includes the header files. For this reason, <code>$&lt;</code> is used. On the other hand, when linking programs and there are multiple files to put into the executable, <code>$^</code> would normally be used.
This relies on a couple of things:
This relies on a couple of things:
-
* $(RM) and $(CC) will be replaced with paths to the system compiler and removal commands. * $(CFLAGS) is a variable that contains a list of options to pass whenever make will invoke the C compiler.
+
* <code>$(RM)</code> and <code>$(CC)</code> will be replaced with paths to the system compiler and removal commands.
 +
* <code>$(CFLAGS)</code> is a variable that contains a list of options to pass whenever make invokes the C compiler.
-
It can also be noticed that all these variable names are in uppercase. This signifies that they have been communicated from the system environment to make. In fact, if creating an environment variable called CFLAGS, make will create it internally for any makefile that it will process. This is the mechanism to communicate variables into makefiles from outside.
+
It can also be noticed that all these variable names are in uppercase. This signifies that they have been communicated from the system environment to make. In fact, if creating an environment variable called <code>CFLAGS</code>, make will create it internally for any makefile that it will process. This is the mechanism to communicate variables into makefiles from outside.
Writing variables in uppercase is a convention signaling external variables, or environmental variables, so this is the reason why lowercase should be used in own private variables within a Makefile.
Writing variables in uppercase is a convention signaling external variables, or environmental variables, so this is the reason why lowercase should be used in own private variables within a Makefile.
-
== Integrating with Pkg-Config ==
+
=== Integrating with Pkg-Config ===
-
The above has provided the knowledge to write a simple Makefile for the Hello World example. In order to get the the result of pkg-config, the GNU make $(shell command params) function will be used here. Its function is similar to the backtick operation of the shell. simple-make-files/Makefile.10
+
The above has provided the knowledge to write a simple Makefile for the Hello World example. To get the the result of [http://pkg-config.freedesktop.org/wiki/ pkg-config], the GNU make <code>$(shell command params)</code> function will be used here. Its function is similar to the backtick operation of the shell. [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.10 simple-make-files/Makefile.10]
-
<tt><span>''<span><font color="#9A1900"><nowiki># define a list of pkg-config packages we want to use</nowiki></font></span>''</span>
+
<source lang="make">
-
pkg_packages <span><font color="#990000"><nowiki>:=</nowiki></font></span> gtk<span><font color="#990000">+</font></span>-<span><font color="#993399">2.0</font></span> hildon-<span><font color="#993399">1</font></span>
+
# define a list of pkg-config packages we want to use
-
<span>''<span><font color="#9A1900"><nowiki># get the necessary flags for compiling</nowiki></font></span>''</span>
+
pkg_packages := gtk+-2.0 hildon-1
-
PKG_CFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(</font></span>shell pkg-config -cflags <span><font color="#009900">$(pkg_packages))</font></span>
+
# get the necessary flags for compiling
-
<span>''<span><font color="#9A1900"><nowiki># get the necessary flags for linking</nowiki></font></span>''</span>
+
PKG_CFLAGS := $(shell pkg-config --cflags $(pkg_packages))
-
PKG_LDFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(</font></span>shell pkg-config -libs <span><font color="#009900">$(pkg_packages))</font></span>
+
# get the necessary flags for linking
-
<span>''<span><font color="#9A1900"><nowiki># additional flags</nowiki></font></span>''</span>
+
PKG_LDFLAGS := $(shell pkg-config --libs $(pkg_packages))
-
<span>''<span><font color="#9A1900"><nowiki># -Wall: warnings</nowiki></font></span>''</span>
+
# additional flags
-
<span>''<span><font color="#9A1900"><nowiki># -g: debugging</nowiki></font></span>''</span>
+
# -Wall: warnings
-
ADD_CFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> -Wall -g
+
# -g: debugging
-
<span>''<span><font color="#9A1900"><nowiki># combine the flags (so that CFLAGS/LDFLAGS from the command line</nowiki></font></span>''</span>
+
ADD_CFLAGS := -Wall -g
-
<span>''<span><font color="#9A1900"><nowiki># still work).</nowiki></font></span>''</span>
+
# combine the flags (so that CFLAGS/LDFLAGS from the command line
-
CFLAGS  <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(PKG_CFLAGS)</font></span> <span><font color="#009900">$(ADD_CFLAGS)</font></span> <span><font color="#009900">$(CFLAGS)</font></span>
+
# still work).
-
LDFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(PKG_LDFLAGS)</font></span> <span><font color="#009900">$(LDFLAGS)</font></span>
+
CFLAGS  := $(PKG_CFLAGS) $(ADD_CFLAGS) $(CFLAGS)
-
targets <span><font color="#990000"><nowiki>=</nowiki></font></span> hildon_helloworld-<span><font color="#993399">1</font></span>
+
LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> all
+
targets = hildon_helloworld-1
-
all<span><font color="#990000"><nowiki>:</nowiki></font></span> <span><font color="#009900">$(targets)</font></span>
+
.PHONY: all
-
hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000"><nowiki>:</nowiki></font></span> hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000">.</font></span>o
+
all: $(targets)
-
        <span><font color="#009900">$(CC)</font></span> <span><font color="#009900">$^</font></span> -o <span><font color="#009900">$@</font></span> <span><font color="#009900">$(LDFLAGS)</font></span>
+
hildon_helloworld-1: hildon_helloworld-1.o
-
hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000">.</font></span>c
+
        $(CC) $^ -o $@ $(LDFLAGS)
-
        <span><font color="#009900">$(CC)</font></span> <span><font color="#009900">$(CFLAGS)</font></span> -c <span><font color="#009900">$&lt;</font></span> -o <span><font color="#009900">$@</font></span>
+
hildon_helloworld-1.o: hildon_helloworld-1.c
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> clean
+
        $(CC) $(CFLAGS) -c $< -o $@
-
clean<span><font color="#990000"><nowiki>:</nowiki></font></span>
+
.PHONY: clean
-
        <span><font color="#009900">$(RM)</font></span> <span><font color="#009900">$(targets)</font></span> <span><font color="#990000"><nowiki>*.</nowiki></font></span>o
+
clean:
-
</tt>
+
        $(RM) $(targets) *.o
 +
</source>
-
One might wonder, where the CC and RM variables come from. They certainly were not declared anywhere in the Makefile. GNU make comes with a list of pre-defined variables for many programs and their arguments. GNU make also contains a preset list of pattern rules (which will not be dealt here), but basically these are pre-defined rules that are used when (for example) one needs an .o file from an .c file. The rules that were manually specified above are actually the same rules that GNU make already contains, so the Makefile can be made even more compact by only specifying the dependencies between files.
+
You might wonder, where the <code>CC</code> and <code>RM</code> variables come from. They certainly were not declared anywhere in the Makefile. GNU make comes with a list of pre-defined variables for many programs and their arguments. GNU make also contains a preset list of pattern rules (which will not be dealt here), but basically these are pre-defined rules that are used when (for example) one needs an .o file from an .c file. The rules that were manually specified above are actually the same rules that GNU make already contains, so the Makefile can be made even more compact by only specifying the dependencies between files.
-
This leads to the following, slightly simpler version: simple-make-files/Makefile.11
+
This leads to the following, slightly simpler version: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/simple-make-files/Makefile.11 simple-make-files/Makefile.11]
-
<tt><span>''<span><font color="#9A1900"><nowiki># define a list of pkg-config packages we want to use</nowiki></font></span>''</span>
+
<source lang="make">
-
pkg_packages <span><font color="#990000"><nowiki>:=</nowiki></font></span> gtk<span><font color="#990000">+</font></span>-<span><font color="#993399">2.0</font></span> hildon-<span><font color="#993399">1</font></span>
+
# define a list of pkg-config packages we want to use
-
PKG_CFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(</font></span>shell pkg-config -cflags <span><font color="#009900">$(pkg_packages))</font></span>
+
pkg_packages := gtk+-2.0 hildon-1
-
PKG_LDFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(</font></span>shell pkg-config -libs <span><font color="#009900">$(pkg_packages))</font></span>
+
PKG_CFLAGS := $(shell pkg-config -cflags $(pkg_packages))
-
ADD_CFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> -Wall -g
+
PKG_LDFLAGS := $(shell pkg-config -libs $(pkg_packages))
-
<span>''<span><font color="#9A1900"><nowiki># combine the flags</nowiki></font></span>''</span>
+
ADD_CFLAGS := -Wall -g
-
CFLAGS  <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(PKG_CFLAGS)</font></span> <span><font color="#009900">$(ADD_CFLAGS)</font></span> <span><font color="#009900">$(CFLAGS)</font></span>
+
# combine the flags
-
LDFLAGS <span><font color="#990000"><nowiki>:=</nowiki></font></span> <span><font color="#009900">$(PKG_LDFLAGS)</font></span> <span><font color="#009900">$(LDFLAGS)</font></span>
+
CFLAGS  := $(PKG_CFLAGS) $(ADD_CFLAGS) $(CFLAGS)
-
targets <span><font color="#990000"><nowiki>=</nowiki></font></span> hildon_helloworld-<span><font color="#993399">1</font></span>
+
LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> all
+
targets = hildon_helloworld-1
-
all<span><font color="#990000"><nowiki>:</nowiki></font></span> <span><font color="#009900">$(targets)</font></span>
+
.PHONY: all
-
<span>''<span><font color="#9A1900"><nowiki># we can omit the rules and just specify the dependencies</nowiki></font></span>''</span>
+
all: $(targets)
-
<span>''<span><font color="#9A1900"><nowiki># for our simple project this doesn't seem like a big win</nowiki></font></span>''</span>
+
# we can omit the rules and just specify the dependencies
-
<span>''<span><font color="#9A1900"><nowiki># but for larger projects where you have multiple object</nowiki></font></span>''</span>
+
# for our simple project this doesn't seem like a big win
-
<span>''<span><font color="#9A1900"><nowiki># files, this will save considerable time.</nowiki></font></span>''</span>
+
# but for larger projects where you have multiple object
-
hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000"><nowiki>:</nowiki></font></span> hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000">.</font></span>o
+
# files, this will save considerable time.
-
hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000">.</font></span>o<span><font color="#990000"><nowiki>:</nowiki></font></span> hildon_helloworld-<span><font color="#993399">1</font></span><span><font color="#990000">.</font></span>c
+
hildon_helloworld-1: hildon_helloworld-1.o
-
<span><font color="#990000">.</font></span>PHONY<span><font color="#990000"><nowiki>:</nowiki></font></span> clean
+
hildon_helloworld-1.o: hildon_helloworld-1.c
-
clean<span><font color="#990000"><nowiki>:</nowiki></font></span>
+
.PHONY: clean
-
        <span><font color="#009900">$(RM)</font></span> <span><font color="#009900">$(targets)</font></span> <span><font color="#990000"><nowiki>*.</nowiki></font></span>o
+
clean:
-
</tt>
+
        $(RM) $(targets) *.o
 +
</source>
-
= GNU Autotools =
+
== GNU Autotools ==
Creating portable software written in the C language has historically been challenging. The portability issues are not restricted just to the differences between binary architectures, but also encompass differences in system libraries and different implementations of UNIX APIs in different systems. This section introduces GNU autotools as one solution for managing this complexity. There are also other tools available, but the most likely to be encountered are autotoolized projects and also Debian packaging supports autotools.
Creating portable software written in the C language has historically been challenging. The portability issues are not restricted just to the differences between binary architectures, but also encompass differences in system libraries and different implementations of UNIX APIs in different systems. This section introduces GNU autotools as one solution for managing this complexity. There are also other tools available, but the most likely to be encountered are autotoolized projects and also Debian packaging supports autotools.
-
== Brief History of Managing Portability ==
+
=== Brief History of Managing Portability ===
When discussing portability challenges with C code, various issues crop up:
When discussing portability challenges with C code, various issues crop up:
Line 587: Line 598:
Besides autoconf, it became evident that a more general Makefile generation tool can be useful as part of the whole process. This is how GNU automake was born. GNU automake can also be used outside autoconf. A simple autoconf configuration file is presented next.
Besides autoconf, it became evident that a more general Makefile generation tool can be useful as part of the whole process. This is how GNU automake was born. GNU automake can also be used outside autoconf. A simple autoconf configuration file is presented next.
-
== GNU Autoconf ==
+
=== GNU Autoconf ===
-
Autoconf is a tool that uses the GNU m4 macro preprocessor to process the configuration file and output a shell script based on the macros used in the file. Anything that m4 does not recognize as a macro is passed verbatim to the output script. This means that almost any wanted shell script fragments can be included into the '''configure.ac''' (the modern name for the default configuration file for autoconf).
+
Autoconf is a tool that uses the GNU m4 macro preprocessor to process the configuration file and output a shell script based on the macros used in the file. Anything that m4 does not recognize as a macro is passed verbatim to the output script. This means that almost any wanted shell script fragments can be included into the <code>configure.ac</code> file (the modern name for the default configuration file for autoconf).
-
The first subject here is a simple example to see how the basic configuration file works. Then some limitations of m4 syntax are covered, and hints on how to avoid problems with the syntax are given. autoconf-automake/example1/configure.ac
+
The first subject here is a simple example to see how the basic configuration file works. Then some limitations of m4 syntax are covered, and hints on how to avoid problems with the syntax are given. [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example1/configure.ac autoconf-automake/example1/configure.ac]
-
<tt><span>''<span><font color="#9A1900"><nowiki># Specify the "application name" and application version</nowiki></font></span>''</span>
+
<source lang="autoconf">
-
AC_INIT<span><font color="#990000">(</font></span>hello<span><font color="#990000">,</font></span> version-<span><font color="#993399">0.1</font></span><span><font color="#990000">)</font></span>
+
# Specify the "application name" and application version
-
+
AC_INIT(hello, version-0.1)
-
<span>''<span><font color="#9A1900"><nowiki># Because autoconf passes trough anything that it does not recognize</nowiki></font></span>''</span>
+
 
-
<span>''<span><font color="#9A1900"><nowiki># into the final script ('configure'), we can use any valid shell</nowiki></font></span>''</span>
+
# Because autoconf passes trough anything that it does not recognize
-
<span>''<span><font color="#9A1900"><nowiki># statements here. Note that you should restrict your shell to</nowiki></font></span>''</span>
+
# into the final script ('configure'), we can use any valid shell
-
<span>''<span><font color="#9A1900"><nowiki># standard features that are available in all UNIX shells, but in our</nowiki></font></span>''</span>
+
# statements here. Note that you should restrict your shell to
-
<span>''<span><font color="#9A1900"><nowiki># case, we are content with the most used shell on Linux systems</nowiki></font></span>''</span>
+
# standard features that are available in all UNIX shells, but in our
-
<span>''<span><font color="#9A1900"><nowiki># (bash).</nowiki></font></span>''</span>
+
# case, we are content with the most used shell on Linux systems
-
echo -e <span><font color="#FF0000">"</font></span><span><font color="#CC33CC">\n\n</font></span><span><font color="#FF0000">Hello from configure (using echo)!</font></span><span><font color="#CC33CC">\n\n</font></span><span><font color="#FF0000">"</font></span>
+
# (bash).
-
+
echo -e "\n\nHello from configure (using echo)!\n\n"
-
<span>''<span><font color="#9A1900"><nowiki># We can use a macro for this messages. This is much preferred as it</nowiki></font></span>''</span>
+
 
-
<span>''<span><font color="#9A1900"><nowiki># is more portable.</nowiki></font></span>''</span>
+
# We can use a macro for this messages. This is much preferred as it
-
AC_MSG_NOTICE<span><font color="#990000">([</font></span>Hello from configure using msg-notice<span><font color="#990000"><nowiki>!])</nowiki></font></span>
+
# is more portable.
-
+
AC_MSG_NOTICE([Hello from configure using msg-notice!])
-
<span>''<span><font color="#9A1900"><nowiki># Check that the C Compiler works.</nowiki></font></span>''</span>
+
 
-
AC_PROG_CC
+
# Check that the C Compiler works.
-
<span>''<span><font color="#9A1900"><nowiki># Check what is the AWK-program on our system (and that one exists).</nowiki></font></span>''</span>
+
AC_PROG_CC
-
AC_PROG_AWK
+
# Check what is the AWK-program on our system (and that one exists).
-
<span>''<span><font color="#9A1900"><nowiki># Check whether the 'cos' function can be found in library 'm'</nowiki></font></span>''</span>
+
AC_PROG_AWK
-
<span>''<span><font color="#9A1900"><nowiki># (standard C math library).</nowiki></font></span>''</span>
+
# Check whether the 'cos' function can be found in library 'm'
-
AC_CHECK_LIB<span><font color="#990000">(</font></span>m<span><font color="#990000">,</font></span> cos<span><font color="#990000">)</font></span>
+
# (standard C math library).
-
<span>''<span><font color="#9A1900"><nowiki># Check for presence of system header 'unistd.h'.</nowiki></font></span>''</span>
+
AC_CHECK_LIB(m, cos)
-
<span>''<span><font color="#9A1900"><nowiki># This also tests a lot of other system include files (it is</nowiki></font></span>''</span>
+
# Check for presence of system header 'unistd.h'.
-
<span>''<span><font color="#9A1900"><nowiki># semi-intelligent in determining which ones are required).</nowiki></font></span>''</span>
+
# This also tests a lot of other system include files (it is
-
AC_CHECK_HEADER<span><font color="#990000">(</font></span>unistd<span><font color="#990000">.</font></span>h<span><font color="#990000">)</font></span>
+
# semi-intelligent in determining which ones are required).
-
<span>''<span><font color="#9A1900"><nowiki># You can also check for multiple system headers at the same time,</nowiki></font></span>''</span>
+
AC_CHECK_HEADER(unistd.h)
-
<span>''<span><font color="#9A1900"><nowiki># but notice the different name of the test macro for this (plural).</nowiki></font></span>''</span>
+
# You can also check for multiple system headers at the same time,
-
AC_CHECK_HEADERS<span><font color="#990000">([</font></span>math<span><font color="#990000">.</font></span>h stdio<span><font color="#990000">.</font></span>h<span><font color="#990000">])</font></span>
+
# but notice the different name of the test macro for this (plural).
-
<span>''<span><font color="#9A1900"><nowiki># A way to implement conditional logic based on header file presence</nowiki></font></span>''</span>
+
AC_CHECK_HEADERS([math.h stdio.h])
-
<span>''<span><font color="#9A1900"><nowiki># (we do not have a b0rk.h in our system).</nowiki></font></span>''</span>
+
# A way to implement conditional logic based on header file presence
-
AC_CHECK_HEADER<span><font color="#990000">(</font></span>b0rk<span><font color="#990000">.</font></span>h<span><font color="#990000">,</font></span> <span><font color="#990000">[</font></span>echo <span><font color="#FF0000">"b0rk.h present in system"</font></span><span><font color="#990000">],</font></span> <span><font color="#990000">\</font></span>
+
# (we do not have a b0rk.h in our system).
-
                        <span><font color="#990000">[</font></span>echo <span><font color="#FF0000">"b0rk.h not present in system"</font></span><span><font color="#990000">])</font></span>
+
AC_CHECK_HEADER(b0rk.h, [echo "b0rk.h present in system"], \
-
+
                        [echo "b0rk.h not present in system"])
-
echo <span><font color="#FF0000">"But that does not stop us from continuing!"</font></span>
+
 
-
+
echo "But that does not stop us from continuing!"
-
echo <span><font color="#FF0000">"Directory to install binaries in is '$bindir'"</font></span>
+
 
-
echo <span><font color="#FF0000">"Directory under which data files go is '$datadir'"</font></span>
+
echo "Directory to install binaries in is '$bindir'"
-
echo <span><font color="#FF0000">"For more variables, check 'config.log' after running configure"</font></span>
+
echo "Directory under which data files go is '$datadir'"
-
echo <span><font color="#FF0000">"CFLAGS is '$CFLAGS'"</font></span>
+
echo "For more variables, check 'config.log' after running configure"
-
echo <span><font color="#FF0000">"LDFLAGS is '$LDFLAGS'"</font></span>
+
echo "CFLAGS is '$CFLAGS'"
-
echo <span><font color="#FF0000">"LIBS is '$LIBS'"</font></span>
+
echo "LDFLAGS is '$LDFLAGS'"
-
echo <span><font color="#FF0000">"CC is '$CC'"</font></span>
+
echo "LIBS is '$LIBS'"
-
echo <span><font color="#FF0000">"AWK is '$AWK'"</font></span>
+
echo "CC is '$CC'"
-
</tt>
+
echo "AWK is '$AWK'"
 +
</source>
The listing is verbosely commented, so it should be pretty self-evident what the different macros do. The macros that test for a feature or an include file normally causes the generated configure script to generate small C code test programs that are run as part of the configuration process. If these programs run successfully, the relevant test succeeds and the configuration process continues to the next test.
The listing is verbosely commented, so it should be pretty self-evident what the different macros do. The macros that test for a feature or an include file normally causes the generated configure script to generate small C code test programs that are run as part of the configuration process. If these programs run successfully, the relevant test succeeds and the configuration process continues to the next test.
Line 643: Line 655:
The following convention holds true in respect to the names of macros that are commonly used and available:
The following convention holds true in respect to the names of macros that are commonly used and available:
-
* '''AC_*'''<nowiki>: A macro that is included in autoconf or is meant for it. </nowiki>
+
* <code>AC_*</code>: A macro that is included in autoconf or is meant for it.
-
* '''AM_*'''<nowiki>: A macro that is meant for automake. </nowiki>
+
* <code>AM_*</code>: A macro that is meant for automake.
* Others: The autoconf system can be expanded by writing custom macros which can be stored in a custom directory. Some development packages also install new macros to be used.
* Others: The autoconf system can be expanded by writing custom macros which can be stored in a custom directory. Some development packages also install new macros to be used.
-
The next step is to run ''autoconf''. Without any parameters, it reads '''configure.ac''' by default. If configure.ac does not exist, it tries to read '''configure.in''' instead.  
+
The next step is to run <code>autoconf</code>. Without any parameters, it reads <code>configure.ac</code> by default. If <code>configure.ac</code> does not exist, it tries to read <code>configure.in</code> instead.  
-
Note that using the name configure.in is considered obsolete.
+
Note that using the name <code>configure.in</code> is considered obsolete.
  <nowiki>
  <nowiki>
Line 707: Line 719:
  </nowiki>
  </nowiki>
-
Autoconf does not output information about its progress. Normally, only errors are output on stdout. Instead, it creates a new script called '''configure''' in the same directory, and sets it as executable.
+
Autoconf does not output information about its progress. Normally, only errors are output on stdout. Instead, it creates a new script called <code>configure</code> in the same directory, and sets it as executable.
The configure script is the result of all of the macro processing. If taking a look at the generated file with an editor or by using less, it can be seen that it contains a lot of shell code.
The configure script is the result of all of the macro processing. If taking a look at the generated file with an editor or by using less, it can be seen that it contains a lot of shell code.
Line 733: Line 745:
If bad shell syntax is introduced into the configuration file, the bad syntax causes errors only when the generated script file is run (not when autoconf generates the script). In general, autoconf almost always succeeds but the generated script does not necessarily succeed. Knowing which error in the shell script corresponds to which line in the original configure.ac is not always easy but can be learned through experience.
If bad shell syntax is introduced into the configuration file, the bad syntax causes errors only when the generated script file is run (not when autoconf generates the script). In general, autoconf almost always succeeds but the generated script does not necessarily succeed. Knowing which error in the shell script corresponds to which line in the original configure.ac is not always easy but can be learned through experience.
-
There is a line that reports the result of testing for '''unistd.h'''. It appears twice: the first time because it is the default test to run whenever testing for headers, and the second time because it was explicitly tested for. The second test output contains text (cached), which means that the test has been already run, and the result has been saved into a cache (the mysterious '''autom4te.cache''' directory). This means that for large projects, which cannot necessarily perform the same tests over and over, the tests are only run once, which makes running the script faster.
+
There is a line that reports the result of testing for <code>unistd.h</code>. It appears twice: the first time because it is the default test to run whenever testing for headers, and the second time because it was explicitly tested for. The second test output contains text (cached), which means that the test has been already run, and the result has been saved into a cache (the mysterious <code>autom4te.cache</code> directory). This means that for large projects, which cannot necessarily perform the same tests over and over, the tests are only run once, which makes running the script faster.
The last line's output above contains the values of variables. When the configure script runs, it automatically creates shell variables that can be used in shell code fragments. The macros for checking what programs are available for compiling must illustrate that point. Here awk was used as an example.
The last line's output above contains the values of variables. When the configure script runs, it automatically creates shell variables that can be used in shell code fragments. The macros for checking what programs are available for compiling must illustrate that point. Here awk was used as an example.
Line 751: Line 763:
  AWK is 'gawk'
  AWK is 'gawk'
  </nowiki>
  </nowiki>
-
 
It can seem that giving the prefix does not change anything, but this is because the shell does not expand the value in this particular case. However, if the variable was used in the script for doing something, the shell would expand later on. In order to see some effect, try passing the datadir-option (because that is printed out explicitly).
It can seem that giving the prefix does not change anything, but this is because the shell does not expand the value in this particular case. However, if the variable was used in the script for doing something, the shell would expand later on. In order to see some effect, try passing the datadir-option (because that is printed out explicitly).
-
If you need to see which variables are available for configuration, read the generated '''config.log''' file. The variables are listed at the end of that file.
+
If you need to see which variables are available for configuration, read the generated <code>config.log</code> file. The variables are listed at the end of that file.
-
== Substitutions ==
+
=== Substitutions ===
Besides creating the configure script, autoconf can do other useful things as well. Some people say that autoconf is at least as powerful as emacs, if not more so. Unfortunately, with all this power comes also lot of complexity. Sometimes finding out why things do not quite work can be rather difficult.
Besides creating the configure script, autoconf can do other useful things as well. Some people say that autoconf is at least as powerful as emacs, if not more so. Unfortunately, with all this power comes also lot of complexity. Sometimes finding out why things do not quite work can be rather difficult.
-
It can be useful to use the variables inside text files that are not directly related to the '''configure.ac'''. These might be configuration files or files that are used in some part of the building process later on. For this, autoconf provides a mechanism called ''substitution''. A special macro reads in an external file, replaces all instances of variable names in it, and then stores the resulting file as a new file. The convention in naming the input files is to add a suffix .in to the names. The name of generated output file are the same but without the suffix.  
+
It can be useful to use the variables inside text files that are not directly related to the <code>configure.ac</code>'''. These might be configuration files or files that are used in some part of the building process later on. For this, autoconf provides a mechanism called ''substitution''. A special macro reads in an external file, replaces all instances of variable names in it, and then stores the resulting file as a new file. The convention in naming the input files is to add a suffix .in to the names. The name of generated output file are the same but without the suffix.  
Note that the substitution is done when the generated configure script is run, not when autoconf is run.
Note that the substitution is done when the generated configure script is run, not when autoconf is run.
Line 767: Line 778:
The generated configure script replaces all occurrences of the variable name surrounded with 'at' (@) characters with the variable value when it reads through each of the input files.
The generated configure script replaces all occurrences of the variable name surrounded with 'at' (@) characters with the variable value when it reads through each of the input files.
-
This is best illustrated with a small example. The input file contents are listed after the autoconf configuration file. In this example, the substitution is only made for one file, but it is also possible to process multiple files using the substitution mechanism. autoconf-automake/example2/configure.ac
+
This is best illustrated with a small example. The input file contents are listed after the autoconf configuration file. In this example, the substitution is only made for one file, but it is also possible to process multiple files using the substitution mechanism. [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example2/configure.ac autoconf-automake/example2/configure.ac]
-
<tt><span>''<span><font color="#9A1900"><nowiki># An example showing how to use a variable-based substitution.</nowiki></font></span>''</span>
+
<source lang="autoconf">
-
+
# An example showing how to use a variable-based substitution.
-
AC_INIT<span><font color="#990000">(</font></span>hello<span><font color="#990000">,</font></span> version-<span><font color="#993399">0.1</font></span><span><font color="#990000">)</font></span>
+
 
-
+
AC_INIT(hello, version-0.1)
-
AC_PROG_CC
+
 
-
AC_PROG_AWK
+
AC_PROG_CC
-
AC_CHECK_HEADER<span><font color="#990000">(</font></span>unistd<span><font color="#990000">.</font></span>h<span><font color="#990000">)</font></span>
+
AC_PROG_AWK
-
AC_CHECK_HEADERS<span><font color="#990000">([</font></span>math<span><font color="#990000">.</font></span>h stdio<span><font color="#990000">.</font></span>h<span><font color="#990000">])</font></span>
+
AC_CHECK_HEADER(unistd.h)
-
AC_CHECK_HEADER<span><font color="#990000">(</font></span>b0rk<span><font color="#990000">.</font></span>h<span><font color="#990000">,</font></span> <span><font color="#990000">[</font></span>echo <span><font color="#FF0000">"b0rk.h present in system"</font></span><span><font color="#990000">],</font></span> <span><font color="#990000">\</font></span>
+
AC_CHECK_HEADERS([math.h stdio.h])
-
                        <span><font color="#990000">[</font></span>echo <span><font color="#FF0000">"b0rk.h not present in system"</font></span><span><font color="#990000">])</font></span>
+
AC_CHECK_HEADER(b0rk.h, [echo "b0rk.h present in system"], \
-
+
                        [echo "b0rk.h not present in system"])
-
echo <span><font color="#FF0000">"But that doesn't stop us from continuing!"</font></span>
+
 
-
+
echo "But that doesn't stop us from continuing!"
-
<span>''<span><font color="#9A1900"><nowiki># Run the test-output.txt(.in) through autoconf substitution logic.</nowiki></font></span>''</span>
+
-
AC_OUTPUT<span><font color="#990000">(</font></span>test-output<span><font color="#990000">.</font></span>txt<span><font color="#990000">)</font></span>
+
-
</tt>
+
-
autoconf-automake/example2/test-output.txt.in
+
# Run the test-output.txt(.in) through autoconf substitution logic.
 +
AC_OUTPUT(test-output.txt)
 +
</source>
-
<code>This file will go through autoconf variable substitution.
+
[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example2/test-output.txt.in autoconf-automake/example2/test-output.txt.in]
-
The output file will be named as 'test-output.txt' (the '.in'-suffix
+
 
-
is stripped).
+
<pre>
-
All the names surrounded by '@'-characters will be replaced by the values
+
This file will go through autoconf variable substitution.
-
of the variables (if present) by the configure script, when it is run
+
The output file will be named as 'test-output.txt' (the '.in'-suffix
-
by the end user.
+
is stripped).
-
Prefix: @prefix@
+
All the names surrounded by '@'-characters will be replaced by the values
-
C compiler: @CC@
+
of the variables (if present) by the configure script, when it is run
-
This is a name for which there is no variable.
+
by the end user.
-
Stuff: @stuff@</code>
+
Prefix: @prefix@
 +
C compiler: @CC@
 +
This is a name for which there is no variable.
 +
Stuff: @stuff@
 +
</pre>
We then run autoconf and configure:
We then run autoconf and configure:
-
[sbox-FREMANTLE_X86: ~/example2] &gt; autoconf
+
<pre>
-
[sbox-FREMANTLE_X86: ~/example2] &gt; ./configure
+
[sbox-FREMANTLE_X86: ~/example2] > autoconf
-
checking for gcc... gcc
+
[sbox-FREMANTLE_X86: ~/example2] > ./configure
-
checking for C compiler default output file name... a.out
+
checking for gcc... gcc
-
checking whether the C compiler works... yes
+
checking for C compiler default output file name... a.out
-
checking whether we are cross compiling... no
+
checking whether the C compiler works... yes
-
checking for suffix of executables...
+
checking whether we are cross compiling... no
-
checking for suffix of object files... o
+
checking for suffix of executables...
-
checking whether we are using the GNU C compiler... yes
+
checking for suffix of object files... o
-
checking whether gcc accepts -g... yes
+
checking whether we are using the GNU C compiler... yes
-
checking for gcc option to accept ANSI C... none needed
+
checking whether gcc accepts -g... yes
-
checking for gawk... gawk
+
checking for gcc option to accept ANSI C... none needed
-
checking how to run the C preprocessor... gcc -E
+
checking for gawk... gawk
-
checking for egrep... grep -E
+
checking how to run the C preprocessor... gcc -E
-
checking for ANSI C header files... yes
+
checking for egrep... grep -E
-
checking for sys/types.h... yes
+
checking for ANSI C header files... yes
-
checking for sys/stat.h... yes
+
checking for sys/types.h... yes
-
checking for stdlib.h... yes
+
checking for sys/stat.h... yes
-
checking for string.h... yes
+
checking for stdlib.h... yes  
-
checking for memory.h... yes
+
checking for string.h... yes
-
checking for strings.h... yes
+
checking for memory.h... yes
-
checking for inttypes.h... yes
+
checking for strings.h... yes
-
checking for stdint.h... yes
+
checking for inttypes.h... yes
-
checking for unistd.h... yes
+
checking for stdint.h... yes
-
checking for unistd.h... (cached) yes
+
checking for unistd.h... yes
-
checking math.h usability... yes
+
checking for unistd.h... (cached) yes
-
checking math.h presence... yes
+
checking math.h usability... yes
-
checking for math.h... yes
+
checking math.h presence... yes
-
checking stdio.h usability... yes
+
checking for math.h... yes
-
checking stdio.h presence... yes
+
checking stdio.h usability... yes
-
checking for stdio.h... yes
+
checking stdio.h presence... yes
-
checking b0rk.h usability... no
+
checking for stdio.h... yes
-
checking b0rk.h presence... no
+
checking b0rk.h usability... no
-
checking for b0rk.h... no
+
checking b0rk.h presence... no
-
b0rk.h not present in system
+
checking for b0rk.h... no
-
But that doesn't stop us from continuing!
+
b0rk.h not present in system
-
configure: creating ./config.status
+
But that doesn't stop us from continuing!
-
config.status: creating test-output.txt
+
configure: creating ./config.status
-
[sbox-FREMANTLE_X86: ~/example2] &gt; cat test-output.txt
+
config.status: creating test-output.txt
-
This file will go through autoconf variable substitution.
+
[sbox-FREMANTLE_X86: ~/example2] > cat test-output.txt
-
+
This file will go through autoconf variable substitution.
-
The output file will be named as 'test-output.txt' (the '.in'-suffix
+
-
is stripped).
+
-
+
-
All names surrounded by '@'-characters will be replaced by the values
+
-
of the variables (if present) by the configure script when it is run
+
-
by end user.
+
-
+
-
Prefix: /usr/local
+
-
C compiler: gcc
+
-
+
-
This is a name for which there is no variable.
+
-
Stuff: @stuff@
+
 +
The output file will be named as 'test-output.txt' (the '.in'-suffix
 +
is stripped).
-
This feature is used later on. When you run your own version of the file, notice the creation of file called '''config.status'''. It is the file that actually does the substitution for external files, so if the configuration is otherwise complex, and you only want to re-run the substitution of the output files, you can run the config.status script.
+
All names surrounded by '@'-characters will be replaced by the values
 +
of the variables (if present) by the configure script when it is run
 +
by end user.
-
== Introducing Automake ==
+
Prefix: /usr/local
 +
C compiler: gcc
 +
 
 +
This is a name for which there is no variable.
 +
Stuff: @stuff@
 +
</pre>
 +
 
 +
This feature is used later on. When you run your own version of the file, notice the creation of file called <code>config.status</code>. It is the file that actually does the substitution for external files, so if the configuration is otherwise complex, and you only want to re-run the substitution of the output files, you can run the config.status script.
 +
 
 +
=== Introducing Automake ===
The next step is to create a small project that consists of yet another hello world. This time, there is a file implementing the application (main), a header file describing the API (printHello()) and the implementation of the function.
The next step is to create a small project that consists of yet another hello world. This time, there is a file implementing the application (main), a header file describing the API (printHello()) and the implementation of the function.
-
As it happens, GNU automake is designed so that it can be easily integrated into autoconf. This is utilized in the next example, so that the Makefile does not have to be written by hand anymore. Instead, the Makefile is generated by the configure script, and it contains the necessary settings for the system on which configure is run.
+
As it happens, GNU automake is designed so that it can be easily integrated with autoconf. Makefiles are generated by a configure script, and it contains the necessary settings for the system on which configure is run.
In order for this to work, two things are necessary:
In order for this to work, two things are necessary:
-
* A configuration file for automake (conventionally Makefile.am).
+
* A configuration file for automake (conventionally <code>Makefile.am</code>) which contains the files to be generated using make
-
* Telling the autoconf that it should create Makefile.in based on Makefile.am by using automake.
+
* A configuration file for autoconf (conventionally <code>configure.ac</code>) which lists the tests which are required to ensure that the system has all the required dependencies
-
The example starts with the autoconf configuration file: autoconf-automake/example3/configure.ac
+
Running automake will generate a file <code>Makefile.in</code> containing a number of standard targets for make, and running autoconf will generate a configure script which will test your system, and generate final Makefiles and other files based on the software it finds present on the system.
-
<tt><span>''<span><font color="#9A1900"><nowiki># Any source file name related to our project is ok here.</nowiki></font></span>''</span>
+
The example starts with the autoconf configuration file: autoconf-[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example3/configure.ac automake/example3/configure.ac]
-
AC_INIT<span><font color="#990000">(</font></span>helloapp<span><font color="#990000">,</font></span> <span><font color="#993399">0.1</font></span><span><font color="#990000">)</font></span>
+
-
<span>''<span><font color="#9A1900"><nowiki># We are using automake, so we init it next. The name of the macro</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># starts with 'AM' which means that it is related to automake ('AC'</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># is related to autoconf).</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># Initing automake means more or less generating the .in file from</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># the .am file although it can also be generated at other steps.</nowiki></font></span>''</span>
+
-
AM_INIT_AUTOMAKE
+
-
<span>''<span><font color="#9A1900"><nowiki># Compiler check.</nowiki></font></span>''</span>
+
-
AC_PROG_CC
+
-
<span>''<span><font color="#9A1900"><nowiki># Check for 'install' program.</nowiki></font></span>''</span>
+
-
AC_PROG_INSTALL
+
-
<span>''<span><font color="#9A1900"><nowiki># Generate the Makefile from Makefile.in (using substitution logic).</nowiki></font></span>''</span>
+
-
AC_OUTPUT<span><font color="#990000">(</font></span>Makefile<span><font color="#990000">)</font></span>
+
-
</tt>
+
-
Then the configuration file is presented for automake: autoconf-automake/example3/Makefile.am
+
<source lang="autoconf">
 +
# Any source file name related to our project is ok here.
 +
AC_INIT(helloapp, 0.1)
 +
# We are using automake, so we init it next. The name of the macro
 +
# starts with 'AM' which means that it is related to automake ('AC'
 +
# is related to autoconf).
 +
# Initing automake means more or less generating the .in file from
 +
# the .am file although it can also be generated at other steps.
 +
AM_INIT_AUTOMAKE
 +
# Compiler check.
 +
AC_PROG_CC
 +
# Check for 'install' program.
 +
AC_PROG_INSTALL
 +
# Generate the Makefile from Makefile.in (using substitution logic).
 +
AC_OUTPUT(Makefile)
 +
</source>
-
<tt><span>''<span><font color="#9A1900"><nowiki># Automake rule primer:</nowiki></font></span>''</span>
+
Then the configuration file is presented for automake: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example3/Makefile.am autoconf-automake/example3/Makefile.am]
-
<span>''<span><font color="#9A1900"><nowiki># 1) Left side_ tells what kind of target this is.</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># 2) _right side tells what kind of dependencies are listed.</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># As an example, below:</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># 1) bin = binaries</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># 2) PROGRAMS lists the programs to generate Makefile.ins for.</nowiki></font></span>''</span>
+
-
bin_PROGRAMS <span><font color="#990000"><nowiki>=</nowiki></font></span> helloapp
+
-
<span>''<span><font color="#9A1900"><nowiki># Listing source dependencies:</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># The left side_ gives the name of the application to which the</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># dependencies are related to.</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># _right side gives again the type of dependencies.</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># Here we then list the source files that are necessary to build the</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># helloapp -binary.</nowiki></font></span>''</span>
+
-
helloapp_SOURCES <span><font color="#990000"><nowiki>=</nowiki></font></span> helloapp<span><font color="#990000">.</font></span>c hello<span><font color="#990000">.</font></span>c hello<span><font color="#990000">.</font></span>h
+
-
<span>''<span><font color="#9A1900"><nowiki># For other files that cannot be automatically deduced by automake,</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># you need to use the EXTRA_DIST rule which should list the files</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># that should be included. Files can also be in other directories or</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># even whole directories can be included this way (not recommended).</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
-
<span>''<span><font color="#9A1900"><nowiki># EXTRA_DIST = some.service.file.service some.desktop.file.desktop</nowiki></font></span>''</span>
+
-
</tt>
+
-
This material tries to introduce just enough of automake for it to be useful for small projects. Because of this, the detailed syntax of Makefile.am is not explained. Based on the above description, automake knows what kind of Makefile.in to create, and autoconf takes it over from there and fills in the missing pieces.
+
<source lang="make">
 +
# Automake rule primer:
 +
# 1) Left side_ tells what kind of target this is.
 +
# 2) _right side tells what kind of dependencies are listed.
 +
#
 +
# As an example, below:
 +
# 1) bin = binaries
 +
# 2) PROGRAMS lists the programs to generate Makefile.ins for.
 +
bin_PROGRAMS = helloapp
 +
# Listing source dependencies:
 +
#
 +
# The left side_ gives the name of the application to which the
 +
# dependencies are related to.
 +
# _right side gives again the type of dependencies.
 +
#
 +
# Here we then list the source files that are necessary to build the
 +
# helloapp -binary.
 +
helloapp_SOURCES = helloapp.c hello.c hello.h
 +
# For other files that cannot be automatically deduced by automake,
 +
# you need to use the EXTRA_DIST rule which should list the files
 +
# that should be included. Files can also be in other directories or
 +
# even whole directories can be included this way (not recommended).
 +
EXTRA_DIST = some.service.file.service some.desktop.file.desktop
 +
</source>
-
The source files for the project are as simple as possible, but notice the implementation of printHello. autoconf-automake/example3/helloapp.c
+
This material tries to introduce just enough of automake for it to be useful for small projects. Because of this, the detailed syntax of <code>Makefile.am</code> is not explained. Based on the above description, automake knows what kind of <code>Makefile.in</code> to create, and autoconf takes it over from there and fills in the missing pieces.
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
The source files for the project are as simple as possible, but notice the implementation of printHello. [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example3/helloapp.c autoconf-automake/example3/helloapp.c]
-
<span>''<span><font color="#9A1900"> * This maemo code example is licensed under a MIT-style license,</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * that can be found in the file called "License" in the same</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * directory as this file.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> */</font></span>''</span>
+
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;stdlib.h&gt;</font></span>
+
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">"hello.h"</font></span>
+
-
<span><font color="#009900">int</font></span> <span>'''<span><font color="#000000">main</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#009900">int</font></span> argc<span><font color="#990000">,</font></span> <span><font color="#009900">char</font></span><span><font color="#990000"><nowiki>**</nowiki></font></span> argv<span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
+
-
  <span>'''<span><font color="#000000">printHello</font></span>'''</span><span><font color="#990000">();</font></span>
+
-
  <span>'''<span><font color="#0000FF">return</font></span>'''</span> EXIT_SUCCESS<span><font color="#990000"><nowiki>;</nowiki></font></span>
+
-
<span><font color="#FF0000">}</font></span>
+
-
</tt>
+
-
autoconf-automake/example3/hello.h
+
<source lang="c">
 +
/**
 +
* This maemo code example is licensed under a MIT-style license,
 +
* that can be found in the file called "License" in the same
 +
* directory as this file.
 +
* Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 +
*/
 +
#include <stdlib.h>
 +
#include "hello.h"
 +
int main(int argc, char** argv) {
 +
  printHello();
 +
  return EXIT_SUCCESS;
 +
}
 +
</source>
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example3/hello.h autoconf-automake/example3/hello.h]
-
<span>''<span><font color="#9A1900"> * This maemo code example is licensed under a MIT-style license,</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * that can be found in the file called "License" in the same</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * directory as this file.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.</font></span>''</span>
+
-
<span>''<span><font color="#9A1900"> */</font></span>''</span>
+
-
<span>'''<span><font color="#000080"><nowiki>#ifndef</nowiki></font></span>'''</span> INCLUDE_HELLO_H
+
-
<span>'''<span><font color="#000080"><nowiki>#define</nowiki></font></span>'''</span> INCLUDE_HELLO_H
+
-
<span>'''<span><font color="#0000FF">extern</font></span>'''</span> <span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">printHello</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#009900">void</font></span><span><font color="#990000">);</font></span>
+
-
<span>'''<span><font color="#000080"><nowiki>#endif</nowiki></font></span>'''</span>
+
-
</tt>
+
-
autoconf-automake/example3/hello.c
+
<source lang="c">
 +
/**
 +
* This maemo code example is licensed under a MIT-style license,
 +
* that can be found in the file called "License" in the same
 +
* directory as this file.
 +
* Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 +
*/
 +
#ifndef INCLUDE_HELLO_H
 +
#define INCLUDE_HELLO_H
 +
extern void printHello(void);
 +
#endif
 +
</source>
-
<tt><span>''<span><font color="#9A1900">/**</font></span>''</span>
+
[https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example3/hello.c autoconf-automake/example3/hello.c]
-
<span>''<span><font color="#9A1900"> * This maemo code example is licensed under a MIT-style license,</font></span>''</span>
+
 
-
  <span>''<span><font color="#9A1900"> * that can be found in the file called "License" in the same</font></span>''</span>
+
<source lang="c">
-
  <span>''<span><font color="#9A1900"> * directory as this file.</font></span>''</span>
+
/**
-
  <span>''<span><font color="#9A1900"> * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.</font></span>''</span>
+
* This maemo code example is licensed under a MIT-style license,
-
  <span>''<span><font color="#9A1900"> */</font></span>''</span>
+
  * that can be found in the file called "License" in the same
-
+
  * directory as this file.
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">&lt;stdio.h&gt;</font></span>
+
  * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
-
<span>'''<span><font color="#000080"><nowiki>#include</nowiki></font></span>'''</span> <span><font color="#FF0000">"hello.h"</font></span>
+
  */
-
+
 
-
<span><font color="#009900">void</font></span> <span>'''<span><font color="#000000">printHello</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#009900">void</font></span><span><font color="#990000">)</font></span> <span><font color="#FF0000">{</font></span>
+
#include <stdio.h>
-
  <span>''<span><font color="#9A1900">/* Note that these are available as defines now. */</font></span>''</span>
+
#include "hello.h"
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"("</font></span> PACKAGE <span><font color="#FF0000">" "</font></span> VERSION <span><font color="#FF0000">")</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
 
-
  <span>'''<span><font color="#000000">printf</font></span>'''</span><span><font color="#990000">(</font></span><span><font color="#FF0000">"Hello world!</font></span><span><font color="#CC33CC">\n</font></span><span><font color="#FF0000">"</font></span><span><font color="#990000">);</font></span>
+
void printHello(void) {
-
<span><font color="#FF0000">}</font></span>
+
  /* Note that these are available as defines now. */
-
</tt>
+
  printf("(" PACKAGE " " VERSION ")\n");
 +
  printf("Hello world!\n");
 +
}
 +
</source>
-
The PACKAGE and VERSION defines is passed to the build process automatically.
+
The <code>PACKAGE</code> and <code>VERSION</code> defines are passed to the build process automatically.
  [sbox-FREMANTLE_X86: ~/example3] &gt; autoconf
  [sbox-FREMANTLE_X86: ~/example3] &gt; autoconf
Line 974: Line 995:
Autoconf is complaining about a macro, for which it cannot find a definition (actually m4 is the program that does the complaining). The problem is that by default, autoconf only knows about built-in macros. When using a macro for integration or a macro that comes with another package, autoconf needs to be told about it. Luckily, this process is quite painless.
Autoconf is complaining about a macro, for which it cannot find a definition (actually m4 is the program that does the complaining). The problem is that by default, autoconf only knows about built-in macros. When using a macro for integration or a macro that comes with another package, autoconf needs to be told about it. Luckily, this process is quite painless.
-
A local '''aclocal.m4''' file needs to be created into the same directory with the '''configure.ac'''. When starting, autoconf reads this file, and it is enough to put the necessary macros there.
+
A local <code>aclocal.m4</code> file needs to be created into the same directory with the <code>configure.ac</code>. When starting, autoconf reads this file, and it is enough to put the necessary macros there.
-
For this, a utility program called aclocal is used, which scans the configure.ac and copy the relevant macros into the local aclocal.m4. The directory for all the extension macros is usually '''/usr/share/aclocal/''', which should be checked out at some point.
+
For this, a utility program called aclocal is used, which scans the configure.ac and copy the relevant macros into the local <code>aclocal.m4</code>. The directory for all the extension macros is usually <code>/usr/share/aclocal/</code>, which should be checked out at some point.
Now it is time to run aclocal, and then try and run autoconf again.  
Now it is time to run aclocal, and then try and run autoconf again.  
Line 982: Line 1,003:
Note that the messages that are introduced into the process from now on are inevitable, because some macros use obsolete features or have incomplete syntax, and thus trigger warnings. There is no easy solution to this, other than to fix the macros themselves.
Note that the messages that are introduced into the process from now on are inevitable, because some macros use obsolete features or have incomplete syntax, and thus trigger warnings. There is no easy solution to this, other than to fix the macros themselves.
-
[sbox-FREMANTLE_X86: ~/example3] &gt; aclocal
+
<pre>
-
/scratchbox/tools/share/aclocal/pkg.m4:5: warning:
+
[sbox-FREMANTLE_X86: ~/example3] > aclocal
-
  underquoted definition of PKG_CHECK_MODULES
+
/scratchbox/tools/share/aclocal/pkg.m4:5: warning:
-
  run info '(automake)Extending aclocal' or see
+
underquoted definition of PKG_CHECK_MODULES
-
  http://sources.redhat.com/automake/automake.html#Extending%20aclocal
+
  run info '(automake)Extending aclocal' or see
-
/usr/share/aclocal/pkg.m4:5: warning:
+
  http://sources.redhat.com/automake/automake.html#Extending%20aclocal
-
  underquoted definition of PKG_CHECK_MODULES
+
/usr/share/aclocal/pkg.m4:5: warning:
-
/usr/share/aclocal/gconf-2.m4:8: warning:
+
underquoted definition of PKG_CHECK_MODULES
-
  underquoted definition of AM_GCONF_SOURCE_2
+
/usr/share/aclocal/gconf-2.m4:8: warning:
-
/usr/share/aclocal/audiofile.m4:12: warning:
+
underquoted definition of AM_GCONF_SOURCE_2
-
  underquoted definition of AM_PATH_AUDIOFILE
+
/usr/share/aclocal/audiofile.m4:12: warning:
-
[sbox-FREMANTLE_X86: ~/example3] &gt; autoconf
+
underquoted definition of AM_PATH_AUDIOFILE
-
[sbox-FREMANTLE_X86: ~/example3] &gt; ./configure
+
[sbox-FREMANTLE_X86: ~/example3] > autoconf
-
configure: error: cannot find install-sh or install.sh in
+
[sbox-FREMANTLE_X86: ~/example3] > ./configure
-
  ~/example3 ~/ ~/..
+
configure: error: cannot find install-sh or install.sh in
 +
~/example3 ~/ ~/..
 +
</pre>
-
Listing the contents of the directory reveals that the '''Makefile.in''' is not among the contents. Automake needs to be run manually, so that the file is created. At the same time, the missing files need to be introduced to the directory (such as the install.sh that configure seems to complain about).
+
Listing the contents of the directory reveals that the <code>Makefile.in</code> is not among the contents. Automake needs to be run manually, so that the file is created. At the same time, the missing files need to be introduced to the directory (such as the install.sh that configure seems to complain about).
-
This is done by executing automake -ac, which creates the Makefile.in and also copy the missing files into their proper places. ''This step also copies a file called COPYING into the directory, which by default contains the GPL.'' So, if the software is going to be distributed under some other license, this is the correct moment to replace the license file with the appropriate one.
+
This is done by executing automake -ac, which creates the Makefile.in and also copy the missing files into their proper places. ''This step also copies a file called <code>COPYING</code> into the directory, which by default contains the GPL.'' So, if the software is going to be distributed under some other license, this is the correct moment to replace the license file with the appropriate one.
-
[sbox-FREMANTLE_X86: ~/example3] &gt; automake -ac
+
<pre>
-
configure.ac: installing `./install-sh'
+
[sbox-FREMANTLE_X86: ~/example3] > automake -ac
-
configure.ac: installing `./missing'
+
configure.ac: installing `./install-sh'
-
Makefile.am: installing `./depcomp'
+
configure.ac: installing `./missing'
-
[sbox-FREMANTLE_X86: ~/example3] &gt; ./configure
+
Makefile.am: installing `./depcomp'
-
checking for a BSD-compatible install... /scratchbox/tools/bin/install -c
+
[sbox-FREMANTLE_X86: ~/example3] > ./configure
-
checking whether build environment is sane... yes
+
checking for a BSD-compatible install... /scratchbox/tools/bin/install -c
-
checking for gawk... gawk
+
checking whether build environment is sane... yes
-
checking whether make sets $(MAKE)... yes
+
checking for gawk... gawk
-
checking for gcc... gcc
+
checking whether make sets $(MAKE)... yes
-
checking for C compiler default output file name... a.out
+
checking for gcc... gcc
-
checking whether the C compiler works... yes
+
checking for C compiler default output file name... a.out
-
checking whether we are cross compiling... no
+
checking whether the C compiler works... yes
-
checking for suffix of executables...
+
checking whether we are cross compiling... no
-
checking for suffix of object files... o
+
checking for suffix of executables...
-
checking whether we are using the GNU C compiler... yes
+
checking for suffix of object files... o
-
checking whether gcc accepts -g... yes
+
checking whether we are using the GNU C compiler... yes
-
checking for gcc option to accept ANSI C... none needed
+
checking whether gcc accepts -g... yes
-
checking for style of include used by make... GNU
+
checking for gcc option to accept ANSI C... none needed
-
checking dependency style of gcc... gcc3
+
checking for style of include used by make... GNU
-
checking for a BSD-compatible install... /scratchbox/tools/bin/install -c
+
checking dependency style of gcc... gcc3
-
configure: creating ./config.status
+
checking for a BSD-compatible install... /scratchbox/tools/bin/install -c
-
config.status: creating Makefile
+
configure: creating ./config.status
-
config.status: executing depfiles commands
+
config.status: creating Makefile
 +
config.status: executing depfiles commands
 +
</pre>
-
Notice the second to last line of the output, telling that autoconf just created a Makefile (based on the Makefile.in that ''automake'' created).
+
Notice the second to last line of the output, which shows that configure just created a Makefile (based on the <code>Makefile.in</code> that ''automake'' created).
-
Performing all these steps manually each time to make sure that all the generated files are really generated can be rather tedious. Most developers create a script called '''autogen.sh''', which implements the necessary bootstrap procedures for them. Below is a file that is suitable for this example. Real-life projects can have more steps because of localization and other requirements. autoconf-automake/example3/autogen.sh
+
Performing all these steps manually each time to make sure that all the generated files are really generated can be rather tedious. Most developers create a script called '''autogen.sh''', which implements the necessary bootstrap procedures for them. Below is a file that is suitable for this example. Real-life projects can have more steps because of localization and other requirements. [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example3/autogen.sh autoconf-automake/example3/autogen.sh]
-
<tt><span>''<span><font color="#9A1900"><nowiki>#!/bin/sh</nowiki></font></span>''</span>
+
<source lang="bash">
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
#!/bin/sh
-
<span>''<span><font color="#9A1900"><nowiki># A utility script to setup the autoconf environment for the first</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki># time. Normally this script is run when checking out a</nowiki></font></span>''</span>
+
# A utility script to setup the autoconf environment for the first
-
<span>''<span><font color="#9A1900"><nowiki># development version of the software from SVN/version control.</nowiki></font></span>''</span>
+
# time. Normally this script is run when checking out a
-
<span>''<span><font color="#9A1900"><nowiki># Regular users expect to download .tar.gz/tar.bz2 source code</nowiki></font></span>''</span>
+
# development version of the software from SVN/version control.
-
<span>''<span><font color="#9A1900"><nowiki># instead, and those should come with with 'configure' script so that</nowiki></font></span>''</span>
+
# Regular users expect to download .tar.gz/tar.bz2 source code
-
<span>''<span><font color="#9A1900"><nowiki># users do not require the autoconf/automake tools.</nowiki></font></span>''</span>
+
# instead, and those should come with with 'configure' script so that
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
# users do not require the autoconf/automake tools.
-
<span>''<span><font color="#9A1900"><nowiki># Scan configure.ac and copy the necessary macros into aclocal.m4.</nowiki></font></span>''</span>
+
#
-
aclocal
+
# Scan configure.ac and copy the necessary macros into aclocal.m4.
-
<span>''<span><font color="#9A1900"><nowiki># Generate Makefile.in from Makefile.am (and copy necessary support</nowiki></font></span>''</span>
+
aclocal
-
<span>''<span><font color="#9A1900"><nowiki># files, because of -ac).</nowiki></font></span>''</span>
+
# Generate Makefile.in from Makefile.am (and copy necessary support
-
automake -ac
+
# files, because of -ac).
-
<span>''<span><font color="#9A1900"><nowiki># This step is not normally necessary, but documented here for your</nowiki></font></span>''</span>
+
automake -ac
-
<span>''<span><font color="#9A1900"><nowiki># convenience. The files listed below need to be present to stop</nowiki></font></span>''</span>
+
# This step is not normally necessary, but documented here for your
-
<span>''<span><font color="#9A1900"><nowiki># automake from complaining during various phases of operation.</nowiki></font></span>''</span>
+
# convenience. The files listed below need to be present to stop
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
# automake from complaining during various phases of operation.
-
<span>''<span><font color="#9A1900"><nowiki># You also should consider maintaining these files separately once</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki># you release your project into the wild.</nowiki></font></span>''</span>
+
# You also should consider maintaining these files separately once
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
# you release your project into the wild.
-
<span>''<span><font color="#9A1900"><nowiki># touch NEWS README AUTHORS ChangeLog</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki># Run autoconf (creates the 'configure'-script).</nowiki></font></span>''</span>
+
# touch NEWS README AUTHORS ChangeLog
-
autoconf
+
# Run autoconf (creates the 'configure'-script).
-
echo <span><font color="#FF0000">'Ready to go (run configure)'</font></span>
+
autoconf
-
</tt>
+
echo 'Ready to go (run configure)'
 +
</source>
In the above code, the line with touch is commented. This can raise a question. There is a target called distcheck that automake creates in the Makefile, and this target checks whether the distribution tarball contains all the necessary files. The files listed on the touch line are necessary (even if empty), so they need to be created at some point. Without these files, the penultimate Makefile complains when running the distcheck-target.
In the above code, the line with touch is commented. This can raise a question. There is a target called distcheck that automake creates in the Makefile, and this target checks whether the distribution tarball contains all the necessary files. The files listed on the touch line are necessary (even if empty), so they need to be created at some point. Without these files, the penultimate Makefile complains when running the distcheck-target.
Line 1,087: Line 1,113:
  rm -f *.o
  rm -f *.o
-
== Checking for Distribution Sanity ==
+
=== Checking for Distribution Sanity ===
-
The generated Makefile contains various targets that can be used when creating distribution tarballs (tar files containing the source code and the necessary files to build the software). The most important of these is the dist-target, which by default creates a .tar.gz-file out of the source, including the configure script and other necessary files (which are specified in Makefile.am).
+
The generated Makefile contains various targets that can be used when creating distribution tarballs (tar files containing the source code and the necessary files to build the software). The most important of these is the dist-target, which by default creates a .tar.gz-file out of the source, including the configure script and other necessary files (which are specified in <code>Makefile.am</code>).
To test whether building the software from the distribution tarball is possible, execute the distcheck-target. It first creates a distribution tarball, then extracts it in a new subdirectory, runs configure there and tries and builds the software with the default make target. If it fails, the relevant error is given.
To test whether building the software from the distribution tarball is possible, execute the distcheck-target. It first creates a distribution tarball, then extracts it in a new subdirectory, runs configure there and tries and builds the software with the default make target. If it fails, the relevant error is given.
-
Making the distcheck target each time before making a dist target is recommended, so that you can be sure that the distribution tarball can be used outside the source tree. This step is especially critical later when making Debian packages.
+
Making the distcheck target each time before making a dist target is recommended, so that you can be sure that the distribution tarball can be used outside the source tree. This step is especially critical later when [[packaging|making Debian packages]].
-
== Cleaning up ==
+
=== Cleaning up ===
-
For the sake of convenience, the example3 directory also includes a script called antigen.sh, which tries its best to get rid of all generated files (it is necessary to autogen.sh the project afterwards).
+
For the sake of convenience, the example3 directory also includes a script called <code>antigen.sh</code>, which tries its best to get rid of all generated files (it is necessary to <code>autogen.sh</code> the project afterwards).
Having a clean-up script is not very common in open source projects, but it is especially useful when starting autotools development because it allows testing the toolchain easily from scratch.
Having a clean-up script is not very common in open source projects, but it is especially useful when starting autotools development because it allows testing the toolchain easily from scratch.
-
The contents of antigen.sh that is suitable for simple projects: autoconf-automake/example3/antigen.sh
+
The contents of antigen.sh that is suitable for simple projects: [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/autoconf-automake/example3/antigen.sh autoconf-automake/example3/antigen.sh]
-
<tt><span>''<span><font color="#9A1900"><nowiki>#!/bin/sh</nowiki></font></span>''</span>
+
<source lang="bash">
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
#!/bin/sh
-
<span>''<span><font color="#9A1900"><nowiki># A utility script to remove all generated files.</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
# A utility script to remove all generated files.
-
<span>''<span><font color="#9A1900"><nowiki># Running autogen.sh will be required after running this script since</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki># the 'configure' script will also be removed.</nowiki></font></span>''</span>
+
# Running autogen.sh will be required after running this script since
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
# the 'configure' script will also be removed.
-
<span>''<span><font color="#9A1900"><nowiki># This script is mainly useful when testing autoconf/automake changes</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki># and as a part of their development process.</nowiki></font></span>''</span>
+
# This script is mainly useful when testing autoconf/automake changes
-
<span>''<span><font color="#9A1900"><nowiki># If there's a Makefile, then run the 'distclean' target first (which</nowiki></font></span>''</span>
+
# and as a part of their development process.
-
<span>''<span><font color="#9A1900"><nowiki># will also remove the Makefile).</nowiki></font></span>''</span>
+
# If there's a Makefile, then run the 'distclean' target first (which
-
<span>'''<span><font color="#0000FF">if</font></span>'''</span> <span>'''<span><font color="#0000FF">test</font></span>'''</span> -f Makefile<span><font color="#990000"><nowiki>;</nowiki></font></span> <span>'''<span><font color="#0000FF">then</font></span>'''</span>
+
# will also remove the Makefile).
-
  make distclean
+
if test -f Makefile; then
-
<span>'''<span><font color="#0000FF">fi</font></span>'''</span>
+
  make distclean
-
<span>''<span><font color="#9A1900"><nowiki># Remove all tar-files (assuming there are some packages).</nowiki></font></span>''</span>
+
fi
-
rm -f <span><font color="#990000"><nowiki>*.</nowiki></font></span>tar<span><font color="#990000">.*</font></span> <span><font color="#990000"><nowiki>*.</nowiki></font></span>tgz
+
# Remove all tar-files (assuming there are some packages).
-
<span>''<span><font color="#9A1900"><nowiki># Also remove the autotools cache directory.</nowiki></font></span>''</span>
+
rm -f *.tar.* *.tgz
-
rm -Rf autom4te<span><font color="#990000">.</font></span>cache
+
# Also remove the autotools cache directory.
-
<span>''<span><font color="#9A1900"><nowiki># Remove rest of the generated files.</nowiki></font></span>''</span>
+
rm -Rf autom4te.cache
-
rm -f Makefile<span><font color="#990000">.</font></span><span>'''<span><font color="#0000FF">in</font></span>'''</span> aclocal<span><font color="#990000">.</font></span>m4 configure depcomp install-sh missing
+
# Remove rest of the generated files.
-
</tt>
+
rm -f Makefile.in aclocal.m4 configure depcomp install-sh missing
 +
</source>
-
== Integration with Pkg-Config ==
+
=== Integration with Pkg-Config ===
-
The last part that is covered for autoconf is how to integrate pkg-config support into the projects when using configure.ac.
+
The last part that is covered for autoconf is how to integrate pkg-config support into the projects when using <code>configure.ac</code>.
Pkg-config comes with a macro package ('''pkg.m4'''), which contains some useful macros for integration. The best documentation for these can be found in the pkg-config manual pages.
Pkg-config comes with a macro package ('''pkg.m4'''), which contains some useful macros for integration. The best documentation for these can be found in the pkg-config manual pages.
-
For the purpose of this example, only one macro is used, PKG_CHECK_MODULES, which is used as part of configure.ac for pkg-config integration
+
For the purpose of this example, only one macro is used, <code>PKG_CHECK_MODULES</code>, which is used as part of <code>configure.ac</code> for pkg-config integration
-
<tt><span>''<span><font color="#9A1900"><nowiki># Check whether the necessary pkg-config packages are present. The</nowiki></font></span>''</span>
+
<source lang="text">
-
<span>''<span><font color="#9A1900"><nowiki># PKG_CHECK_MODULES macro is supplied by pkg-config</nowiki></font></span>''</span>
+
# Check whether the necessary pkg-config packages are present. The
-
<span>''<span><font color="#9A1900"><nowiki># (/usr/share/aclocal/).</nowiki></font></span>''</span>
+
# PKG_CHECK_MODULES macro is supplied by pkg-config
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
# (/usr/share/aclocal/).
-
<span>''<span><font color="#9A1900"><nowiki># The first parameter is the variable name prefix that is</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki># used to create two variables: one to hold the CFLAGS required by</nowiki></font></span>''</span>
+
# The first parameter is the variable name prefix that is
-
<span>''<span><font color="#9A1900"><nowiki># the packages, and one to hold the LDFLAGS (LIBS) required by the</nowiki></font></span>''</span>
+
# used to create two variables: one to hold the CFLAGS required by
-
<span>''<span><font color="#9A1900"><nowiki># packages. The variable name prefix (HHW) can be chosen freely.</nowiki></font></span>''</span>
+
# the packages, and one to hold the LDFLAGS (LIBS) required by the
-
PKG_CHECK_MODULES<span><font color="#990000">(</font></span>HHW<span><font color="#990000">,</font></span> gtk<span><font color="#990000">+</font></span>-<span><font color="#993399">2.0</font></span> hildon-<span><font color="#993399">1</font></span> hildon-fm-<span><font color="#993399">2</font></span> gnome-vfs-<span><font color="#993399">2.0</font></span> <span><font color="#990000">\</font></span>
+
# packages. The variable name prefix (HHW) can be chosen freely.
-
                        gconf-<span><font color="#993399">2.0</font></span> libosso<span><font color="#990000">)</font></span>
+
PKG_CHECK_MODULES(HHW, gtk+-2.0 hildon-1 hildon-fm-2 gnome-vfs-2.0 \
-
<span>''<span><font color="#9A1900"><nowiki># At this point HHW_CFLAGS contains the necessary compiler flags</nowiki></font></span>''</span>
+
                      gconf-2.0 libosso)
-
<span>''<span><font color="#9A1900"><nowiki># and HHW_LIBS contains the linker options necessary for all the</nowiki></font></span>''</span>
+
# At this point HHW_CFLAGS contains the necessary compiler flags
-
<span>''<span><font color="#9A1900"><nowiki># packages listed above.</nowiki></font></span>''</span>
+
# and HHW_LIBS contains the linker options necessary for all the
-
<span>''<span><font color="#9A1900"><nowiki>#</nowiki></font></span>''</span>
+
# packages listed above.
-
<span>''<span><font color="#9A1900"><nowiki># Add the pkg-config supplied values to the ones that are used by</nowiki></font></span>''</span>
+
#
-
<span>''<span><font color="#9A1900"><nowiki># Makefile or supplied by the user running ./configure.</nowiki></font></span>''</span>
+
# Add the pkg-config supplied values to the ones that are used by
-
<span><font color="#009900">CFLAGS</font></span><span><font color="#990000"><nowiki>=</nowiki></font></span><span><font color="#FF0000">"$HHW_CFLAGS $CFLAGS"</font></span>
+
# Makefile or supplied by the user running ./configure.
-
<span><font color="#009900">LIBS</font></span><span><font color="#990000"><nowiki>=</nowiki></font></span><span><font color="#FF0000">"$HHW_LIBS $LIBS"</font></span></tt>
+
CFLAGS="$HHW_CFLAGS $CFLAGS"
 +
LIBS="$HHW_LIBS $LIBS"
 +
</source>
-
The proper placing for this code is after all the AC_PROG_* checks and before the AC_OUTPUT macros (so that the build flags may affect the substituted files).
+
The proper placing for this code is after all the <code>AC_PROG_*</code> checks and before the <code>AC_OUTPUT</code> macros (so that the build flags may affect the substituted files).
Check also the validity of the package names by using:
Check also the validity of the package names by using:
Line 1,159: Line 1,188:
to make sure you do not try to get the wrong library information.
to make sure you do not try to get the wrong library information.
 +
 +
[[Category:Development]]
 +
[[Category:Documentation]]
 +
[[Category:Fremantle]]

Latest revision as of 18:23, 13 October 2014

The following code examples are used in this chapter:

Contents

[edit] GNU Make and Makefiles

The make program from the GNU project is a powerful tool to aid implementing automation in the software building process. Beside this, it can be used to automate any task that uses files and in which these files are transformed into some other form. Make by itself does not know what the files contain or what they represent, but using a simple syntax it can be taught how to handle them.

When developing software with gcc (and other tools), gcc is often invoked repeatedly with the same parameters and flags. After changing one source file, it is noticed that other output files need to be rebuilt, and even the whole application if some interface has changed between the functions. This might happen whenever declarations change, new parameters are added to function prototypes, and so on.

These tasks can always be performed manually, but after a while a nicer way is more desirable.

GNU make is a software building automation tool that will execute repetitive tasks. It is controlled via a Makefile that contains lists of dependencies between different source files and output files. It also contains lists of commands that should be executed to satisfy these dependencies. Make uses the timestamps of files and the information of the files' existence to automate the rebuilding of applications (targets in make), as well as the rules that are specified in the Makefile.

Make can be used for other purposes as well. A target can easily be created for installing the built software on a destination computer, a target for generating documentation by using some automatic documentation generation tool, and so on. Some people use make to keep multiple Linux systems up to date with the newest software and various system configuration changes. In short, make is flexible enough to be generally useful.

Diagram of project dependencies
The dependencies between different files making up a software project

The aim of make is to satisfy the target. Each target has its own dependencies. A user generally selects a target for make to satisfy by supplying the target name on the command line. Make starts by checking whether all of the dependencies exist and have an older timestamp than the target. If so, make does nothing, because nothing has changed. However, because a header file (that an application is not dependent on directly) can change, make propagates the changes to the 'root' of the target as shown in the picture above.

Make rebuilds all of the necessary dependencies and targets on the way towards the target. This way, make only rebuilds those dependencies that actually affect something, and thus, saves time and effort. In big projects, the amount of time saved is significant.

To illustrate this, suppose that file3.c in the above picture is modified. After that, make is run, and it will automatically rebuild the necessary targets (file3.o, libutil.a and app):

Diagram of project files that need to be rebuilt
Project files that need to be rebuilt after file3.c is modified

Now suppose that another function is added to file1.c. Then also util.h needs to be modified accordingly. The picture shows that quite a few objects and targets depend on this header file, so a sizable number of objects need to be rebuilt (but not all):

Diagram of project files that need to be rebuilt
Project files that need to be rebuilt after file1.c and util.h are modified

N.B. In the example pictures, there is a project with a custom static library, which is linked against the test application.

[edit] Simple Real Example

Before delving too deeply into the syntax of makefiles, it is instructive to first see make in action. For this, a simple project will be used, written in the C language.

In C, it is customary to write "header" files (conventional suffix for them is .h) and regular source files (.c). The header files describe calling conventions, APIs and structures that are to be made usable for the outside world. The .c files contain the implementation of these interfaces.

The first rule in this is: if something is changed in the interface file, the binary file containing the code implementation (and other files that use the same interface) must be regenerated. Regeneration in this case means invoking gcc to create the binary file out of the C-language source file.

Make needs to be told two things at this point:

  • If a file's content changes, which other files will be affected? Because a single interface likely affects multiple other files, make uses a reversed ordering here. For each resulting file, it is necessary to list the files on which this one file depends on.
  • What are the commands to regenerate the resulting files when the need arises?

This example deals with that as simply as possible. There is a project that consists of two source files and one header file. The contents of these files are listed below: simple-make-files/hello.c

/**
 * The old faithful hello world.
 *
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 */
#include <stdlib.h>    /* EXIT_* */
#include "hello_api.h" /* sayhello */
int main(int argc, char **argv) {
  sayhello();
  return EXIT_SUCCESS;
}

simple-make-files/hello_func.c

/**
 * Implementation of sayhello.
 *
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 */
 
#include <stdio.h>     /* printf */
#include "hello_api.h" /* sayhello declaration */
 
void sayhello(void) {
  printf("Hello world!\n");
}

simple-make-files/hello_api.h

/**
 * Interface description for the hello_func module.
 *
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 */
 
#ifndef INCLUDE_HELLO_API_H
#define INCLUDE_HELLO_API_H
/* The above is protection against circular header inclusion. */
 
/* Function to print out "Hello world!\n". */
extern void sayhello(void);
 
#endif
/* ifndef INCLUDE_HELLO_API_H */

So, in effect, there is the main application in hello.c, which uses a function that is implemented in hello_func.c and declared in hello_api.h. Building an application out of these files can be performed manually like this:

gcc -Wall hello.c hello_func.c -o hello

Or, it can be done in three stages:

gcc -Wall -c hello.c -o hello.o
gcc -Wall -c hello_func.c -o hello_func.o
gcc -Wall hello.o hello_func.o -o hello

In both cases, the resulting application (hello) will be the same.

In the first case, gcc is instructed to process all source files in one go, link the resulting object code and store that code (program in this case) into hello.

In the second case, gcc is instructed to create a binary object file for each of the source files. After that, gcc is instructed to link these output files (hello.o and hello_func.o) together, and store the linked code into hello.

Image:Ambox_notice.png
When gcc reads through the C source files, it also reads in the header files, because the C code uses the #include preprocessor directive. This is because gcc internally runs all files ending with .c through cpp (the preprocessor) first.

The file describing this situation to make is as follows: simple-make-files/Makefile

# define default target (first target = default)
# it depends on 'hello.o' (which will be created if necessary)
# and hello_func.o (same as hello.o)
hello: hello.o hello_func.o
        gcc -Wall hello.o hello_func.o -o hello
# define hello.o target
# it depends on hello.c (and is created from it)
# also depends on hello_api.h which would mean that
# changing the hello.h api would force make to rebuild
# this target (hello.o).
# gcc -c: compile only, do not link
hello.o: hello.c hello_api.h
        gcc -Wall -c hello.c -o hello.o
# define hello_func.o target
# it depends on hello_func.c (and is created from)
# and hello_api.h (since that's its declaration)
hello_func.o: hello_func.c hello_api.h
        gcc -Wall -c hello_func.c -o hello_func.o
#

This file is in the simplest form without using any variables or relying on built-in magic in GNU make. Later it will be shown that the same rules can be written in a much shorter way.

This makefile can be tested by running make in the directory that contains the makefile and the source files:

user@system:~$ make
gcc -Wall -c hello.c -o hello.o
gcc -Wall -c hello_func.c -o hello_func.o
gcc -Wall hello.o hello_func.o -o hello

The resulting files after running make:

user@system:~$ ls -la
total 58
drwxr-xr-x 3  user user 456  Aug 11 15:04 .
drwxr-xr-x 13 user user 576  Aug 11 14:56 ..
-rw-r--r-- 1  user user 699  Jun 1  14:48 Makefile
-rwxr-xr-x 1  user user 4822 Aug 11 15:04 hello
-rw-r--r-- 1  user user 150  Jun 1  14:48 hello.c
-rw-r--r-- 1  user user 824  Aug 11 15:04 hello.o
-rw-r--r-- 1  user user 220  Jun 1  14:48 hello_api.h
-rw-r--r-- 1  user user 130  Jun 1  14:48 hello_func.c
-rw-r--r-- 1  user user 912  Aug 11 15:04 hello_func.o

Executing the binary:

user@system:~$ ./hello
Hello world!

[edit] Anatomy of Makefile

From the simple example above, some of the syntax of 'make' can be deduced.

Here are the rules that can be learned:

  • Comments are lines that start with the #-character. To be more precise, when make reads the makefile, it will ignore the #-character and any characters after it up to the end of the line. This means that comments can also be put at the end of lines, and make will ignore them, but this is considered bad practice as it would lead to subtle problems later on.
  • The backslash character (\) can be used to escape the special meaning of the next character. The most important special character in makefiles is the dollar character ($), which is used to access the contents of variables. There are also other special characters. To continue a line that is too long, the newline character can be escaped on that line. When the backslash is put at the end of the line, make ignores the newline when reading input.
  • Empty lines by themselves are ignored.
  • A line that starts at column 0 (start of the line) and contains a colon character (:) is considered a rule. The name on the left side of the colon is created by the commands. This name is called a target. Any filenames specified after the colon are the files that the target depends on. They are called prerequisites (i.e. they are required to exist, before make decides to create the target.
  • Lines starting with the tabulation character (tab) are commands that make runs to achieve the target.

In the printed material, the tabs are represented with whitespace, so be careful when reading the example makefiles. Note also that in reality, the command lines are considered as a part of the rule.

Using these rules, it can now be deduced that:

  • make regenerates hello when either or both of its prerequisites change. So, if either hello.o or hello_func.o change, make regenerates hello by using the command: gcc -Wall hello.o hello_func.o -o hello
  • If either hello.c or hello_api.h change, make regenerates hello.o.
  • If either hello_func.c or hello_api.h change, make regenerates
    hello_func.o.

[edit] Default Goal

Note that make was not explicitly told what it should do by default when run without any command line parameters (as was done above). How does it know that creating hello is the target for the run?

The first target given in a makefile is the default target. A target that achieves some higher-level goal (like linking all the components into the final application) is sometimes called a goal in GNU make documentation.

So, the first target in the makefile is the default goal when make is run without command line parameters.

N.B. Make automatically learns the dependencies between the various components and deduces that to create hello, it also needs to create hello.o and hello_func.o. Make regenerates the missing prerequisites when necessary. In fact, this is a quality that causes make do its magic.

Because the prerequisites for hello (hello.o and hello_func.o) do not exist, and hello is the default goal, make first creates the files that the hello target needs. This can be evidenced from the screen capture of make running without command line parameters. It shows the execution of each command in the order that make decides is necessary to satisfy the default goal's prerequisites, and finally create the hello.

user@system:~$ make
gcc -Wall -c hello.c -o hello.o
gcc -Wall -c hello_func.c -o hello_func.o
gcc -Wall hello.o hello_func.o -o hello

[edit] Names of Makefiles

The recommended name for the makefile is Makefile. This is not the first filename that GNU make tries to open, but it is the most portable one. In fact, the order of filenames that make attempts to open is: GNUMakefile, Makefile and finally makefile.

Unless you are sure that your makefile does not work on other make systems (not GNU), refrain from using GNUMakefile. Makefile will be used here for the most of this material. The idea behind using Makefile instead of makefile is related to how shells and commands sort filenames, when contents of directories are requested. Because in ASCII the uppercase letters come before the lowercase letters, the important files are listed first. Makefiles are considered important, because they are the basis for building the project. (The collation order might be different in your locale and your environment.)

Make can explicitly be told which file to read by using the -f command line option. This option is used in the next example.

[edit] Questions

Based on common sense, what should make do when it is run after:

  • Deleting the hello file?
  • Deleting the hello.o file?
  • Modifying hello_func.c?
  • Modifying hello.c?
  • Modifying hello_api.h?
  • Deleting the Makefile?

What would be done when writing the commands manually?

[edit] Adding Make Goals

Sometimes it is useful to add targets, whose execution does not result in a file, but instead causes some commands to be run. This is commonly used in makefiles of software projects to get rid of the binary files, so that building can be attempted from a clean state. These kinds of targets can also be justifiably called goals. GNU documentation uses the name "phony target" for these kinds of targets, because they do not result in creating a file, like normal targets do.

The next step is to create a copy of the original makefile, and add a goal that removes the binary object files and the application. N.B. Other parts of the makefile do not change. simple-make-files/Makefile.2

# add a cleaning target (to get rid of the binaries)
# define default target (first target = default)
# it depends on 'hello.o' (which must exist)
# and hello_func.o
hello: hello.o hello_func.o
        gcc -Wall hello.o hello_func.o -o hello
# define hello.o target
# it depends on hello.c (and is created from)
# also depends on hello_api.h which would mean that
# changing the hello.h api would force make to rebuild
# this target (hello.o).
# gcc -c: compile only, do not link
hello.o: hello.c hello_api.h
        gcc -Wall -c hello.c -o hello.o
# define hello_func.o target
# it depends on hello_func.c (and is created from)
# and hello_api.h (since that's it's declaration)
hello_func.o: hello_func.c hello_api.h
        gcc -Wall -c hello_func.c -o hello_func.o
# This is the definition of the target 'clean'
# Here we'll remove all the built binaries and
# all the object files that we might have generated
# Notice the -f flag for rm, it means "force" which
# in turn means that rm will try to remove the given
# files, and if there are none, then that's ok. Also
# it means that we have no writing permission to that
# file and have writing permission to the directory
# holding the file, rm will not then ask for permission
# interactivelly.
clean:
        rm -f hello hello.o hello_func.o

To get make to use this file instead of the default Makefile, use the -f command line parameter as follows:

user@system:~$ make -f Makefile.2
gcc -Wall -c hello.c -o hello.o
gcc -Wall -c hello_func.c -o hello_func.o
gcc -Wall hello.o hello_func.o -o hello

To control which target make processes (instead of the default goal), give the target name as a command line parameter like this:

user@system:~$ make -f Makefile.2 clean
rm -f hello hello.o hello_func.o

No binary files remain in the directory:

user@system:~$ ls -la
total 42
drwxr-xr-x 3  user user 376  Aug 11 15:08 .
drwxr-xr-x 13 user user 576  Aug 11 14:56 ..
-rw-r--r-- 1  user user 699  Jun 1  14:48 Makefile
-rw-r--r-- 1  user user 1279 Jun 1  14:48 Makefile.2
-rw-r--r-- 1  user user 150  Jun 1  14:48 hello.c
-rw-r--r-- 1  user user 220  Jun 1  14:48 hello_api.h
-rw-r--r-- 1  user user 130  Jun 1  14:48 hello_func.c

[edit] Making One Target at a Time

Sometimes it is useful to ask make to process only one target. Similar to the clean case, it just needs the target name to be given on the command line:

user@system:~$ make -f Makefile.2 hello.o
gcc -Wall -c hello.c -o hello.o

Multiple target names can also be supplied as individual command line parameters:

user@system:~$ make -f Makefile.2 hello_func.o hello
gcc -Wall -c hello_func.c -o hello_func.o
gcc -Wall hello.o hello_func.o -o hello

This can be done with any number of targets, even phony ones. Make tries to complete all of them in the order that they are on the command line. If any of the commands within the targets fail, make aborts at that point, and does not pursue the rest of the targets.

[edit] PHONY Keyword

Suppose that for some reason a file called clean appears in the directory in which make is run with clean as the target. In this case, make probably decides that because clean already exists, there is no need to run the commands leading to the target, and in this case, make does not run the rm command at all. Clearly this is something that needs to be avoided.

For these cases, GNU make provides a special target called .PHONY (note the leading dot). The real phony targets (clean) will be listed as a dependency to .PHONY. This signals to make that it should never consider a file called clean to be the result of the phony target.

In fact, this is what most open source projects that use make do.

This leads in the following makefile (comments omitted for brevity): simple-make-files/Makefile.3

hello: hello.o hello_func.o
        gcc -Wall hello.o hello_func.o -o hello
hello.o: hello.c hello_api.h
        gcc -Wall -c hello.c -o hello.o
hello_func.o: hello_func.c hello_api.h
        gcc -Wall -c hello_func.c -o hello_func.o
.PHONY: clean
clean:
        rm -f hello hello.o hello_func.o

[edit] Specifying Default Goal

Make uses the first target in a makefile as its default goal. What if there is a need to explicitly set the default goal instead? Because it is not possible to actually change the "first target is the default goal" setting in make, this needs to be taken into account. So, a new target has to be added, and made sure that it will be processed as the first target in a makefile.

To achieve this, a new phony target must be created, and the wanted targets should be listed as the phony target's prerequisites. Any name can be used for the target, but all is a very common name for this use. The only thing that needs to be rememberd is that this target needs to be the first one in the makefile. simple-make-files/Makefile.4

.PHONY: all
all: hello
hello: hello.o hello_func.o
        gcc -Wall hello.o hello_func.o -o hello
hello.o: hello.c hello_api.h
        gcc -Wall -c hello.c -o hello.o
hello_func.o: hello_func.c hello_api.h
        gcc -Wall -c hello_func.c -o hello_func.o
.PHONY: clean
clean:
        rm -f hello hello.o hello_func.o

Something peculiar can be seen in the listing above. Because the first target is the default goal for make, would that not make .PHONY now to be the default target? Because .PHONY is a special target in GNU make, this is safe. Also, because of compatibility reasons, GNU make ignores any targets that start with a leading dot (.) when looking for the default goal.

[edit] Other Common Phony Goals

Many other phony goals are encountered in makefiles that projects use.

Some of the more common ones include:

  • install: Prerequisites for install is the software application binary (or binaries). The commands (normally install is used on Linux) will specify which binary file to place under which directory on the system (/usr/bin, /usr/local/bin, etc).
  • distclean: Similar to clean; removes object files and such, but removes other files as well (sounds scary). Normally this is used to implement the removal of Makefile in the case that it was created by some automatic tool (configure for example).
  • package: Prerequisites are as in install, but instead of installing, creates an archive file (tar) with the files in question. This archive can then be used to distribute the software.

For information on other common phony targets, see GNU make manual.

[edit] Variables in Makefiles

So far these files have been listing filenames explicitly. Writing makefiles this way can get rather tedious, if not error prone.

This is why all make programs (not just the GNU variant) provide variables. Some other make programs call them macros.

Variables work almost as they do inside regular UNIX command shells. They are a simple mechanism, by which a piece of text can be associated with a name that can be referenced later on in multiple places in the makefiles. Make variables are based on text replacement, just like shell variables are.

[edit] Variable Flavors

The variables that can be used in makefiles come in two basic styles or flavors.

The default flavor is where referencing a variable causes make to expand the variable contents at the point of reference. This means that if the value of the variable is some text in which other variables are referenced, their contents is also replaced automatically. This flavor is called recursive.

The other flavor is simple, meaning that the content of a variable is evaluated only once, when the variable is defined.

Deciding on which flavor to use is important, when the evaluation of variable contents needs to be repeatable and fast. In these cases, simple variables are often the correct solution.

[edit] Recursive Variables

Here are the rules for creating recursive variables:

  • Names must contain only ASCII alphanumerics and underscores (to preserve portability).
  • Use only lowercase letters in the names of the variables. Make is case sensitive, and variable names written in capital letters are used when it is necessary to communicate the variables outside make, or their origin is from outside (environment variables). This is, however, only a convention, and there will also be variables that are local to the makefile, but still written in uppercase.
  • Values can contain any text. The text is evaluated by make when the variable is used, not when it is defined.
  • Break up long lines with a backslash character (\) and newline combination. Use this same mechanism to continue other long lines as well (not just variables). Do not put any whitespace after the backslash.
  • Do not reference a variable that is being defined in its text portion. This results in an endless loop whenever this variable is used. If this happens GNU make stops to an error.

Now the previously used makefile is reused, but some variables are introduced. This also shows the syntax of defining the variables, and how to use them (reference them): simple-make-files/Makefile.5

# define the command that we use for compilation
CC = gcc -Wall
# which targets do we want to build by default?
# note that 'targets' is just a variable, its name
# does not have any special meaning to make
targets = hello
# first target defined will be the default target
# we use the variable to hold the dependencies
.PHONY: all
all: $(targets)
hello: hello.o hello_func.o
        $(CC) hello.o hello_func.o -o hello
hello.o: hello.c hello_api.h
        $(CC) -c hello.c -o hello.o
hello_func.o: hello_func.c hello_api.h
        $(CC) -c hello_func.c -o hello_func.o
# we'll make our cleaning target more powerful
# we remove the targets that we build by default and also
# remove all object files
.PHONY: clean
clean:
        rm -f $(targets) *.o

The CC variable is the standard variable to hold the name of the C compiler executable. GNU make comes preloaded with a list of tools that can be accessed in similar way (as will be shown with $(RM) shortly, but there are others). Most UNIX tools related to building software already have similar pre-defined variables in GNU make. Here one of them is overridden to demonstrate how it is done. Overriding variables like this is not recommended, because the user running make later might want to use some other compiler, and would have to edit the makefile to do so.

[edit] Simple Variables

Suppose you have a makefile like this: simple-make-files/Makefile.6

CC = gcc -Wall
# we want to add something to the end of the variable
CC = $(CC) -g
hello.o: hello.c hello_api.h
        $(CC) -c hello.c -o hello.o

What might seem quite logical to a human reader, does not seem very logical to make.

Because the contents of recursive variables are evaluated when they are referenced, it can be seen that the above fragment will lead to an infinite loop.

How can this be corrected? Make actually provides two mechanisms for this. This is the solution with simple variables: simple-make-files/Makefile.7

CC := gcc -Wall
# we want to add something to the end of the variable
CC := $(CC) -g
hello.o: hello.c hello_api.h
        $(CC) -c hello.c -o hello.o

Notice that the equals character (=) has been changed into := .

This is how simple variables are created. Whenever a simple variable is referenced, make just replaces the text that the variable contains without evaluating it. It does the evaluation only when the variable is defined. In the above example, CC is created with the content of gcc -Wall (which is evaluated, but is just plain text), and when the CC variable is defined next time, make evaluates $(CC) -g which is replaced with gcc -Wall -g.

So, the only two differences between the variable flavors are:

  • When defining simple variables, := is used.
  • make evaluates the contents, when the simple variable is defined, not when it is referenced later.

Most of the time it is advisable to use the recursive variable flavor, because it does what is wanted.

Two ways of appending text to an existing variable were mentioned. The other mechanism is the += operation as follows: simple-make-files/Makefile.8

CC = gcc -Wall
# we want to add something to the end of the variable
CC += -g
hello.o: hello.c hello_api.h
        $(CC) -c hello.c -o hello.o

The prepending operation can also be used with simple variables. Make will not change the type of variable on the left side of the += operator.

[edit] Automatic Variables

There is a pre-defined set of variables inside make that can be used to avoid repetitive typing, when writing out the commands in a rule.

This is a list of the most useful ones:

  • $< : replaced by the first prerequisite of the rule.
  • $^ : replaced by the list of all prerequisites of the rule.
  • $@ : replaced by the target name.
  • $? : list of prerequisites that are newer than the target is (if target does not exist, they are all considered newer).

By rewriting the makefile using automatic variables, the result is: simple-make-files/Makefile.9

# add the warning flag to CFLAGS-variable
CFLAGS += -Wall
targets = hello
.PHONY: all
all: $(targets)
hello: hello.o hello_func.o
        $(CC) $^ -o $@
hello.o: hello.c hello_api.h
        $(CC) $(CFLAGS) -c $< -o $@
hello_func.o: hello_func.c hello_api.h
        $(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
        $(RM) $(targets) *.o

Notice the cases when $^ is used instead of $< in the above snippet. It is not desired to pass the header files for compilation to the compiler, because the source file already includes the header files. For this reason, $< is used. On the other hand, when linking programs and there are multiple files to put into the executable, $^ would normally be used.

This relies on a couple of things:

  • $(RM) and $(CC) will be replaced with paths to the system compiler and removal commands.
  • $(CFLAGS) is a variable that contains a list of options to pass whenever make invokes the C compiler.

It can also be noticed that all these variable names are in uppercase. This signifies that they have been communicated from the system environment to make. In fact, if creating an environment variable called CFLAGS, make will create it internally for any makefile that it will process. This is the mechanism to communicate variables into makefiles from outside.

Writing variables in uppercase is a convention signaling external variables, or environmental variables, so this is the reason why lowercase should be used in own private variables within a Makefile.

[edit] Integrating with Pkg-Config

The above has provided the knowledge to write a simple Makefile for the Hello World example. To get the the result of pkg-config, the GNU make $(shell command params) function will be used here. Its function is similar to the backtick operation of the shell. simple-make-files/Makefile.10

# define a list of pkg-config packages we want to use
pkg_packages := gtk+-2.0 hildon-1
# get the necessary flags for compiling
PKG_CFLAGS := $(shell pkg-config --cflags $(pkg_packages))
# get the necessary flags for linking
PKG_LDFLAGS := $(shell pkg-config --libs $(pkg_packages))
# additional flags
# -Wall: warnings
# -g: debugging
ADD_CFLAGS := -Wall -g
# combine the flags (so that CFLAGS/LDFLAGS from the command line
# still work).
CFLAGS  := $(PKG_CFLAGS) $(ADD_CFLAGS) $(CFLAGS)
LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
targets = hildon_helloworld-1
.PHONY: all
all: $(targets)
hildon_helloworld-1: hildon_helloworld-1.o
        $(CC) $^ -o $@ $(LDFLAGS)
hildon_helloworld-1.o: hildon_helloworld-1.c
        $(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
        $(RM) $(targets) *.o

You might wonder, where the CC and RM variables come from. They certainly were not declared anywhere in the Makefile. GNU make comes with a list of pre-defined variables for many programs and their arguments. GNU make also contains a preset list of pattern rules (which will not be dealt here), but basically these are pre-defined rules that are used when (for example) one needs an .o file from an .c file. The rules that were manually specified above are actually the same rules that GNU make already contains, so the Makefile can be made even more compact by only specifying the dependencies between files.

This leads to the following, slightly simpler version: simple-make-files/Makefile.11

# define a list of pkg-config packages we want to use
pkg_packages := gtk+-2.0 hildon-1
PKG_CFLAGS := $(shell pkg-config -cflags $(pkg_packages))
PKG_LDFLAGS := $(shell pkg-config -libs $(pkg_packages))
ADD_CFLAGS := -Wall -g
# combine the flags
CFLAGS  := $(PKG_CFLAGS) $(ADD_CFLAGS) $(CFLAGS)
LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
targets = hildon_helloworld-1
.PHONY: all
all: $(targets)
# we can omit the rules and just specify the dependencies
# for our simple project this doesn't seem like a big win
# but for larger projects where you have multiple object
# files, this will save considerable time.
hildon_helloworld-1: hildon_helloworld-1.o
hildon_helloworld-1.o: hildon_helloworld-1.c
.PHONY: clean
clean:
        $(RM) $(targets) *.o

[edit] GNU Autotools

Creating portable software written in the C language has historically been challenging. The portability issues are not restricted just to the differences between binary architectures, but also encompass differences in system libraries and different implementations of UNIX APIs in different systems. This section introduces GNU autotools as one solution for managing this complexity. There are also other tools available, but the most likely to be encountered are autotoolized projects and also Debian packaging supports autotools.

[edit] Brief History of Managing Portability

When discussing portability challenges with C code, various issues crop up:

  • Same library function has differing prototypes in different UNIX-style systems.
  • Same library function has differing implementations between systems (this is a difficult problem).
  • Same function can be found in different libraries in different UNIX systems, and because of this, the linker parameters need to be modified when making the final linking of the project.
  • Besides these not so obvious problems, there is also of course the problem of potentially different architecture, and hence different sizes for the standard C data types. This problem is best fixed by using GLib (as in this case), so it is not covered here.
  • GLib also provides the necessary macros to do endianess detection and conversion.

The historical solutions to solve these problems can be roughly grouped as follows:

  • The whole software is built with one big shell script, which tries to pass the right options to different compilers and tools. However, such scripts are very hard to maintain and their use is strongly discouraged.
  • Makefiles (GNU or other kind) allow some automation in building, but do not directly solve any of the portability issues. The classical solution is to ship various makefiles already tailored for different UNIX systems, and make it the user's responsibility to select the appropriate Makefile to use for their system. However, quite often this method required the Makefile to be edited, so the user had to be knowledgeable in UNIX programming tools. A good example of this style is found in some of the older versions of the game nethack.
  • Some parts of the Makefile selection above can be automated by a suitable script that tries to guess the system on which it is running and select a suitably prepared Makefile. However, maintaining such scripts is quite hard, because there have been so many different kinds of systems, such as different library versions and different compilers.
  • Even the creation of Makefiles can be automated from a script that guesses the system. Such scripts are normally called configure or Configure and are marked as executable for the sake of convenience. The name of the script does not automatically mean that the script is related to GNU autotools.
  • Two major branches of these master configure scripts evolved, each operating slightly differently and catering for differing needs.
  • These two scripts and a third guessing script were then combined into GNU autoconf. Because this happened many years ago, most of the historical code has already been purged from GNU autoconf.

Besides autoconf, it became evident that a more general Makefile generation tool can be useful as part of the whole process. This is how GNU automake was born. GNU automake can also be used outside autoconf. A simple autoconf configuration file is presented next.

[edit] GNU Autoconf

Autoconf is a tool that uses the GNU m4 macro preprocessor to process the configuration file and output a shell script based on the macros used in the file. Anything that m4 does not recognize as a macro is passed verbatim to the output script. This means that almost any wanted shell script fragments can be included into the configure.ac file (the modern name for the default configuration file for autoconf).

The first subject here is a simple example to see how the basic configuration file works. Then some limitations of m4 syntax are covered, and hints on how to avoid problems with the syntax are given. autoconf-automake/example1/configure.ac


GeSHi Error: GeSHi could not find the language autoconf (using path /usr/share/php-geshi/geshi/) (code 2)

You need to specify a language like this: <source lang="html4strict">...</source>

Supported languages for syntax highlighting:

abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80

The listing is verbosely commented, so it should be pretty self-evident what the different macros do. The macros that test for a feature or an include file normally causes the generated configure script to generate small C code test programs that are run as part of the configuration process. If these programs run successfully, the relevant test succeeds and the configuration process continues to the next test.

The following convention holds true in respect to the names of macros that are commonly used and available:

  • AC_*: A macro that is included in autoconf or is meant for it.
  • AM_*: A macro that is meant for automake.
  • Others: The autoconf system can be expanded by writing custom macros which can be stored in a custom directory. Some development packages also install new macros to be used.

The next step is to run autoconf. Without any parameters, it reads configure.ac by default. If configure.ac does not exist, it tries to read configure.in instead.

Note that using the name configure.in is considered obsolete.

 [sbox-FREMANTLE_X86: ~/example1] > autoconf
 [sbox-FREMANTLE_X86: ~/example1] > ls -l
 total 112
 drwxr-xr-x 2 user user  4096 Sep 16 05:14 autom4te.cache
 -rwxrwxr-x 1 user user 98683 Sep 16 05:14 configure
 -rw-r--r-- 1 user user  1825 Sep 15 17:23 configure.ac
 [sbox-FREMANTLE_X86: ~/example1] > ./configure
 Hello from configure (using echo)!
 
 configure: Hello from configure using msg-notice!
 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 ANSI C... none needed
 checking for gawk... gawk
 checking for cos in -lm... yes
 checking how to run the C preprocessor... gcc -E
 checking for egrep... grep -E
 checking for ANSI C header files... yes
 checking for sys/types.h... yes
 checking for sys/stat.h... yes
 checking for stdlib.h... yes
 checking for string.h... yes
 checking for memory.h... yes
 checking for strings.h... yes
 checking for inttypes.h... yes
 checking for stdint.h... yes
 checking for unistd.h... yes
 checking for unistd.h... (cached) yes
 checking math.h usability... yes
 checking math.h presence... yes
 checking for math.h... yes
 checking stdio.h usability... yes
 checking stdio.h presence... yes
 checking for stdio.h... yes
 checking b0rk.h usability... no
 checking b0rk.h presence... no
 checking for b0rk.h... no
 b0rk.h not present in system
 But that doesn't stop us from continuing!
 Directory to install binaries in is '${exec_prefix}/bin'
 Directory under which data files go is '${prefix}/share'
 For more variables, check 'config.log' after running configure
 CFLAGS is '-g -O2'
 LDFLAGS is ''
 LIBS is '-lm '
 CC is 'gcc'
 AWK is 'gawk'
 

Autoconf does not output information about its progress. Normally, only errors are output on stdout. Instead, it creates a new script called configure in the same directory, and sets it as executable.

The configure script is the result of all of the macro processing. If taking a look at the generated file with an editor or by using less, it can be seen that it contains a lot of shell code.

Unless you are experienced in reading convoluted shell code, you do not need to try to understand what is attempted at the various stages. Normally the generated file is not fixed or modified manually because it is overwritten anyway the next time that someone runs autoconf.

When the generated script is executed, the output of various parts can be seen in the order that they were used in the configuration file.

Note that autoconf (because of m4) is an imperative language, which means that it executes the commands one by one when it detects them. This is in contrast to declarative languages, like Makefiles.

M4-syntax notes:

  • Public autoconf M4 macros all start with A[CST]_* .
  • Private macros start with an underscore, but they must not be used because they change from one autoconf version to the other (using undocumented features is bad style anyway).
  • m4 uses [ and ] to quote arguments to functions, but in most cases quoting is not needed. Avoid using brackets, unless the macro does not seem to work properly otherwise. When writing new macros, using brackets become more important, but this material does not cover creating custom macros.
  • If brackets absolutely must be passed to the generated script, there are three choices:
    ${}$
    @<:@ is same as [, and @>:@ is same as ]
    []
    expands into [] (most of time)
    ${}$
    avoid [ and ] (most command line tools and shell do not really require them)
  • Because m4 uses brackets for its own needs, the [ command cannot be used to test things in scripts, but instead test has to be used (which is more clear anyway). This is why the brackets are escaped with the rules given above if they really must be output into the generated shell script.

If bad shell syntax is introduced into the configuration file, the bad syntax causes errors only when the generated script file is run (not when autoconf generates the script). In general, autoconf almost always succeeds but the generated script does not necessarily succeed. Knowing which error in the shell script corresponds to which line in the original configure.ac is not always easy but can be learned through experience.

There is a line that reports the result of testing for unistd.h. It appears twice: the first time because it is the default test to run whenever testing for headers, and the second time because it was explicitly tested for. The second test output contains text (cached), which means that the test has been already run, and the result has been saved into a cache (the mysterious autom4te.cache directory). This means that for large projects, which cannot necessarily perform the same tests over and over, the tests are only run once, which makes running the script faster.

The last line's output above contains the values of variables. When the configure script runs, it automatically creates shell variables that can be used in shell code fragments. The macros for checking what programs are available for compiling must illustrate that point. Here awk was used as an example.

The configure script takes the initial values for variables from the environment, but also contains a lot of options that can be given to the script. Using these options introduces new variables that can also be used. Options such as prefix are commonly used in compiling modern open source projects. Both of these cases are illustrated below:

 [sbox-FREMANTLE_X86: ~/example1] > CFLAGS='-O2 -Wall' ./configure --prefix=/usr
 ...
 Directory to install binaries in is '${exec_prefix}/bin'
 Directory under which data files go is '${prefix}/share'
 For more variables, check 'config.log' after running configure
 CFLAGS is '-O2 -Wall'
 LDFLAGS is ''
 LIBS is '-lm '
 CC is 'gcc'
 AWK is 'gawk'
 

It can seem that giving the prefix does not change anything, but this is because the shell does not expand the value in this particular case. However, if the variable was used in the script for doing something, the shell would expand later on. In order to see some effect, try passing the datadir-option (because that is printed out explicitly).

If you need to see which variables are available for configuration, read the generated config.log file. The variables are listed at the end of that file.

[edit] Substitutions

Besides creating the configure script, autoconf can do other useful things as well. Some people say that autoconf is at least as powerful as emacs, if not more so. Unfortunately, with all this power comes also lot of complexity. Sometimes finding out why things do not quite work can be rather difficult.

It can be useful to use the variables inside text files that are not directly related to the configure.ac. These might be configuration files or files that are used in some part of the building process later on. For this, autoconf provides a mechanism called substitution. A special macro reads in an external file, replaces all instances of variable names in it, and then stores the resulting file as a new file. The convention in naming the input files is to add a suffix .in to the names. The name of generated output file are the same but without the suffix.

Note that the substitution is done when the generated configure script is run, not when autoconf is run.

The generated configure script replaces all occurrences of the variable name surrounded with 'at' (@) characters with the variable value when it reads through each of the input files.

This is best illustrated with a small example. The input file contents are listed after the autoconf configuration file. In this example, the substitution is only made for one file, but it is also possible to process multiple files using the substitution mechanism. autoconf-automake/example2/configure.ac


GeSHi Error: GeSHi could not find the language autoconf (using path /usr/share/php-geshi/geshi/) (code 2)

You need to specify a language like this: <source lang="html4strict">...</source>

Supported languages for syntax highlighting:

abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80

autoconf-automake/example2/test-output.txt.in

This file will go through autoconf variable substitution.
The output file will be named as 'test-output.txt' (the '.in'-suffix
is stripped).
All the names surrounded by '@'-characters will be replaced by the values
of the variables (if present) by the configure script, when it is run
by the end user.
Prefix: @prefix@
C compiler: @CC@
This is a name for which there is no variable.
Stuff: @stuff@

We then run autoconf and configure:

[sbox-FREMANTLE_X86: ~/example2] > autoconf
[sbox-FREMANTLE_X86: ~/example2] > ./configure
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 ANSI C... none needed
checking for gawk... gawk
checking how to run the C preprocessor... gcc -E
checking for egrep... grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes 
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for unistd.h... (cached) yes
checking math.h usability... yes
checking math.h presence... yes
checking for math.h... yes
checking stdio.h usability... yes
checking stdio.h presence... yes
checking for stdio.h... yes
checking b0rk.h usability... no
checking b0rk.h presence... no
checking for b0rk.h... no
b0rk.h not present in system
But that doesn't stop us from continuing!
configure: creating ./config.status
config.status: creating test-output.txt
[sbox-FREMANTLE_X86: ~/example2] > cat test-output.txt
This file will go through autoconf variable substitution.

The output file will be named as 'test-output.txt' (the '.in'-suffix
is stripped).

All names surrounded by '@'-characters will be replaced by the values
of the variables (if present) by the configure script when it is run
by end user.

Prefix: /usr/local
C compiler: gcc

This is a name for which there is no variable.
Stuff: @stuff@

This feature is used later on. When you run your own version of the file, notice the creation of file called config.status. It is the file that actually does the substitution for external files, so if the configuration is otherwise complex, and you only want to re-run the substitution of the output files, you can run the config.status script.

[edit] Introducing Automake

The next step is to create a small project that consists of yet another hello world. This time, there is a file implementing the application (main), a header file describing the API (printHello()) and the implementation of the function.

As it happens, GNU automake is designed so that it can be easily integrated with autoconf. Makefiles are generated by a configure script, and it contains the necessary settings for the system on which configure is run.

In order for this to work, two things are necessary:

  • A configuration file for automake (conventionally Makefile.am) which contains the files to be generated using make
  • A configuration file for autoconf (conventionally configure.ac) which lists the tests which are required to ensure that the system has all the required dependencies

Running automake will generate a file Makefile.in containing a number of standard targets for make, and running autoconf will generate a configure script which will test your system, and generate final Makefiles and other files based on the software it finds present on the system.

The example starts with the autoconf configuration file: autoconf-automake/example3/configure.ac


GeSHi Error: GeSHi could not find the language autoconf (using path /usr/share/php-geshi/geshi/) (code 2)

You need to specify a language like this: <source lang="html4strict">...</source>

Supported languages for syntax highlighting:

abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80

Then the configuration file is presented for automake: autoconf-automake/example3/Makefile.am

# Automake rule primer:
# 1) Left side_ tells what kind of target this is.
# 2) _right side tells what kind of dependencies are listed.
#
# As an example, below:
# 1) bin = binaries
# 2) PROGRAMS lists the programs to generate Makefile.ins for.
bin_PROGRAMS = helloapp
# Listing source dependencies:
#
# The left side_ gives the name of the application to which the
# dependencies are related to.
# _right side gives again the type of dependencies.
#
# Here we then list the source files that are necessary to build the
# helloapp -binary.
helloapp_SOURCES = helloapp.c hello.c hello.h
# For other files that cannot be automatically deduced by automake,
# you need to use the EXTRA_DIST rule which should list the files
# that should be included. Files can also be in other directories or
# even whole directories can be included this way (not recommended).
EXTRA_DIST = some.service.file.service some.desktop.file.desktop

This material tries to introduce just enough of automake for it to be useful for small projects. Because of this, the detailed syntax of Makefile.am is not explained. Based on the above description, automake knows what kind of Makefile.in to create, and autoconf takes it over from there and fills in the missing pieces.

The source files for the project are as simple as possible, but notice the implementation of printHello. autoconf-automake/example3/helloapp.c

/**
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 */
#include <stdlib.h>
#include "hello.h"
int main(int argc, char** argv) {
  printHello();
  return EXIT_SUCCESS;
}

autoconf-automake/example3/hello.h

/**
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 */
#ifndef INCLUDE_HELLO_H
#define INCLUDE_HELLO_H
extern void printHello(void);
#endif

autoconf-automake/example3/hello.c

/**
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 */
 
#include <stdio.h>
#include "hello.h"
 
void printHello(void) {
  /* Note that these are available as defines now. */
  printf("(" PACKAGE " " VERSION ")\n");
  printf("Hello world!\n");
}

The PACKAGE and VERSION defines are passed to the build process automatically.

[sbox-FREMANTLE_X86: ~/example3] > autoconf
configure.ac:10: error: possibly undefined macro: AM_INIT_AUTOMAKE
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.

Autoconf is complaining about a macro, for which it cannot find a definition (actually m4 is the program that does the complaining). The problem is that by default, autoconf only knows about built-in macros. When using a macro for integration or a macro that comes with another package, autoconf needs to be told about it. Luckily, this process is quite painless.

A local aclocal.m4 file needs to be created into the same directory with the configure.ac. When starting, autoconf reads this file, and it is enough to put the necessary macros there.

For this, a utility program called aclocal is used, which scans the configure.ac and copy the relevant macros into the local aclocal.m4. The directory for all the extension macros is usually /usr/share/aclocal/, which should be checked out at some point.

Now it is time to run aclocal, and then try and run autoconf again.

Note that the messages that are introduced into the process from now on are inevitable, because some macros use obsolete features or have incomplete syntax, and thus trigger warnings. There is no easy solution to this, other than to fix the macros themselves.

[sbox-FREMANTLE_X86: ~/example3] > aclocal
/scratchbox/tools/share/aclocal/pkg.m4:5: warning:
 underquoted definition of PKG_CHECK_MODULES
  run info '(automake)Extending aclocal' or see
  http://sources.redhat.com/automake/automake.html#Extending%20aclocal
/usr/share/aclocal/pkg.m4:5: warning:
 underquoted definition of PKG_CHECK_MODULES
/usr/share/aclocal/gconf-2.m4:8: warning:
 underquoted definition of AM_GCONF_SOURCE_2
/usr/share/aclocal/audiofile.m4:12: warning:
 underquoted definition of AM_PATH_AUDIOFILE
[sbox-FREMANTLE_X86: ~/example3] > autoconf
[sbox-FREMANTLE_X86: ~/example3] > ./configure
configure: error: cannot find install-sh or install.sh in
 ~/example3 ~/ ~/..

Listing the contents of the directory reveals that the Makefile.in is not among the contents. Automake needs to be run manually, so that the file is created. At the same time, the missing files need to be introduced to the directory (such as the install.sh that configure seems to complain about).

This is done by executing automake -ac, which creates the Makefile.in and also copy the missing files into their proper places. This step also copies a file called COPYING into the directory, which by default contains the GPL. So, if the software is going to be distributed under some other license, this is the correct moment to replace the license file with the appropriate one.

[sbox-FREMANTLE_X86: ~/example3] > automake -ac
configure.ac: installing `./install-sh'
configure.ac: installing `./missing'
Makefile.am: installing `./depcomp'
[sbox-FREMANTLE_X86: ~/example3] > ./configure
checking for a BSD-compatible install... /scratchbox/tools/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 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 ANSI C... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking for a BSD-compatible install... /scratchbox/tools/bin/install -c
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands

Notice the second to last line of the output, which shows that configure just created a Makefile (based on the Makefile.in that automake created).

Performing all these steps manually each time to make sure that all the generated files are really generated can be rather tedious. Most developers create a script called autogen.sh, which implements the necessary bootstrap procedures for them. Below is a file that is suitable for this example. Real-life projects can have more steps because of localization and other requirements. autoconf-automake/example3/autogen.sh

#!/bin/sh
#
# A utility script to setup the autoconf environment for the first
# time. Normally this script is run when checking out a
# development version of the software from SVN/version control.
# Regular users expect to download .tar.gz/tar.bz2 source code
# instead, and those should come with with 'configure' script so that
# users do not require the autoconf/automake tools.
#
# Scan configure.ac and copy the necessary macros into aclocal.m4.
aclocal
# Generate Makefile.in from Makefile.am (and copy necessary support
# files, because of -ac).
automake -ac
# This step is not normally necessary, but documented here for your
# convenience. The files listed below need to be present to stop
# automake from complaining during various phases of operation.
#
# You also should consider maintaining these files separately once
# you release your project into the wild.
#
# touch NEWS README AUTHORS ChangeLog
# Run autoconf (creates the 'configure'-script).
autoconf
echo 'Ready to go (run configure)'

In the above code, the line with touch is commented. This can raise a question. There is a target called distcheck that automake creates in the Makefile, and this target checks whether the distribution tarball contains all the necessary files. The files listed on the touch line are necessary (even if empty), so they need to be created at some point. Without these files, the penultimate Makefile complains when running the distcheck-target.

Build the project now and test it out:

[sbox-FREMANTLE_X86: ~/example3] > make
if gcc -DPACKAGE_NAME=\"helloapp\" -DPACKAGE_TARNAME=\"helloapp\"
 -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"helloapp\ 0.1\"
 -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"helloapp\" -DVERSION=\"0.1\"
 -I. -Iexample3 -g -O2 -MT helloapp.o -MD -MP -MF ".deps/helloapp.Tpo"
 -c -o helloapp.o helloapp.c; \ then \
  mv -f ".deps/helloapp.Tpo" ".deps/helloapp.Po"; 
 else rm -f ".deps/helloapp.Tpo"; exit 1;
fi
if gcc -DPACKAGE_NAME=\"helloapp\" -DPACKAGE_TARNAME=\"helloapp\"
 -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"helloapp\ 0.1\"
 -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"helloapp\" -DVERSION=\"0.1\"
 -I. -Iexample3 -g -O2 -MT hello.o -MD -MP -MF ".deps/hello.Tpo"
 -c -o hello.o hello.c; \ then \
  mv -f ".deps/hello.Tpo" ".deps/hello.Po"; 
 else rm -f ".deps/hello.Tpo"; exit 1;
fi
gcc -g -O2 -o helloapp helloapp.o hello.o
[sbox-FREMANTLE_X86: ~/example3] > ./helloapp
(helloapp 0.1)
Hello world!
[sbox-FREMANTLE_X86: ~/example3] > make clean
test -z "helloapp" || rm -f helloapp
rm -f *.o

[edit] Checking for Distribution Sanity

The generated Makefile contains various targets that can be used when creating distribution tarballs (tar files containing the source code and the necessary files to build the software). The most important of these is the dist-target, which by default creates a .tar.gz-file out of the source, including the configure script and other necessary files (which are specified in Makefile.am).

To test whether building the software from the distribution tarball is possible, execute the distcheck-target. It first creates a distribution tarball, then extracts it in a new subdirectory, runs configure there and tries and builds the software with the default make target. If it fails, the relevant error is given.

Making the distcheck target each time before making a dist target is recommended, so that you can be sure that the distribution tarball can be used outside the source tree. This step is especially critical later when making Debian packages.

[edit] Cleaning up

For the sake of convenience, the example3 directory also includes a script called antigen.sh, which tries its best to get rid of all generated files (it is necessary to autogen.sh the project afterwards).

Having a clean-up script is not very common in open source projects, but it is especially useful when starting autotools development because it allows testing the toolchain easily from scratch.

The contents of antigen.sh that is suitable for simple projects: autoconf-automake/example3/antigen.sh

#!/bin/sh
#
# A utility script to remove all generated files.
#
# Running autogen.sh will be required after running this script since
# the 'configure' script will also be removed.
#
# This script is mainly useful when testing autoconf/automake changes
# and as a part of their development process.
# If there's a Makefile, then run the 'distclean' target first (which
# will also remove the Makefile).
if test -f Makefile; then
  make distclean
fi
# Remove all tar-files (assuming there are some packages).
rm -f *.tar.* *.tgz
# Also remove the autotools cache directory.
rm -Rf autom4te.cache
# Remove rest of the generated files.
rm -f Makefile.in aclocal.m4 configure depcomp install-sh missing

[edit] Integration with Pkg-Config

The last part that is covered for autoconf is how to integrate pkg-config support into the projects when using configure.ac.

Pkg-config comes with a macro package (pkg.m4), which contains some useful macros for integration. The best documentation for these can be found in the pkg-config manual pages.

For the purpose of this example, only one macro is used, PKG_CHECK_MODULES, which is used as part of configure.ac for pkg-config integration

# Check whether the necessary pkg-config packages are present. The
# PKG_CHECK_MODULES macro is supplied by pkg-config
# (/usr/share/aclocal/).
#
# The first parameter is the variable name prefix that is
# used to create two variables: one to hold the CFLAGS required by
# the packages, and one to hold the LDFLAGS (LIBS) required by the
# packages. The variable name prefix (HHW) can be chosen freely.
PKG_CHECK_MODULES(HHW, gtk+-2.0 hildon-1 hildon-fm-2 gnome-vfs-2.0 \
                       gconf-2.0 libosso)
# At this point HHW_CFLAGS contains the necessary compiler flags
# and HHW_LIBS contains the linker options necessary for all the
# packages listed above.
#
# Add the pkg-config supplied values to the ones that are used by
# Makefile or supplied by the user running ./configure.
CFLAGS="$HHW_CFLAGS $CFLAGS"
LIBS="$HHW_LIBS $LIBS"

The proper placing for this code is after all the AC_PROG_* checks and before the AC_OUTPUT macros (so that the build flags may affect the substituted files).

Check also the validity of the package names by using:

pkg-config --list-all

to make sure you do not try to get the wrong library information.