This is a Makefile named AutoMakefile for executing the Autotools toolchain.
It is based on the documentation Overview of GNU Autotools - Building Your Application
Check out the Autotools tutorial on this site to learn more about Automake, Autoconf, libtools, etc.
Briefly, the Autotools toolchain creates Makefiles automatically for your source code.
You can browse and download all files listed here (as well as others not listed).
BEFORE (not "Autotools-aware"):
Assume we have an existing project called mysleep, with the following tree layout:
mysleep/ (tree root)
src/
source code
doc/
documentation
man/
man pages
etc.
In this example, we will only use the src/ subdirectory.
Create the mysleep directory, create the subdirectory src/, and put the following files in src/:
src/mysleep.h:
#include<stdio.h>#ifdef WIN32
#include<windows.h>/* Needed for Windows Sleep() */#definesleep(x) (Sleep(x * 1000))
#else#include<unistd.h>/* Needed for BSD sleep() */#endif
src/mysleep.c:
#include"mysleep.h"
#defineSECONDS_TO_SLEEP 3
intmain()
{
unsignedintsleep_left = 0;
/* sleep() for SECONDS_TO_SLEEP seconds, then print a message. */
sleep(SECONDS_TO_SLEEP);
printf("I woke up after %d seconds.\n", SECONDS_TO_SLEEP);
return 0;
}
In the src/ directory you should now be able to compile and run the application:
cc mysleep.c -o mysleep
./mysleep
The output should be:
I woke up after 3 seconds.
AFTER ("Autotools-aware"):
These steps are required:
Include config.h in your code.
(Note that config.h does not exist yet, but will be created by Autotools.)
Create configure.ac in mysleep/.
Create Makefile.am in mysleep/.
Create src/Makefile.am.
1. src/mysleep.h (modified):
#include<config.h>#include<stdio.h>#ifdef WIN32
#include<windows.h>/* Needed for Windows Sleep() */#definesleep(x) (Sleep(x * 1000))
#else#include<unistd.h>/* Needed for BSD sleep() */#endif
2. configure.ac (you may run autoscan in the mysleep/ directory to create a template for this file):
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.56)
AC_INIT([mysleep], [0.0.1], [[email protected]])
# 1. Deprecated form of AM_INIT_AUTOMAKE:
# http://www.gnu.org/software/automake/manual/html_node/Public-macros.html
# AM_INIT_AUTOMAKE(sleep, 0.0.1)
# 2. Recommended form of AM_INIT_AUTOMAKE, but is not supported by older versions of automake
# AM_INIT_AUTOMAKE([-Wall -Werror foreign])
# 3. Tested to work with automake 1.4-p6
# AM_INIT_AUTOMAKE([-Wall])
# 4. Without options: Should work with any version, but does it tell you about all automake warnings?
AM_INIT_AUTOMAKEAC_CONFIG_SRCDIR([src/mysleep.c])
AM_CONFIG_HEADER(config.h)
AC_COPYRIGHT([Copyright 2007, Johan Kuuse])
# Checks for programs.
AC_PROG_CCAC_PROG_MAKE_SET# If you add the macro AC_PROG_LIBTOOL here, you must run "libtoolize" before "automake",
# or you will get an error:
# required file `./ltmain.sh' not found
###AC_PROG_LIBTOOL
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile
src/Makefile])
AC_OUTPUT
As we will see, both configure.ac and Makefile.am are small files, not too tricky to configure.
The tricky part consists in executing the 10 steps in the toolchain in the correct order.
This is where AutoMakefile comes to help.
It can execute all the toolchain steps, or one by one.
If one step is executed, all dependencies (read "previous steps") are executed first, to create all files in the correct order.
README.AutoMakefile was used as a specification for AutoMakefile to figure out dependencies:
# README.AutoMakefile - heavily based on
# http://developer.novell.com/wiki/index.php/Overview_of_GNU_Autotools#Building_Your_Application
Step 1:
Action: Create NEWS, README, AUTHORS, and ChangeLog if they do not exist already.
How: touch NEWS README AUTHORS ChangeLog
Input: None
Ouput: NEWS, README, AUTHORS, ChangeLog
Used in step: 7
Step 2:
Action: Create configure.ac automatically using autoscan if it does not exist.
Edit configure.ac by hand if it exists.
Check if configure.ac has been modified by hand.
How: Non-existing configure.ac: autoscan && mv configure.scan configure.ac
Existing configure.ac: awk check-for-modified configure.ac
Input: None
Ouput: configure.ac
Used in step: 4, 6, 8
Step 3:
Action: Create Makefile.am by hand if it does not exist.
Check if Makefile.am has been modified by hand.
How: awk check-for-modified Makefile.am
Input: None
Output: Makefile.am
Used in step: 7
Step 4:
Action: Create aclocal.m4
How: aclocal
Input: configure.ac (step 2)
Output: aclocal.m4
Used in steps: 5, 8
Step 5:
Action: Create config.h.in by invoking autoheader.
How: autoheader
Input: aclocal.m4 (step 4)
Output: config.h.in
Used in step: 9
Step 6 (optional, only with libtool):
Action: Create config.guess, config.sub, and ltmain.sh.
How: libtoolize
Input: configure.ac (step 2)
aclocal.m4 (step 4)
Output: config.guess, config.sub, ltmain.sh
Used in step: 7
NOTE: The web page
http://developer.novell.com/wiki/index.php/Overview_of_GNU_Autotools
does mention configure.ac but not aclocal.m4 (created in step 4) as
required input file for 'libtoolize'.
Anyhow, if aclocal.m4 is missing, 'libtoolize' complains with the following message:
"You should add the contents of `/usr/share/aclocal/libtool.m4' to `aclocal.m4'."The fix: Required input files: configure.ac, aclocal.m4
Step 7:
Action: Create Makefile.in, install-sh, missing, INSTALL, COPYING, and depcomp
by invoking automake.
How: automake --add-missing
Input: NEWS, README, AUTHORS, ChangeLog (step 1)
Makefile.am (step 3)
config.guess, config.sub, ltmain.sh (step 6, optional, only with libtool)
Output: Makefile.in, install-sh, missing, INSTALL, COPYING, depcomp
Used in step: 9
Step 8:
Action: Create configure by invoking autoconf.
How: autoconf
Input: aclocal.m4 (step 4)
configure.ac (step 2)
Output: configure
Used in step: 9
Step 9:
Action: Create Makefile by invoking configure
How: ./configure
Input: configure (step 8)
config.h.in (step 5)
Makefile.in (step 7)
Output: Makefile
Used in step: 10
Step 10:
Action: Create executable by executing make
How: make
Input: Makefile (step 9)
Output: executable
The Makefile is named AutoMakefile to not cause a name conflict with the automatically generated Makefile.
To use AutoMakefile as input to make, type:
make -f AutoMakefile
AutoMakefile:
# AutoMakefile - Makefile for autotools.
# NOTE: This file is for developers only!
# Read README, where the construction of this makefile is explained.
#
# If you just want to install and use the program/library, type:
# ./configure && make && make install
# Read INSTALL for details.
# Change this section to fit your needs.
# ---------------------------------------
# LIB1 =
PROGRAM1 = mysleep
FULL-PACKAGE-NAME = mysleep
VERSION = 0.0.1
BUG-REPORT-ADDRESS = [email protected]# ---------------------------------------
# There should be no need to change anything below this line.
# Variables for multiple targets.
TOUCH_TARGETS = AUTHORS ChangeLog NEWS README
LIBTOOLIZE_TARGETS = config.guess config.sub ltmain.sh
AUTOMAKE_TARGETS = Makefile.in install-sh missing INSTALL COPYING
.PHONY: help
help:
@echo Type \'make -f AutoMakefile all\' to generate a Makefile \
for this project using autotools.
@echo Type \'make -f AutoMakefile libtool\' to generate a Makefile \
for this project using autotools \(including libtool\).
@echo Type \'make -f AutoMakefile stepN\' \(N = 1-10\) to go through \
the autotool chain step by step.
@echo Type \'make -f AutoMakefile readme\' about a detailed explaination \
for each step.
@echo Type \'make -f AutoMakefile\' or \'make -f AutoMakefile help\' to show \
this message again.
.PHONY: readme
readme:
@if test -r README.AutoMakefile; then less README.AutoMakefile; else \
echo Sorry, but \'README.AutoMakefile\' is missing.; fi
# autotools process, step by step, as described in README.AutoMakefile
.PHONY: all
all: step1 step2 step3 step4 step5 step7 step8 step9 step10
.PHONY: libtool
libtool: libtool_precheck step1 step2 step3 step4 step5 step6 step7libtool step8 step9 step10
.PHONY: libtool_precheck
libtool_precheck:
@if ! test -r configure.ac; then echo configure.ac does not exist.; \
echo Please create it by hand and be sure to include the AC_PROG_LIBTOOL \
macro if you plan to run libtoolize.; exit 1; fi
@awk 'BEGIN {rc=1} {if ($$0 ~ /^AC_PROG_LIBTOOL/) {rc=0}} END {exit(rc)}' configure.ac || \
(echo Macro AC_PROG_LIBTOOL was not found in configure.ac.; \
echo Please add this macro to configure.ac if you plan to run libtoolize.; exit 1)
# Step 1:
# Create NEWS, README, AUTHORS, and ChangeLog, if missing.
.PHONY: step1
step1: $(TOUCH_TARGETS)
$(TOUCH_TARGETS):
touch $@# Step 2:
# Check if configure.ac exists.
# If not, create a template, configure.scan, using autoscan, rename configure.scan to configure.ac.
# Display "created, requires edit" message, exit.
# If configure.ac already exists, check if the AC_INIT macro has been edited has been edited.
# If not, display "requires edit" message, exit.
# NOTE: This target is .PHONY, as we always want to do this check.
have_configure_ac := $(wildcard configure.ac)
.PHONY: step2
ifeq($(strip $(have_configure_ac)),)
step2: configure.ac_was_created_from_template_and_requires_edit
.PHONY: configure.ac_was_created_from_template_and_requires_edit
configure.ac_was_created_from_template_and_requires_edit:
@echo "configure.ac does not exist, let us create a configure.scan template using autoscan..."
rm -rf autom4te.cache configure.scan && autoscan
mv configure.scan configure.ac
@echo "Now edit configure.ac by hand, then try again."
exit 1
elsestep2: configure.ac_exists_but_requires_edit
.PHONY: configure.ac_exists_but_requires_edit
configure.ac_exists_but_requires_edit:
@awk 'BEGIN {rc=1} {if ($$0 ~ /^AC_INIT/) {rc=0}} END {exit(rc)}' configure.ac || \
(echo The required macro AC_INIT is missing in configure.ac.; \
echo Please edit configure.ac and try again.; exit 1)
@awk '{if ($$0 ~ /^AC_INIT\(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS\)/) {printf "\
It seems like you have created a template for configure.ac, but you need to edit it.\n\
You should at least modify the following macro:\n\
AC_INIT\(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS\)\n\
Try something like:\n\
AC_INIT\($(FULL-PACKAGE-NAME), $(VERSION), $(BUG-REPORT-ADDRESS)\)\n\
Please edit configure.ac and try again.\n\
"; exit 1} }' configure.ac
endif# Step 3:
# Check if Makefile.am exists.
# If not, display "create" message, exit.
# If Makefile.am already exists, check if the variable 'datarootdir' is present.
# If not, display "requires edit" message, exit.
# NOTE: This target is .PHONY, as we always want to do this check.
have_makefile_am := $(wildcard Makefile.am)
.PHONY: step3
ifeq($(strip $(have_makefile_am)),)
step3: Makefile.am_does_not_exist
.PHONY: Makefile.am_does_not_exist
Makefile.am_does_not_exist:
@echo "Makefile.am does not exist, please create it by hand, then try again."
exit 1
elsestep3: Makefile.am_exists_but_requires_edit
.PHONY: Makefile.am_exists_but_requires_edit
Makefile.am_exists_but_requires_edit:
@awk 'BEGIN {rc=1} {if ($$0 ~ /datarootdir/) {rc=0}} END {exit(rc)}' Makefile.am || \
(echo You have created Makefile.am, but you need to edit it.; \
echo You should at least define the following variable:; \
echo datarootdir = $$\(prefix\)/share; \
echo Please edit Makefile.am and try again.; exit 1)
endif# Step 4:
# Create aclocal.m4
.PHONY: step4
step4: step2 aclocal.m4
aclocal.m4:
aclocal
# Step 5:
# Create config.h.in by invoking autoheader.
.PHONY: step5
step5: step4 config.h.in
config.h.in:
autoheader
# Step 6 (optional, for libtool only):
# Create config.guess, config.sub, and ltmain.sh by invoking libtoolize.
# TODO: Automatic check for AC_PROG_LIBTOOL macro in configure.ac.
# Do not use libtool if AC_PROG_LIBTOOL is missing.
.PHONY: step6
step6: configure.ac_requires_edit_for_libtool $(LIBTOOLIZE_TARGETS)
.PHONY: configure.ac_requires_edit_for_libtool
configure.ac_requires_edit_for_libtool: configure.ac step4
$(LIBTOOLIZE_TARGETS):
@awk 'BEGIN {rc=1} {if ($$0 ~ /^AC_PROG_LIBTOOL/) {rc=0}} END {exit(rc)}' configure.ac || \
(echo Macro AC_PROG_LIBTOOL was not found in configure.ac.; \
echo Please add this macro to configure.ac if you plan to run libtoolize.; exit 1)
libtoolize
# Step 7 (without libtool):
# Create Makefile.in, install-sh, missing, INSTALL, COPYING, and depcomp by invoking automake.
.PHONY: step7
step7: step1 step3 step5 $(AUTOMAKE_TARGETS)
# Step 7 (with libtool):
# Create Makefile.in, install-sh, missing, INSTALL, COPYING, and depcomp by invoking automake.
.PHONY: step7libtool
step8libtool: step1 step3 step5 step6 $(AUTOMAKE_TARGETS)
$(AUTOMAKE_TARGETS):
automake --add-missing --copy
# Step 8:
# Create configure by invoking autoconf.
.PHONY: step8
step8: step2 step4 configure
configure:
autoconf
# Step 9:
# Create Makefile by invoking configure.
.PHONY: step9
step9: step5 $(AUTOMAKE_TARGETS) step8 Makefile
.PHONY: step9libtool
step9libtool: step5 step6 $(AUTOMAKE_TARGETS) step8 Makefile
Makefile:
./configure
# Step 10:
# Create executable by executing make.
.PHONY: step10
step10: make
.PHONY: make
make: step9
make
@echo
@echo Type \'src/$(PROGRAM1)\' to launch the application.
@echo Type \'make install \' to install it \(requires root access\).
# Clean up.
.PHONY: clean
clean: emacsclean
# First, clean up from possible files created by 'make'.
@if test -r Makefile; then make clean; rm -f Makefile; fi
@if test -r src/Makefile; then cd src; make clean; rm -f Makefile; fi
# Then, clean up from files created by 'make -f AutoMakefile all'.
rm -rf .deps src/.deps COPYING INSTALL Makefile.in src/Makefile.in \
aclocal* autoscan.log autom4te.cache \
configure configure.scan config.* \
libtool stamp-h* *.o *.exe \
$(PROGRAM1) $(LIBTOOLIZE_TARGETS) $(AUTOMAKE_TARGETS) \
depcomp mkinstalldirs
# Clean up Emacs backup files in current directory and all subdirectories.
.PHONY: emacsclean
emacsclean:
find . -name "*~" -exec rm {} \;
Comments:
Note that each step (1-10) is defined as a .PHONY target, which serves as an "alias" for the "real" target.
If the "real" target is a file (most of the cases), then the "real" target is NOT defined as .PHONY.
(We don't want to recreate an already existing file.)
Let's look at the rule for the target step1 as an example:
The commands for the step1 target is always executed by force (it is a .PHONY target), but the touch command for each "real" target (NEWS, README, AUTHORS, and ChangeLog, respectively) is only executed if the file corrsponding to the target name does not exist.
As we see, step1 works an an "alias" for the four targets NEWSREADMEAUTHORSChangeLog.
The target step1 is .PHONY, but the resulting "real" targets are not.
On the other hand, if the target name doesn't correspond to a file name, this means that we want to force to execute tha target's commands.
Let's look at parts of the rule for the target step2 as an example (some lines omitted for clarity):
# Step 2:
# If configure.ac already exists, check if the AC_INIT macro has been edited has been edited.
# If not, display "requires edit" message, exit.
# NOTE: This target is .PHONY, as we always want to do this check.
step2: configure.ac_exists_but_requires_edit
.PHONY: configure.ac_exists_but_requires_edit
configure.ac_exists_but_requires_edit:
check configure.ac contents with 'awk', exit with error code if not edited correctly
The commands for the step2 target is always executed by force (it is a .PHONY target).
It is an alias for the target configure.ac_exists_but_requires_edit, which isn't a real target, and is also defined as .PHONY.
This is because we always want to force a check of the contents of configure.ac, even if the file configure.ac exists.