***********************************************************************
*                                                                     *
*                     GNU autotools tutorial                          * 
*                     ======================                          *
*                                                                     *
*                 Copyright (C) 2004-2005 Holger Macht                *
*                                                                     *
* Permission is granted to copy, distribute and/or modify this        *
* document under the terms of the GNU Free Documentation License,     *
* Version 1.2 or any later version published by the  Free Software    *
* Foundation; with no Invariant Sections, no Front-Cover Texts, and   *
* no Back-Cover Texts. A copy of the license is included in the       *
* section entitled  "GNU Free Documentation License".                 *
*                                                                     *
***********************************************************************

=================
Table of contents
=================

1) Introduction

2) Autoconf - Part 1

3) Autoconf - Part 2

4) Configuration header

5) Autoheader

6) Writing macros - Part 1

7) Writing macros - Part 2

8) GNU make - Part 1

9) GNU make - Part 2

10) Automake - Part 1

11) Automake - Part 2


===============
1) Introduction
===============

The following chapters will explain the basic concepts of the GNU
autotools. This includes simple autoconf scripts, configuration headers
and a quick guide for writing own testmacros. Afterwards, there will be an
explanation about GNU make which is needed to understand the next chapters
about automake.

This tutorial can only be considered as a draft. So don't expect too much.

The chapters are divided into directories. Each chapter has its own
directory and explains a small part. For every chapter, create a new
directory and follow the tutorial. The complete directories - how they
should look like in the end - are provided as bzipped tarball:
http://www.homac.de/files/autotools_tut.tar.bz2 .

Just doing the steps explained should actually be enough, but if something
does not work the provided files can be used to compare. The directory
which is suitable for each chapter is indicated with 'dir:
' directly below the title. When doing the tutorial one can
use this directory names for testing.


====================
2) Autoconf - Part 1
====================

dir: autoconf1

Autoconf is the most used tool for checking different systems of their
capabilities. So it can be made easy to compile a software package on
different architectures. Autoconf 'configures' a sourcecode package
according to the results of the system tests.

The output file autoconf creates is a shell script named configure which
tests for compilers, libraries or header files.

At first you have to write configure.ac. You will also often find the
name configure.in, but the official autoconf manual sais that this name
should not be used anymore.

Based upon this configure.ac, autoconf generates the configure script.

The basic layout of configure.ac (configure.in) in looks like that:

    AC_PREREQ(autoconf_version)

This line tells autoconf that at least version autoconf_version is
needed. If this preconditon is not given, an error message is printed and
configure exits. This macro is not essential but should be used everytime.

    AC_INIT(packagename , version , [email for bug-reports] )

This macro is absolutely required. It performs a lot of initializations
and defines the name of the package, its version number and the e-mail
where bug-reports (optional) should go to. An optional fourth argument is
the tar-name of the package. The [, ] characters are quotes like " in
C++.

    AC_CONFIG_SRCDIR([some file in the source directory])

This macro simply checks for the existance of a file in the source
directory. This is only a savety check but should also be used everytime.

Now, there would be the several checks about which are axplained later.
At last, there must be the following macro call:

    AC_OUTPUT([filename])

This defines the filename configure should create when all tests passed
and no error occured (usual Makefile). This only makes sence in
conjunction with automake. So you can simply omit the parameter when only
using autoconf.

Now let's come to a simple example. Therefore, we will check if a simple
c++ program can be compiled on the system we use. It is called hello.cpp:

    #include 

    using namespace std;

    int main()
    {
        cout << "Hallo, Welt!\n";
        return 0;
    }

We will go through configure.ac step by step:

    AC_PREREQ(2.59)

Like mentioned above, this line sais that at least autoconf version 2.59
has to be available.

    AC_INIT( greetings , 0.1 , hmacht@suse.de )

Our program will be called "greetings", the version number is 0.1 and
bug-reports should go to hmacht@suse.de.

    AC_CONFIG_SRCDIR([hello.cpp])

We check for the existance of hello.cpp and therefore if the source
directory exists.

Now there will be the program checks. For now, we will only use the
already available macros. It is also possible to write own macros. It
is obvious that our program will need a c++ compiler, so we check for one
with the following macro.

    AC_PROG_CXX

This macro call checks if a compatible c++ compiler is available.

This should be enough for the moment. Finally we need the macro

    AC_OUTPUT

The complete configure.ac file looks like that:

    AC_PREREQ(2.59)
    AC_INIT( greetings , 0.1 , hmacht@suse.de )
    AC_CONFIG_SRCDIR([hello.cpp])
    AC_PROG_CXX
    AC_OUTPUT


Now you can run autoconf. This results in a configure script and an
additional directory autom4te.cache. Run ./configure and you will see if
your system is able to compile a simple c++ program.


====================
3) Autoconf - Part 2
====================

dir: autoconf2

Now it is time to have a closer look at the features autoconf provides.
For that we will check if a small QT program can be compiled. The first
lines of configure.ac remain the same:

    AC_PREREQ(2.59)
    AC_INIT( qttestapp , 0.1 , hmacht@suse.de )
    AC_CONFIG_SRCDIR([hello.cpp])

The only changed thing is the name if the application (qttestapp). After
these in some manner standard lines, the checks follow:

    AC_PROG_CXX

Check for a c++ compiler.

    AC_CHECK_PROG(QMAKE, qmake, [/usr/lib/qt3/bin/qmake],
        [qmake not found],[$QTDIR/bin])

This is something new. AC_CHECK_PROG checks if the program 'qmake'
(second parameter) exists in the directory given by the environment
variable $PATH. The first parameter is the variable which will hold the
result of the ckeck. The third parameter contains the string which will
become the value of QMAKE if the prog was found. The fourth will become
the value of QMAKE if the prog was not found.

    AC_CHECK_PROG(MOC, moc, [$QTDIR/moc], [moc not found],[$QTDIR/bin])

That is nearly the same except that it is checked for 'moc'.

The following lines check for some libraries:

    AC_PATH_X

Test if the development labraries of the X-Server can be found.

Now, we define some shell variables especially for the qt-needed
directories and libraries.

    qtdir=${QTDIR}
    qt_includes=$qtdir/include
    qt_libraries=$qtdir/lib
    LDFLAGS="$LDFLAGS -L$qt_libraries"

The last line adds the path for the qt-libraries to the variable LDFLAGS
which will be appended to the compiler command at compile time.

    AC_CHECK_LIB(qt,main,,AC_MSG_ERROR(Cannot find required library Qt.))

AC_CHECK_LIB checks for the library qt (-lqt). This is done by linking a
testprogram with the library qt to get the function 'main' (second
argument). The third argument, which is left empty in this case, is a
list of shell command or macros which should be executed if the
function/library was found/is usable. If it is omited, the library
(-lqt) is prepended to the variable $LIBS. The next argument specifies
the actions if the library could not be found. In this case, the macro
AC_MSG_ERROR is used to print an error message and to exit.

    AC_SUBST(qt_includes)
    AC_SUBST(qt_libraries)

This two lines mean that AC_OUTPUT should substitude every occurrence of
@qt_includes@ in inputfiles with the values $qt_include and $qt_libraries
have at the time AC_OUTPUT is called.

    AC_OUTPUT

After all, AC_OUTPUT is called. So the complete configure.ac looks like
that:

    AC_PREREQ(2.59)
    AC_INIT( qttestapp , 0.1 , hmacht@suse.de )
    AC_CONFIG_SRCDIR([hello.cpp])

    # Checks for programs.
    AC_PROG_CXX
    AC_CHECK_PROG(QMAKE, qmake, [/usr/lib/qt3/bin/qmake], [qmake not found],[$QTDIR/bin])
    AC_CHECK_PROG(MOC, moc, [$QTDIR/moc], [moc not found],[$QTDIR/bin])

    # Checks for libraries.
    AC_PATH_X
    qtdir=${QTDIR}
    qt_includes=$qtdir/include
    qt_libraries=$qtdir/lib
    LDFLAGS="$LDFLAGS -L$qt_libraries"
    AC_CHECK_LIB(qt,main,,AC_MSG_ERROR(Cannot find required library Qt.))

    # substitutions
    AC_SUBST(qt_includes)
    AC_SUBST(qt_libraries)

    AC_OUTPUT

Run autoconf and ./configure and you will have a simple but working test
if a qt-application can be compiled on a specific system. The lines
beginning with # are comments and are not considered by autoconf.

There are many more checks provided by autoconf. Refer to the autoconf
manual on
http://www.gnu.org/software/autoconf/manual/autoconf-2.57/autoconf.html
for a complete list.


=======================
4) Configuration header
=======================

dir: config_header

It is also possible to use a configuration file for autoconf. That is
helpful if you define a lot of preprocessor symbols which would be usally
appended to the commandline using the '-D' option. When using a
configuration header you do not use this '-D' options at compile time, but
you can include all symbols in an extra header. Afterwards you can insert
this headerfile into your sourcecode. That makes the reading of the
anyway relative long 'compile lines' much more easier. Also, on some
systems the command line can become too long for the operating system to
handle. You also have the possibility to take actions regarding to the
results of configure in your sourcecode.

Taking action in reference to system checks, for instance, is a common
practise when developing qt/kde application. Some applications offer the
possibility to decide whether to compile with or without kde support.

So for creating such a configuration header you have to insert
AC_CONFIG_HEADERS into your configure.ac. The argument passed to this
macro is the filename of the header and should usually be called conf.h.

For instance, if you check for a header file (e.g. AC_CHECK_UNISTD) in
configure.ac, and the system has this header,  configure will #define
HAVE_UNISTD_H to 1. For this to work you have to tell ./configure whose
symbols it should check. This is done by creating a conf.h.in with for
instance the following lines:

    /* Define as 1 if you have unistd.h.  */
    #undef HAVE_UNISTD_H

configure will now #define HAVE_UNISTD_H to 1 if the header file is
present on this system otherwise #undef HAVE_UNISTD_H is used.

So the files look like that:

    configure.ac:

        AC_PREREQ(2.59)
        AC_INIT( greetings , 0.1 , hmacht@suse.de )
        AC_CONFIG_HEADERS([conf.h])
        AC_CONFIG_SRCDIR([hello.cpp])
        AC_PROG_CXX
        AC_CHECK_HEADERS([unistd.h])
        AC_OUTPUT

Additionally to the macro call AC_CONFIG_HEADERS we check for the header
unistd.h.

Now run autoconf and you will see that conf.h contains (hopefully) the
following lines:

    /* conf.h.  Generated by configure.  */
    /* Define as 1 if you have unistd.h.  */
    #define HAVE_UNISTD_H 1

You can now #include  on top of the source file hello.cpp and
test for preprocessor conditionals:

    #include 
    #include 

    using namespace std;

    int main()
    {
        #ifdef HAVE_UNISTD_H
        cout << "Great! We found a unistd.h!\n";
        #else
        cout << "No unistd.h present!\n";
        #endif

        cout << "Hallo, Welt!\n";
        return 0;
    }

Compile the program with 'g++ -I. hello.cpp -o greetings'. The '-I.'
parameter is necessary because we have included conf.h with the <>
characters and so we have to add the current working directory (where
conf.h can be found) to our includepath. This should be done everytime so
that conf.h can be found from everywhere. Run ./greetings and you will
know if your system is aware of an unistd.h.


=============
5) Autoheader
=============

dir: autoheader

Instead of writing conf.h.in yourself, you can use the tool autoheader
which is much more comfortable.

For this, after running autoconf you simply can execute autoheader and
this results in a suitable conf.h.in. Autoheader takes all occurrances of
AC_DEFINE in configure.ac and inserts it into conf.h.in. By default this
are e.g. the package name, the bugreport e-mail and the version number.
So you can have for example additionally this line:

    AC_DEFINE(MYVAR,["hello trainees"],[My personal example variable])

Run autoconf, autoheader and ./configure. You will find lines in conf.h.in saying the
following:

    /* My personal example variable */
    #undef MYVAR

Compile the following program ( g++ -I. hello.cpp -o greetings ):

    #include 
    #include 

    using namespace std;

    int main()
    {
        cout << "\nDieses Programm heisst "<< PACKAGE_NAME << "\n";
        cout << "Die Versionsnummer ist " << PACKAGE_VERSION << "\n";
        cout << "MYVAR hat den Wert: " << MYVAR <<"\n\n";
    }

The output should look like this:

    Dieses Programm heisst greetings
    Die Versionsnummer ist 0.1
    MYVAR hat den Wert: hello trainees


==========================
6) Writing macros - Part 1
==========================

dir: macrowriting1

In some special cases it is neccessary to write own macros which check
for specific conditions. The following chapter will explain how this is
done. So there will be a macro which checks for an environment variable.
In the simpliest case, configure.ac looks like that:

    AC_PREREQ(2.59)
    AC_INIT( greetings , 0.1 , hmacht@suse.de )
    HM_CHECK_ENVVAR([MYVAR])
    AC_OUTPUT

The new macro is called HM_CHECK_ENVVAR and checks if a specific
environment variable is set. The given parameter is the name of the
variable.

The macro for defining own macros is called AC_DEFUN. Its first argument
is the name of the new macro and the second is the body (code).

You have to create a file acinclude.m4 which will hold this macro
definition. The first lines are a comment with the prototype. Then, the
definition follows:

    # HM_CHECK_ENVVAR([ENVVAR])
    # --------------------------------------
    AC_DEFUN([HM_CHECK_ENVVAR],
    [

The new macro will be called HM_CHECK_ENVVAR (first argument). The second
argument is the body and begins with this line:

    AC_MSG_CHECKING([$1])

This macro is used to print a message saying for which condition
configure checks at the moment. The first given argument is refered to by
$1 which is in our case 'MYVAR' from configure.ac.

    if test x"$$1" = x ; then
        AC_MSG_ERROR([ $1 must be set])
    fi

These lines are simple shell scripting. They test if there is an
environment variable with the name $1 (first argument) and if it is not
empty. If it is empty an error message ($1 must be set) is printed and
configure exits.

    AC_MSG_RESULT([$$1])

The result - and therefore the value of $1 - of the test is printed.

    ])

Close the macro definition.

In completeness, acinclude.m4 looks like that:

    # HM_CHECK_ENVVAR([ENVVAR])
    # --------------------------------------
    AC_DEFUN([HM_CHECK_ENVVAR],
    [
    AC_MSG_CHECKING([$1])

    if test x"$$1" = x ; then
        AC_MSG_ERROR([ $1 must be set])
    fi

    AC_MSG_RESULT([$$1])
    ])


In order for autoconf/configure to find this fresh new macro you have to
call aclocal. This copies all new macros from acinclude.m4 to aclocal.m4.
Run autoconf. Now you can test whether the macro works. First, set MYVAR
to some value:

    export MYVAR="Hallo, Welt!"

Now run configure and you should get the following output:

    checking MYVAR... Hallo, Welt
    configure: creating ./config.status

Now unset MYVAR:

    unset MYVAR

The output:

    checking MYVAR... configure: error:  MYVAR must be set


It works!!!!


==========================
7) Writing macros - Part 2
==========================

dir: macrowriting2

The old (HM_CHECK_ENVVAR) macro remains unchanged in acinclude.m4. Below,
we add the following new macro definition:


    # HM_CHECK_QTVERSION
    # --------------------------------------
    AC_DEFUN([HM_CHECK_QTVERSION],
    [

    AC_MSG_CHECKING([qt-version])

    if test x$QTDIR = x ;then
        AC_MSG_ERROR([QTDIR is not set])
    fi

    QT_VERSION_LINE="`grep \"#define QT_VERSION_STR\"
        $QTDIR/include/qglobal.h 2>/dev/null`"
    QT_VERSION=`echo $QT_VERSION_LINE | cut -d' ' -f3 | sed -e 's/"//g'`

    if test x$QT_VERSION = x ;then
        AC_MSG_ERROR([qglobal.h could not be found in $QTDIR/include/.
            Please set \$QTDIR correctly])
    fi

    AC_MSG_RESULT([$QT_VERSION])

])

We are checking for the qtversion (HM_CHECK_QTVERSION). If $QTDIR is not
set, exit with an error message. Now, the version is grepped out of
$QTDIR/include/qglobal.h. Afterwards, if the variable holding the version
($QT_VERSION) is empty, exit also.

configure.ac with both new macro calls:

    AC_PREREQ(2.59)
    AC_INIT( greetings , 0.1 , hmacht@suse.de )
    HM_CHECK_ENVVAR([MYVAR])
    HM_CHECK_QTVERSION
    AC_OUTPUT

Yuu will see if there is a version of QT installed, and what version
number it has.


====================
8) GNU make - Part 1
====================

dir: make1

Now I want to show the basic concept of make.

Example program:

main.cpp:

    #include "printing.h"

    int main()
    {
        printStr("Hello, World!");
        return 0;
    }

printing.cpp:

    #include "printing.h"

    void printStr(char *text)
    {
        cout << text << "\n";
    }

printing.h:

    #include 

    using namespace std;

    void printStr(char *);


Usally translated with:

    g++ main.cpp printing.cpp -o greetings

When making changes in one of the three files you have to translate all
the three files again. That does not matter much with such a small
program, but with a big project it takes a long time to compile
everything. So you have the possibility to compile the files
independently into object files. Afterwards you can link the three files
together. So you can execute the following:

    g++ -c main.cpp
    g++ -c printing.cpp

This results in two object files called main.o and printing.o.
You can link these files together to get a binary file.

    g++ main.o printing.o -o greetings

When changing one file, for instance main.cpp, you only have to
translate main.cpp into an object file and then link the files together.
This saves a lot of compile time in big projects. Also the command line
can get quite long when having a lot of source files. So you can
configure make to do the job for you. It looks at the last time when a
sourcefile was modified and so decides whether it has to be recompiled.
So you only have to type make and you will get the executable.

At first you have to write a Makefile. It mainly consists of targets.
Targets can be executables, object files or even actions (like clean up
directory). The following shape will be used everytime:

target : prerequisites
    command

Notice that there _MUST_ be a real tab before the command. The target
specifies what should be built. The prerequisites are something which are
needed to build the target and the result of the command is the target.
So our first line of the Makefile looks like that:

    greetings : main.o printing.o
        g++ -o greetings main.o printing.o

greetings is our first target. The first target is executed by make
everytime you only type the single word make at the command prompt. As an
alternative you can also type make greetings. main.o and printing.o are
needed to built greetings and the command beginning with g++ produces the
target. But that is not everything we have to do. We also have to specify
how the object files are created. This are the next lines:

    main.o : main.cpp printing.h
        g++ -c main.cpp

    printing.o : printing.cpp printing.h
        g++ -c printing.cpp

There are two new targets. main.o depends on main.cpp and printing.h.
main.o is build with the command g++ -c main.cpp which results in the
target.
printing.o depends on printing.cpp and printing.h. The command is analog
to the one above.

The last target is an action called clean which cleans up the
sourcedirectory removing all object files.

    clean :
        rm main.o printing.o

The target clean has no prerequisites because it depends on nothing else.
So 'make clean' on the command line results in removing all mentioned
object files (rm main.o printing.o).

The whole Makefile:

    greetings : main.o printing.o
        g++ -o greetings main.o printing.o

    main.o : main.cpp printing.h
        g++ -c main.cpp

    printing.o : printing.cpp printing.h
        g++ -c printing.cpp

    clean :
        rm main.o printing.o


Now simply type make and greetings will be build. Modifying main.cpp
results in only rebuilding main.cpp and linking main.o and printing.o.
Changing printing.cpp results in compiling printing.cpp into an object
file and afterwards linking. When you edit printing.h both main.cpp and
printing.cpp will be recompiled because main.cpp and printing.cpp depend
on this header file.


====================
9) GNU make - Part 2
====================

dir: make2

It is commaon practise to use variables in Makefiles. So at first we
define a variable holding our object files. The big advantage is that
when the names of the object files change or there are new ones, you only
have to change this one variable. Change your Makefile like that:

    objects = main.o printing.o

    greetings : $(objects)
        g++ -o hi $(objects)

    main.o : main.cpp printing.h
        g++ -c main.cpp

    printing.o : printing.cpp printing.h
        g++ -c printing.cpp

    .PHONY : clean
    clean :
        rm $(objects)

So the expression $(objects) is replaced with all the object files we
have. We also added the line '.PHONY : clean' which tells make that clean
is no file to create but rather an action. This prevents conflicts when
there will ever be a file called clean in the directory.

With a Phony target, clean will be executed everytime because it has no
prerequisites. So make will not decide that it is up-to-date and
therefore not to rebuild it.


=====================
10) Automake - Part 1
=====================

dir: automake1

Automake automates the writing of Makefiles.

For using automake you have to write a file called Makefile.am. This file
will be used by automake to create Makefile.in. Based on this file
./configure (autoconf) will create the 'real' Makefile.

But at first you have to update your configure.ac. In the following
examples we return to the first example from autoconf. So until now,
configure.ac looks like that:

    AC_PREREQ(2.59)
    AC_INIT( greetings , 0.1 , hmacht@suse.de )
    AC_CONFIG_SRCDIR([hello.cpp])
    AC_PROG_CXX
    AC_OUTPUT

We have to add a line AM_INIT_AUTOMAKE directly below AC_INIT. This
initializes the automake process.

It is also very helpful to check for an install program which will
install the resulting binary, documentation or datafiles into its
corresponding directories. So we add the line AC_PROG_INSTALL below
AC_PROG_CXX. For this to work, you have to distribute your own install
program, otherwise automake will complain about that. You can copy the
default install-sh from /usr/share/automake-1.8/ to the project
directory. If you have a suitable install programm in your $PATH,
automake will use this one.

Additionally we add a macro call for checking for a default C compiler.
So here is our new configure.ac:

    AC_PREREQ(2.59)
    AC_INIT( greetings , 0.1 , hmacht@suse.de )
    AM_INIT_AUTOMAKE
    AC_CONFIG_SRCDIR([hello.cpp])
    AC_PROG_CC
    AC_PROG_CXX
    AC_PROG_INSTALL
    AC_OUTPUT(Makefile)

Now that we are using automake we have also to define an output file.
This is done by giving an additional argument to AC_OUTPUT
(AC_OUTPUT(Makefile)).

Now we have a look on Makefile.am. At first we add an option:

    AUTOMAKE_OPTIONS = foreign

This tells automake that not all common files like INSTALL, README,
AUTHORS or COPYRIGHT are needed. This is only used here and should be
avoided in real projects.

Now the filename of the binary/output program is defined:

    bin_PROGRAMS = greetings

If there are more output files, simply add them whitespace seperated. The
prefix 'bin_' means that the executables should go to bindir (usual
/usr/bin). If it sais sbin_PROGRAMS, then the files would be installed in
/usr/sbin.

    greetings_SOURCES = hello.cpp

The sourcefiles are mentioned. The variable is prefixed with the value of
bin_PROGRAMS (greetings). So Makefile.am looks like that:

    AUTOMAKE_OPTIONS = foreign
    bin_PROGRAMS = greetings
    greetings_SOURCES = hello.cpp

That's it. You have to run aclocal first, otherwise autoconf will
recognise AM_INIT_AUTOMAKE and will complain about an unknown macro.
Aclocal will add the automake macros to the list of known macros for
autoconf. Now run autoconf and afterwards automake -a. The argument '-a'
will add all missing files to the directory.

Again you can run ./configure which creates a Makefile. Now you can call
make to compile the program and make clean to remove the object files.


=====================
11) Automake - Part 2
=====================

dir: automake2

Now let's come to a more complex example. The sources are in an extra
directory named 'src'. Additionally, there will be a main.cpp, a
printing.cpp and the corresponding header file printing.h. They look like
that:

    src/main.cpp:

        #include "printing.h"

        int main()
        {
            printStr("Hello, World!");
            return 0;
        }

    src/printing.cpp:

       #include "printing.h"

        void printStr(char *text)
        {
            cout << text << "\n";
        }

    src/printing.h:

        #include 

        using namespace std;

        void printStr(char *);

In this example, main.cpp uses a function (printStr) which is defined in
printing.cpp. The prototype is in printing.h. The function simply prints
a string to stdout.

As you can see, main.cpp depends on printing.h. So when building
the binary and there where changes in printing.h then main.cpp and
printing.cpp have to be rebuild.

configure.ac has to be adjusted:

    AC_PREREQ(2.59)
    AC_INIT( greetings , 0.1 , hmacht@suse.de )
    AM_INIT_AUTOMAKE
    AC_CONFIG_SRCDIR([hello.cpp])
    AC_PROG_CC
    AC_PROG_CXX
    AC_OUTPUT(Makefile src/Makefile)

We added one more file to AC_OUTPUT, that is to say the Makefile in the
src-subdirectory.

The top-level Makefile.am contains only two lines:

    AUTOMAKE_OPTIONS = foreign
    SUBDIRS = src

This tells automake to look in all mentioned subdirs (whitespace
seperated) for further occurrances of Makefile.am's.

The src/Makefile.am looks like that:

    bin_PROGRAMS = greetings
    greetings_SOURCES = hello.cpp printing.cpp printing.h

The usual command sequenze:

    aclocal
    autoconf
    automake -a

Now you can run ./configure and make and the program will be built. You
also can try the dependencies. Modify printing.h and both printing.cpp
and main.cpp will be rebuild and linked together. Only modifying main.cpp
results in only rebuilding main.cpp and then linking together. So you
have the same result then writing the Makefile on your own.