Using Not AutoMake to develop platform independent build environments

CAIA Technical Report 050412A

Jason But
April 12th, 2004

Table of Contents

  1. Introduction
  2. Producing Platform Independent Code
    1. Writing Platform Independent Source Code
    2. Providing a Platform Independent Build Environment
  3. The GNU AutoTools Suite
    1. Automake
    2. Autoconf
    3. Using Autoconf Without Automake
  4. Not AutoMake (NAM)
  5. Using NAM
    1. Required Files
      1. NAM_rules.mk.in
      2. bsd.mk
      3. gnu.mk
    2. Sample Files
      1. Makefile.in
      2. configure.in
    3. Building the Project
    4. Distributing the Project
    5. Examples
  6. Download NAM
  7. Conclusion

Introduction

While not all developed software - particularly tools developed for research purposes - is suitable for widespread distribution, it is still a good idea to develop software with a distinct goal of being able to compile and execute it on a variety of different platforms.

If we do intend to publically distribute code, then it becomes imperative to ensure that it will compile and execute on various platforms. This is even an issue when considering the same platform as different builds may have different names for their development tools, or may have libraries installed in different directories.

Recently, the general approach taken for distribution of platform independent code is the configure/make/make install cycle. In this technical report we discuss different ways to build this type of build environment, in particular looking at the GNU Autotools suite, why Automake is not as useful as Autoconf, and how to use Autoconf without Automake. I will then discuss our Not AutoMake (NAM) tool and how to use it to develop platform independent configure scripts.

Producing Platform Independent Code

There are two seperate issues to overcome when developing platform independent software:

Writing Platform Independent Source Code

A complete treatise of writing platform independent source code is beyond the scope of this document, but some tips that can be used to help guide you are:

Providing a Platform Independent Build Environment

The build environment is what enables the end user to build and install your software in such a way that they can later use it. This can be complex as you cannot guarantee that certain tools and libraries will be available on the end user's platform. Similarly, the tools you require may be present but available under a different name. Finally, installation of your software after the build process can be highly platform dependent - this might include the location of files after installation and whether or not any of the files need to be registered.

While it is possible for each project to have its own way of configuring the build environment, and then building and installing the software, the configure/make/make install cycle is fast becoming the de-facto technique to do so. In this case:

The primary difficulty in this scenario is how to write the configure script. In order for the script to function in all environments, we are restricted to using the standard Bourne Shell, the only scripting language which is practically guaranteed to exist on all platforms. While the shell itself may be present, this means we are limited in available functionality that more complex shells and scripting languages may offer.

The GNU AutoTools Suite

The GNU Autotools suite is a set of tools that aim to reduce the complexity in developing scripts to support the configure/make/make install software buildcycle. The suite consists of a number of tools but in terms of building application software, the tools of most interest are Automake and Autoconf.

The relationship between the tools in the GNU Autotools suite and their input and output files are shown in Fig. 1. For most developers, we need only create a configure.in and a set of Makefile.am files prior to running automake and autoconf to generate a final configure script and set of Makefile.in files. Execution of configure will use the Makefile.in files as templates to generate the Makefiles.


Figure 1 - Usage of the Autotools Suite

Automake

Automake uses the configure.in and a set of Makefile.am files as input to help it generate a set of Makefile.in files. Automake extracts a list of Makefile.am files to consider and some automake specific macros from the configure.in file and uses this information to help it decide what contents to put into the Makefile.in files. The Makefile.am files contain a list of targets seperated into different types and a list of sources that are required to build those targets. Automake then pieces together the required rules to build the specified targets from a library to Makefile segments to generate a templated set of Makefile.in files. Variables in the Makefile.in templates are later substituted by values determined when running the configure script.

AdvantagesDisadvantages
  • Makefile.am format is simple and easy to write.
  • No need to worry about writing a platform independent Makefile.
  • Large number of different types of targets supported
  • Adding extra rules that must be built at certain stages is difficult.
  • Generated Makefile.in template files are complex and difficult to understand.
  • The final Makefiles created using automake generated Makefile.in files are difficult to read
    • Understanding build process.
    • Debugging build/compile problems.
  • Output generated during make is messy and confusing
The biggest problem with automake is the quality of the generated Makefiles. While the execution of make is fully functional, the output is unwieldy and trying to debug the build process using the contents of the Makefiles is not easy - as the contents of these Makefiles are not commented or spaced out. An example of an automake generated Makefile can be downloaded here.

Typical output of running make on a project is shown below:

Making all in src
Making all in Crypto-PAn.1.0
if g++ -DHAVE_CONFIG_H -I. -I. -I../../include      -g -O2 -MT panonymizer.o -MD -MP -MF ".deps/panonymizer.Tpo" -c -o panonymizer.o panonymizer.cpp;  then mv -f ".deps/panonymizer.Tpo" ".deps/panonymizer.Po"; else rm -f ".deps/panonymizer.Tpo"; exit 1; fi
if g++ -DHAVE_CONFIG_H -I. -I. -I../../include      -g -O2 -MT rijndael.o -MD -MP -MF ".deps/rijndael.Tpo" -c -o rijndael.o rijndael.cpp;  then mv -f ".deps/rijndael.Tpo" ".deps/rijndael.Po"; else rm -f ".deps/rijndael.Tpo"; exit 1; fi
rm -f libCryptoPAn.a
ar cru libCryptoPAn.a panonymizer.o rijndael.o 
ranlib libCryptoPAn.a
Leaving Crypto-PAn.1.0
depbase=`echo application.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT application.o -MD -MP -MF "$depbase.Tpo" -c -o application.o application.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo parameters.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT parameters.o -MD -MP -MF "$depbase.Tpo" -c -o parameters.o parameters.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo pcapdev.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT pcapdev.o -MD -MP -MF "$depbase.Tpo" -c -o pcapdev.o pcapdev.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo uchar_traits.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT uchar_traits.o -MD -MP -MF "$depbase.Tpo" -c -o uchar_traits.o uchar_traits.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo anonymization/ipanonymization.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT anonymization/ipanonymization.o -MD -MP -MF "$depbase.Tpo" -c -o anonymization/ipanonymization.o anonymization/ipanonymization.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo anonymization/stringanonymizer.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT anonymization/stringanonymizer.o -MD -MP -MF "$depbase.Tpo" -c -o anonymization/stringanonymizer.o anonymization/stringanonymizer.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/nullpacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/nullpacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/nullpacket.o protocols/nullpacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/etherpacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/etherpacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/etherpacket.o protocols/etherpacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/ppppacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/ppppacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/ppppacket.o protocols/ppppacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/pppoediscoverypacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/pppoediscoverypacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/pppoediscoverypacket.o protocols/pppoediscoverypacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/pppoesessionpacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/pppoesessionpacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/pppoesessionpacket.o protocols/pppoesessionpacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/arppacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/arppacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/arppacket.o protocols/arppacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/ippacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/ippacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/ippacket.o protocols/ippacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/icmppacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/icmppacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/icmppacket.o protocols/icmppacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/tcppacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/tcppacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/tcppacket.o protocols/tcppacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/udppacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/udppacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/udppacket.o protocols/udppacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo protocols/dnspacket.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT protocols/dnspacket.o -MD -MP -MF "$depbase.Tpo" -c -o protocols/dnspacket.o protocols/dnspacket.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo tcpstreams/tcpdataflow.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT tcpstreams/tcpdataflow.o -MD -MP -MF "$depbase.Tpo" -c -o tcpstreams/tcpdataflow.o tcpstreams/tcpdataflow.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo tcpstreams/tcpstream.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT tcpstreams/tcpstream.o -MD -MP -MF "$depbase.Tpo" -c -o tcpstreams/tcpstream.o tcpstreams/tcpstream.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo tcpstreams/tcpstreammanager.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT tcpstreams/tcpstreammanager.o -MD -MP -MF "$depbase.Tpo" -c -o tcpstreams/tcpstreammanager.o tcpstreams/tcpstreammanager.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/appparser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/appparser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/appparser.o applications/appparser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/debugparser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/debugparser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/debugparser.o applications/debugparser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/httpparser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/httpparser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/httpparser.o applications/httpparser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/ftpparser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/ftpparser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/ftpparser.o applications/ftpparser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/smtpparser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/smtpparser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/smtpparser.o applications/smtpparser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/pop3parser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/pop3parser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/pop3parser.o applications/pop3parser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/imap4parser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/imap4parser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/imap4parser.o applications/imap4parser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/imap4common.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/imap4common.o -MD -MP -MF "$depbase.Tpo" -c -o applications/imap4common.o applications/imap4common.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/imap4client.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/imap4client.o -MD -MP -MF "$depbase.Tpo" -c -o applications/imap4client.o applications/imap4client.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/imap4server.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/imap4server.o -MD -MP -MF "$depbase.Tpo" -c -o applications/imap4server.o applications/imap4server.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/tlsparser.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/tlsparser.o -MD -MP -MF "$depbase.Tpo" -c -o applications/tlsparser.o applications/tlsparser.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
depbase=`echo applications/tlssession.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;  if g++ -DHAVE_CONFIG_H -I. -I. -I../include   -ICrypto-PAn.1.0   -g -O2 -MT applications/tlssession.o -MD -MP -MF "$depbase.Tpo" -c -o applications/tlssession.o applications/tlssession.cpp;  then mv -f "$depbase.Tpo" "$depbase.Po"; else rm -f "$depbase.Tpo"; exit 1; fi
g++  -g -O2    -o netsniff -LCrypto-PAn.1.0 application.o parameters.o  pcapdev.o uchar_traits.o  anonymization/ipanonymization.o  anonymization/stringanonymizer.o  protocols/nullpacket.o protocols/etherpacket.o  protocols/ppppacket.o  protocols/pppoediscoverypacket.o  protocols/pppoesessionpacket.o  protocols/arppacket.o protocols/ippacket.o  protocols/icmppacket.o protocols/tcppacket.o  protocols/udppacket.o protocols/dnspacket.o  tcpstreams/tcpdataflow.o  tcpstreams/tcpstream.o  tcpstreams/tcpstreammanager.o  applications/appparser.o  applications/debugparser.o  applications/httpparser.o  applications/ftpparser.o  applications/smtpparser.o  applications/pop3parser.o  applications/imap4parser.o  applications/imap4common.o  applications/imap4client.o  applications/imap4server.o  applications/tlsparser.o  applications/tlssession.o -lCryptoPAn -lpcap -lcrypto
Leaving src
Making all in include
make  all-am
Leaving include
Making all in scripts
Leaving scripts

As can be seen, each step in the build process is accompanied by a complex output string. On a typical terminal window, these build lines can often consume up to ten rows of the terminal display, with the command scrolling off the screen at a high rate. This type of output is unnecesary and unprofessional (in my humble opinion). A developer has issues of trying to spot compiler warning messages amongst the jumble of output, while trying to determine the progress of the build process is difficult since the text often scrolls by very quickly. This problem is often seen when building large open-source projects that compile large numbers (often over 100) source code files. Also, unless actually working on parameters required to build the application, compiler and linker flags are typically not necessary for a developer to see. It also appears unprofessional when the source is downloaded and installed by users who are not developers - having numerous lines of giberish does not create a polished look for our software.

A good example of well crafted make output is that output when building the Linux 2.6 kernel, where one line of output is printed for each step in the build process. The output looks professional, you can see exactly which files are being compiled, and information does not scroll off the terminal before the user has a chance to see it.

In conclusion, while automake does the job of generating Makefiles, it does so poorly. Fortunately, while it is not possible to use automake without also using autoconf, it is possible to use autoconf without using automake by manually generating the Makefile.in templates for the final configure script to use.

Autoconf

Autoconf uses the configure.in and optionally aclocal.m4 and acsite.m4 to generate a platform independent configure script. The autoconf program essentially parses the configure.in file with an M4 macro parser, expanding all contained macros into their base level shell script commands. It is possible to insert shell code directly into the configure.in file which will be processed when the configure script is executed.

The code in the final configure script essentially runs a series of system tests, storing the results in shell variables. Upon conclusion, these variables are substituted into appropriate locations in the Makefile.in files to generate the final Makefiles for the build.
AdvantagesDisadvantages
  • Pre-existing macro set to check for the existence of:
    • Tools
    • Programs
    • Libraries
    • Headers
  • M4 Macro Language to simplify understanding of configure.in
  • Can directly use shell script in configure.in
  • Can be used without automake
  • M4 Macro Language means needing to learn yet another language
  • The autotools suite of applications must be executed in the correct order to regenerate all required files and a correct configure script
The ability to easily check for the existence and locations of libraries installed on the system makes the developer task much easier. The final configure script can fail with an appropriate error message rather than the rather cryptic message printed at compile or link time during make. Also, as configure finds the locations of installed libraries, it is easier to ensure that they will be correctly used at build time.

It is also possible to not write a check for a required package in configure.in - in this case executing configure will be successful and the error will instead occur during the build (make) process.

For further assistance in writing configure.in files, please consult the Autoconf Manual.

NOTE: Autoconf will process either configure.in or configure.ac as input files. I prefer configure.in as it is consistent with the Makefile.in files we will also be generating.

Using Autoconf Without Automake

I previously mentioned that it is possible to use the autoconf tool without using automake. In this case we need to manually generate the Makefile.in template files. As per the Autoconf Manual, variables defined in the configure script will be substituted into the *.in templates where the variable name is both prefixed and suffixed with the '@' character (eg. @srcdir@ will be replaced with the value of the srcdir variable, containing a link to the directory containing the source).

The primary advantage is that any comments inserted into the Makefile.in templates will be migrated to the final Makefiles, similarly the structure of the template files will also be kept. This allows us to ensure that the final generated Makefiles will be neat and readable by any user looking to debug the build process.

Not AutoMake (NAM)

The primary problem with not using automake is that the entire build process must now be manuall created in the Makefile.in templates. In order to minimise the effort required to write these template files, I have developed Not AutoMake (NAM). NAM is a set of files that implement core project build functionality in a way that minimises the effort involved in writing Makefile.in file, it is based in spirit on the process used in the WINE project which also uses autoconf but not automake. The primary differences include comments, support for BSD Make as well as GNU Make and nice build output.

NAM offers the following features:

Using NAM

Details on downloading NAM are at the end of the document.

Required Files

NAM consists of three files, NAM_rules.mk.in, bsd.mk and gnu.mk. These three files should all be placed in the top level directory of the project to be built. You should not need to edit or modify these files in any way unless extending the functionality of NAM, in which case it would be appreciated if these changes are forwarded back to CAIA for incorporation into NAM.

NAM_rules.mk.in

Contains all the basic build rules to support the functionality provided by NAM, including regeneration of the Makefiles, recursive make, and all available targets. This file will be used as a template during execution of configure to generate NAM_rules.mk, which will subsequently be inserted into all other Makefiles for the project.

bsd.mk

Included from NAM_rules.mk during execution of make only if BSD Make is being executed. This includes some BSD make specific instructions to perform the tasks of:

gnu.mk

Included from NAM_rules.mk during execution of make only if GNU Make is being executed. This includes some GNU make specific instructions to perform the tasks of:

Sample Files

A sample Makefile.in and configure.in are also provided to assist in setting up the build environment for your project. Your project should have a single configure.in file situated in the top level directory of the project and a number of Makefile.in files, one in each recursive level you wish to run make in. It is absolutely necessary for a Makefile.in to exist in the top level directory of the project.

Makefile.in

The contents of the sample Makefile.in are listed below.
################################################################################
# File: Makefile                                                               #
################################################################################
# Makefile for the project.                                                    #
################################################################################

################################################################################
# Variables required by the global make rules.                                 #
################################################################################
# TOPSRCDIR   - Points to the top level directory of the project.              #
# SRCDIR      - Points to the actual directory where the source code files for #
#               this Makefile exists.                                          #
# VPATH       - Directory to look for source files if not in the current       #
#               directory.  Must be equal to SRCDIR.                           #
# TOPBUILDDIR - The top level directory we initially ran make from, used for   #
#               generating nice output of the working directories.             #
################################################################################
TOPSRCDIR   = @top_srcdir@
SRCDIR      = @srcdir@
VPATH       = @srcdir@
TOPBUILDDIR = ./@top_builddir@

##########
# Recursively make in these subdirectories
##########
SUBDIRS = subdir1 subdir2

##########
# Compile flags, list include directories
##########
INCLUDES = -I$(TOPSRCDIR)/extrainclude -I$(TOPSRCDIR)/include2

##########
# List of programs and archives to link
##########
PROGRAMS = prog1 prog2
ARCHIVES = libar1 libar2

##########
# Source files for each target
##########
prog1_SRCS = prog.cpp p1.cpp
prog2_SRCS = prog.cpp p2.cpp
libar1_SRCS = ar1.cpp ar2.cpp
libar2_SRCS = arA.cpp arB.cpp

##########
# Extra libraries for link stage (only if needed)
##########
prog1_LIBS = -lextralib
prog1_LDFLAGS = -L/path/to/extralib

##########
# Precompiled headers
##########
PRECOMP_HEADER = myheader.h

##########
# Stuff to install
##########
INSTALL_BIN = prog1
INSTALL_SBIN = prog2
INSTALL_MAN = prog1.5

@NAM_RULES@

################################################################################
# End of File: Makefile                                                        #
################################################################################

The comments in this file are optional and can be removed, however all comments will be copied into the final Makefile so their presence can be useful.

The first four lines of the Makefile.in file are mandatory and MUST NOT be commented out or deleted. These lines ensure that variables will be set for each Makefile to describe the location of certain required directories.

The remaining variables may be commented out or deleted as required, these variables have the following uses:

These variables should be declared BEFORE the line containing @NAM_RULES@ (which includes the contents of NAM_rules.mk).

Any program specific targets and extra instructions to run for the all, install and uninstall targets MUST be listed after the line containing @NAM_RULES@, otherwise the default target of all will be replaced.

When writing rules you need to be aware how output is taken care of during build. When make is run in clean(default) or quiet verbose mode (see below), then the Makefile is processed in silent mode, as if @ is prepended to all commands in all build rules. When make is run in verbose mode, all commands in all build rules will be echoed to the display

configure.in

The contents of the sample configure.in are listed below.
################################################################################
# The minimum version of autoconf required to regenerate the configure script. #
################################################################################
AC_PREREQ(2.59)

################################################################################
# Initialise autoconf, set package name, version number and contact details.   #
################################################################################
AC_INIT(my_prog, 0.1.2, [Contact Details])

AC_CONFIG_SRCDIR(src/myprog.cpp)

################################################################################
# Check for programs used to build my_prg                                      #
################################################################################
##########
# Check whether make sets the MAKE variable.
# Check which C++ compiler we have (sets CXX and CXXFLAGS)
# Check which RANLIB program we have
# Set the language for all further tests to C++
##########
AC_PROG_MAKE_SET
AC_PROG_CXX
AC_PROG_RANLIB
AC_PROG_INSTALL

AC_LANG(C++)

AC_ARG_PROGRAM

##########
# Check how dependencies are created for the C++ compiler on this system
##########
AS_IF(g++ -v -MP 2> /dev/null, 
      [AC_SUBST(CPPDEPFLAGS, "-MMD -MP -MF \"\`dirname \$@\`/.deps/\`basename \$*\`.d\"")] [AC_SUBST(DEPDIR, ".deps")],
      [AC_SUBST(CPPDEPFLAGS, "-MMD")] [AC_SUBST(DEPDIR, ".")])

# Add macros to check for other programs here

################################################################################
# Checks for header files.                                                     #
################################################################################
# Add macros to check for header files here

################################################################################
# Checks for typedefs, structures, and compiler characteristics.               #
################################################################################
# Add macros to check for these characteristics here

################################################################################
# Checks for library functions.                                                #
################################################################################
# Add macros to check for library functions here

################################################################################
# Allow insertion of the global rules from NAM_rules.mk(.in) into any file     #
# that requests it using @NAM_RULES@.  Note that for this to work properly,    #
# NAM_rules.mk must be listed BEFORE any Makefiles that use this feature in    #
# the AC_CONFIG_FILES() macro below.                                           #
################################################################################
NAM_RULES=NAM_rules.mk
AC_SUBST_FILE(NAM_RULES)

################################################################################
# List of files to generate from the corresponding (*.in) files and the        #
# subsequent command to generate those files.                                  #
################################################################################
AC_CONFIG_FILES([NAM_rules.mk Makefile add extra makefiles])

AC_OUTPUT

This contains the minimal set of macros required in a configure.in file to work within the NAM architecture. You should add extra tests (macros) where indicated by the comments. You must also ensure that your Makefiles are listed AFTER NAM_rules.mk in the AC_CONFIG_FILES macro, otherwise an old copy of NAM_rules.mk will be included into your Makefile. For more information in writing configure.in macros, please consult the Autoconf Manual.

Building the Project

When you project is ready to go, you can build it by invoking the configure script to prepare the Makefiles initially. I prefer to invoke the build in a different subtree of the project so that object and other files do not get mixed up with the source code for the project. To do this for a project in a directory called my_proj you can execute the following steps:
    cd my_proj
    autoconf
    mkdir build
    cd build
    ../configure
  
Executing autoconf will generate the configure script initially, while running configure from the build subdirectory will cause the top level directory for the build to be in the build directory, this is where you will find the top level Makefile.

You can now execute make from this directory to build and install the software. It is no longer necessary to rerun autoconf as the Makefile you have just generated will ensure this occurs if required (due to a change in any of the *.in files).

To build the software with clean (default) output:

    make
or
    make VERBOSE=1
To build the software with verbose output:
    make VERBOSE=2
To build the software with silent output:
    make VERBOSE=3
To install the software with clean (default) output:
    make install
or
    make VERBOSE=1 install
To clean the build tree with verbose output:
    make VERBOSE=2 clean
The same verbosity rule is applied to other targets.

Sample output during execution of make for the netsniff project is shown below.

 Making in	src
 Making in	src/Crypto-PAn.1.0
  Compiling:	panonymizer.cpp
  Compiling:	rijndael.cpp
  Archiving:	libCryptoPAn.a
  Indexing:	libCryptoPAn.a
 Leaving	src/Crypto-PAn.1.0

  Compiling:	application.cpp
  Compiling:	parameters.cpp
  Compiling:	pcapdev.cpp
  Compiling:	uchar_traits.cpp
  Compiling:	anonymization/ipanonymization.cpp
  Compiling:	anonymization/stringanonymizer.cpp
  Compiling:	protocols/nullpacket.cpp
  Compiling:	protocols/etherpacket.cpp
  Compiling:	protocols/ppppacket.cpp
  Compiling:	protocols/pppoediscoverypacket.cpp
  Compiling:	protocols/pppoesessionpacket.cpp
  Compiling:	protocols/arppacket.cpp
  Compiling:	protocols/ippacket.cpp
  Compiling:	protocols/icmppacket.cpp
  Compiling:	protocols/tcppacket.cpp
  Compiling:	protocols/udppacket.cpp
  Compiling:	protocols/dnspacket.cpp
  Compiling:	tcpstreams/tcpdataflow.cpp
  Compiling:	tcpstreams/tcpstream.cpp
  Compiling:	tcpstreams/tcpstreammanager.cpp
  Compiling:	applications/appparser.cpp
  Compiling:	applications/debugparser.cpp
  Compiling:	applications/httpparser.cpp
  Compiling:	applications/ftpparser.cpp
  Compiling:	applications/smtpparser.cpp
  Compiling:	applications/pop3parser.cpp
  Compiling:	applications/imap4parser.cpp
  Compiling:	applications/imap4common.cpp
  Compiling:	applications/imap4client.cpp
  Compiling:	applications/imap4server.cpp
  Compiling:	applications/tlsparser.cpp
  Compiling:	applications/tlssession.cpp
  Linking:	netsniff
 Leaving	src

 Making in	scripts
 Leaving	scripts


Sample output during execution of make VERBOSE=2 for the netsniff project is shown below.

gmake[1]: Entering directory `/home/jbut/Development/test/build/src'
gmake[2]: Entering directory `/home/jbut/Development/test/build/src/Crypto-PAn.1.0'
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../../src/Crypto-PAn.1.0 -I../../../include -MMD -MP -MF "`dirname panonymizer.o`/.deps/`basename panonymizer`.d" -c -o panonymizer.o ../../../src/Crypto-PAn.1.0/panonymizer.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../../src/Crypto-PAn.1.0 -I../../../include -MMD -MP -MF "`dirname rijndael.o`/.deps/`basename rijndael`.d" -c -o rijndael.o ../../../src/Crypto-PAn.1.0/rijndael.cpp
ar cru libCryptoPAn.a panonymizer.o rijndael.o  
ranlib libCryptoPAn.a
gmake[2]: Leaving directory `/home/jbut/Development/test/build/src/Crypto-PAn.1.0'
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname application.o`/.deps/`basename application`.d" -c -o application.o ../../src/application.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname parameters.o`/.deps/`basename parameters`.d" -c -o parameters.o ../../src/parameters.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname pcapdev.o`/.deps/`basename pcapdev`.d" -c -o pcapdev.o ../../src/pcapdev.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname uchar_traits.o`/.deps/`basename uchar_traits`.d" -c -o uchar_traits.o ../../src/uchar_traits.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname anonymization/ipanonymization.o`/.deps/`basename anonymization/ipanonymization`.d" -c -o anonymization/ipanonymization.o ../../src/anonymization/ipanonymization.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname anonymization/stringanonymizer.o`/.deps/`basename anonymization/stringanonymizer`.d" -c -o anonymization/stringanonymizer.o ../../src/anonymization/stringanonymizer.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/nullpacket.o`/.deps/`basename protocols/nullpacket`.d" -c -o protocols/nullpacket.o ../../src/protocols/nullpacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/etherpacket.o`/.deps/`basename protocols/etherpacket`.d" -c -o protocols/etherpacket.o ../../src/protocols/etherpacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/ppppacket.o`/.deps/`basename protocols/ppppacket`.d" -c -o protocols/ppppacket.o ../../src/protocols/ppppacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/pppoediscoverypacket.o`/.deps/`basename protocols/pppoediscoverypacket`.d" -c -o protocols/pppoediscoverypacket.o ../../src/protocols/pppoediscoverypacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/pppoesessionpacket.o`/.deps/`basename protocols/pppoesessionpacket`.d" -c -o protocols/pppoesessionpacket.o ../../src/protocols/pppoesessionpacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/arppacket.o`/.deps/`basename protocols/arppacket`.d" -c -o protocols/arppacket.o ../../src/protocols/arppacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/ippacket.o`/.deps/`basename protocols/ippacket`.d" -c -o protocols/ippacket.o ../../src/protocols/ippacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/icmppacket.o`/.deps/`basename protocols/icmppacket`.d" -c -o protocols/icmppacket.o ../../src/protocols/icmppacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/tcppacket.o`/.deps/`basename protocols/tcppacket`.d" -c -o protocols/tcppacket.o ../../src/protocols/tcppacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/udppacket.o`/.deps/`basename protocols/udppacket`.d" -c -o protocols/udppacket.o ../../src/protocols/udppacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname protocols/dnspacket.o`/.deps/`basename protocols/dnspacket`.d" -c -o protocols/dnspacket.o ../../src/protocols/dnspacket.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname tcpstreams/tcpdataflow.o`/.deps/`basename tcpstreams/tcpdataflow`.d" -c -o tcpstreams/tcpdataflow.o ../../src/tcpstreams/tcpdataflow.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname tcpstreams/tcpstream.o`/.deps/`basename tcpstreams/tcpstream`.d" -c -o tcpstreams/tcpstream.o ../../src/tcpstreams/tcpstream.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname tcpstreams/tcpstreammanager.o`/.deps/`basename tcpstreams/tcpstreammanager`.d" -c -o tcpstreams/tcpstreammanager.o ../../src/tcpstreams/tcpstreammanager.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/appparser.o`/.deps/`basename applications/appparser`.d" -c -o applications/appparser.o ../../src/applications/appparser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/debugparser.o`/.deps/`basename applications/debugparser`.d" -c -o applications/debugparser.o ../../src/applications/debugparser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/httpparser.o`/.deps/`basename applications/httpparser`.d" -c -o applications/httpparser.o ../../src/applications/httpparser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/ftpparser.o`/.deps/`basename applications/ftpparser`.d" -c -o applications/ftpparser.o ../../src/applications/ftpparser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/smtpparser.o`/.deps/`basename applications/smtpparser`.d" -c -o applications/smtpparser.o ../../src/applications/smtpparser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/pop3parser.o`/.deps/`basename applications/pop3parser`.d" -c -o applications/pop3parser.o ../../src/applications/pop3parser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/imap4parser.o`/.deps/`basename applications/imap4parser`.d" -c -o applications/imap4parser.o ../../src/applications/imap4parser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/imap4common.o`/.deps/`basename applications/imap4common`.d" -c -o applications/imap4common.o ../../src/applications/imap4common.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/imap4client.o`/.deps/`basename applications/imap4client`.d" -c -o applications/imap4client.o ../../src/applications/imap4client.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/imap4server.o`/.deps/`basename applications/imap4server`.d" -c -o applications/imap4server.o ../../src/applications/imap4server.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/tlsparser.o`/.deps/`basename applications/tlsparser`.d" -c -o applications/tlsparser.o ../../src/applications/tlsparser.cpp
g++ -g -O2 -DHAVE_CONFIG_H -I. -I../../src -I../../include -I../../src/Crypto-PAn.1.0 -I../../src/anonymization -I../../src/protocols -I../../src/tcpstreams -I../../src/applications -MMD -MP -MF "`dirname applications/tlssession.o`/.deps/`basename applications/tlssession`.d" -c -o applications/tlssession.o ../../src/applications/tlssession.cpp
g++  -LCrypto-PAn.1.0 -o netsniff application.o parameters.o pcapdev.o uchar_traits.o anonymization/ipanonymization.o anonymization/stringanonymizer.o protocols/nullpacket.o protocols/etherpacket.o protocols/ppppacket.o protocols/pppoediscoverypacket.o protocols/pppoesessionpacket.o protocols/arppacket.o protocols/ippacket.o protocols/icmppacket.o protocols/tcppacket.o protocols/udppacket.o protocols/dnspacket.o tcpstreams/tcpdataflow.o tcpstreams/tcpstream.o tcpstreams/tcpstreammanager.o applications/appparser.o applications/debugparser.o applications/httpparser.o applications/ftpparser.o applications/smtpparser.o applications/pop3parser.o applications/imap4parser.o applications/imap4common.o applications/imap4client.o applications/imap4server.o applications/tlsparser.o applications/tlssession.o  -lCryptoPAn -lpcap -lcrypto  
gmake[1]: Leaving directory `/home/jbut/Development/test/build/src'
gmake[1]: Entering directory `/home/jbut/Development/test/build/scripts'
gmake[1]: Nothing to be done for `all'.
gmake[1]: Leaving directory `/home/jbut/Development/test/build/scripts'

Distributing the Project

You should distribute your project with a prebuilt configure script, not every platform will have autoconf installed.

Examples

The pkthisto and netsniff projects provide a NAM based build environment. They can be downloaded as samples of how to use NAM in a real project.

Download NAM

The NAM set of files is maintained and made available here.

Conclusion

While autoconf can be used to facilitate the building of Makefiles for building platform independent software, the use of automake leaves a result that appears unprofessional and is difficult to understand. This precipitated the development of Not AutoMake (NAM). NAM allows the use of autoconf without automake, with simple specification input Makefile.in files, and resultant Makefiles that are both easy to read and follow, while producing a much nicer output during the build process.


 

Last Updated: Friday 15-Apr-2005 16:41:21 AEST | Maintained by: Jason But (jbut@swin.edu.au) | Authorised by: Grenville Armitage ( garmitage@swin.edu.au)