From 32a1ea434d0dd0bac45ee849b836df11470757e8 Mon Sep 17 00:00:00 2001
From: Manuel Traut <manut@linutronix.de>
Date: Thu, 19 May 2016 16:13:03 +0200
Subject: first version of my-way to teach autotools

Signed-off-by: Manuel Traut <manut@linutronix.de>
---
 distribution/autotools/autotools.tex | 984 +++++++++++++++++++++++++++++++----
 1 file changed, 878 insertions(+), 106 deletions(-)

(limited to 'distribution/autotools/autotools.tex')

diff --git a/distribution/autotools/autotools.tex b/distribution/autotools/autotools.tex
index 68a6fe2..30791d4 100644
--- a/distribution/autotools/autotools.tex
+++ b/distribution/autotools/autotools.tex
@@ -1,208 +1,980 @@
-\subsection{Standalone Application}
+\subsection{About autotools}
+
 \begin{frame}[fragile]
-  \lstinputlisting{standalone/hello-orig.c}
+\frametitle{Autotools, aka GNU Build System}
+\begin{itemize}
+\item make software (builds) portable
+\item well-known format for distribution
+\item ease integration in distributions and build-systems
+\end{itemize}
 \end{frame}
 
-\begin{frame}
-\frametitle{Minimalkonfiguration}
+\begin{frame}[fragile]
+\frametitle{first attemp, keep it simple}
+\begin{verbatim}
+% cd
+% mkdir hello
+% cd hello
+\end{verbatim}
+
+'hello.c':
+\begin{verbatim}
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	printf("Hello World\n");
+	return 0;
+}
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{track changes with git}
+\begin{verbatim}
+% git init .
+% git add hello.c
+% git commit -sa
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{Why not just 'make'? \#1}
+\begin{verbatim}
+hello:
+
+install:
+	install -d /usr/bin
+	install hello /usr/bin/hello
+\end{verbatim}
+
+\begin{verbatim}
+% git add Makefile
+% git commit -sa
+\end{verbatim}
+what if the user doesn't want to install into /usr/bin?
+
+edit the Makefile? introduce variables, .. :-/
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{Why not just 'make'? \#2}
+use a template 'Makefile.in'
+\begin{verbatim}
+hello:
+
+install:
+	install -d @exec_prefix@
+	install hello @exec_prefix@/hello
+\end{verbatim}
+and run './configure --exec-prefix=/opt/bin'
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{write configure by you own?}
+\dots or use autoconf, it generates one for you, based on a configure.ac file.
+
+'autoscan' can be used to generate an initial version:
+\begin{verbatim}
+% autoscan
+% mv configure.scan configure.ac
+% rm autoscan.log
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{configure.ac}
+replace FULL-PACKAGE-NAME, VERSION and BUG-REPORT-ADDRESS with sane values
+
+remove temporarily unneeded calls
+\begin{verbatim}
+AC_PREREQ([2.69])
+AC_INIT([hello], [1.0], [manut@linutronix.de])
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+\end{verbatim}
+update git
+\begin{verbatim}
+git rm Makefile
+git add Makefile.in
+git add configure.ac
+git commit -sa
+\end{verbatim}
+then run the following commands to generate the configure script
+\begin{verbatim}
+% autoconf
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{generate the Makefile}
+\begin{verbatim}
+% ./configure --exec-prefix=/opt/bin
+\end{verbatim}
+the generated Makefile:
+\begin{verbatim}
+hello:
+
+install:
+	install -d /opt/bin/hello
+	install hello /opt/bin/hello
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{config.h \#1}
+generate a 'config.h' that should be included on top of the other includes in
+all files.
+
+Insert the following m4 function call in 'configure.ac'
+\begin{verbatim}
+AC_CONFIG_HEADERS([config.h])
+\end{verbatim}
+
+and run
+\begin{verbatim}
+% autoreconf -sif
+\end{verbatim}
+to regenerate the 'configure' script and create a 'config.h.in' template.
+
+Then run
+\begin{verbatim}
+% ./configure --exec-prefix=/opt/bin
+\end{verbatim}
+again to generate the 'Makefile' and 'config.h'
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{config.h \#2}
+include 'config.h' in main.c and use the PACKAGE\_STRING define:
+\begin{verbatim}
+#include "config.h"
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	printf(PACKAGE_STRING "\n\n")
+	printf("Hello World\n");
+	return 0;
+}
+\end{verbatim}
+\begin{verbatim}
+% make
+cc     hello.c   -o hello
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{reasons for automake}
+rebuild the program:
+\begin{verbatim}
+% make
+make: 'hello' is up to date.
+% make clean
+make: *** No rule to make target 'clean'.  Stop.
+% git status
+    Makefile
+    autom4te.cache
+    ...
+\end{verbatim}
+write 'clean', 'distclean', 'maintainerclean' targets?
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{automake}
+describe input and output files in 'Makefile.am':
+\begin{verbatim}
+bin_PROGRAMS = hello
+hello_SOURCES = hello.c
+\end{verbatim}
+add invocation of 'automake' to 'configure.ac':
+\begin{verbatim}
+AC_PREREQ([2.69])
+AC_INIT([hello], [1.0], [manut@linutronix.de])
+AM_INIT_AUTOMAKE
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{Excurs: GNU project layout}
+\begin{verbatim}
+autoreconf -sif
+configure.ac:6: installing './install-sh'
+configure.ac:6: installing './missing'
+Makefile.am: installing './INSTALL'
+Makefile.am: error: required file './NEWS' not found
+Makefile.am: error: required file './README' not found
+Makefile.am: error: required file './AUTHORS' not found
+Makefile.am: error: required file './ChangeLog' not found
+Makefile.am: installing './COPYING' using GNU General Public License v3 file
+Makefile.am:     Consider adding the COPYING file to the version control system
+Makefile.am:     for your code, to avoid questions about which license your project uses
+Makefile.am: installing './depcomp'
+/usr/share/automake-1.15/am/depend2.am: error: am__fastdepCC does not appear in AM_CONDITIONAL
+/usr/share/automake-1.15/am/depend2.am:   The usual way to define 'am__fastdepCC' is to add 'AC_PROG_CC'
+/usr/share/automake-1.15/am/depend2.am:   to 'configure.ac' and run 'aclocal' and 'autoconf' again
+/usr/share/automake-1.15/am/depend2.am: error: AMDEP does not appear in AM_CONDITIONAL
+/usr/share/automake-1.15/am/depend2.am:   The usual way to define 'AMDEP' is to add one of the compiler tests
+/usr/share/automake-1.15/am/depend2.am:     AC_PROG_CC, AC_PROG_CXX, AC_PROG_OBJC, AC_PROG_OBJCXX,
+/usr/share/automake-1.15/am/depend2.am:     AM_PROG_AS, AM_PROG_GCJ, AM_PROG_UPC
+/usr/share/automake-1.15/am/depend2.am:   to 'configure.ac' and run 'aclocal' and 'autoconf' again
+Makefile.am: error: C source seen but 'CC' is undefined
+Makefile.am:   The usual way to define 'CC' is to add 'AC_PROG_CC'
+Makefile.am:   to 'configure.ac' and run 'autoconf' again.
+autoreconf: automake failed with exit status: 1
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{Excurs: GNU project layout}
+'automake' generated some templates:
 \begin{itemize}
-\item README
-\item NEWS
 \item COPYING
-\item AUTHORS
-\item autogen.sh
-\item configure.ac
-\item Makefile.am
+\item INSTALL
 \end{itemize}
+customize them if needed.
+
+Some other files are mandatory, create them:
+\begin{verbatim}
+% touch NEWS README AUTHORS ChangeLog
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{README}
-  \lstinputlisting[lastline=14]{standalone/README}
+\frametitle{remember 2nd part of the errors}
+\begin{verbatim}
+% autoreconf -sif
+/usr/share/automake-1.15/am/depend2.am: error: am__fastdepCC does not appear in AM_CONDITIONAL
+/usr/share/automake-1.15/am/depend2.am:   The usual way to define 'am__fastdepCC' is to add 'AC_PROG_CC'
+/usr/share/automake-1.15/am/depend2.am:   to 'configure.ac' and run 'aclocal' and 'autoconf' again
+/usr/share/automake-1.15/am/depend2.am: error: AMDEP does not appear in AM_CONDITIONAL
+/usr/share/automake-1.15/am/depend2.am:   The usual way to define 'AMDEP' is to add one of the compiler tests
+/usr/share/automake-1.15/am/depend2.am:     AC_PROG_CC, AC_PROG_CXX, AC_PROG_OBJC, AC_PROG_OBJCXX,
+/usr/share/automake-1.15/am/depend2.am:     AM_PROG_AS, AM_PROG_GCJ, AM_PROG_UPC
+/usr/share/automake-1.15/am/depend2.am:   to 'configure.ac' and run 'aclocal' and 'autoconf' again
+Makefile.am: error: C source seen but 'CC' is undefined
+Makefile.am:   The usual way to define 'CC' is to add 'AC_PROG_CC'
+Makefile.am:   to 'configure.ac' and run 'autoconf' again.
+autoreconf: automake failed with exit status: 1
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{README - (f.)}
-  \lstinputlisting[firstline=15]{standalone/README}
+\frametitle{which compiler should be used?}
+to use autoconf to look for a C compiler add a function call to configure.ac:
+\begin{verbatim}
+AC_PREREQ([2.69])
+AC_INIT([hello], [1.0], [manut@linutronix.de])
+AM_INIT_AUTOMAKE
+AC_PROG_CC
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+\end{verbatim}
+rerun autoconf
+\begin{verbatim}
+% autoreconf -sif
+configure.ac:11: installing './compile'
+\end{verbatim}
+
+
+\begin{frame}[fragile]
+\frametitle{generate a Makefile}
+now a 'Makefile.in' that takes care on a lot of settings from './configure'
+was generated!
+\begin{verbatim}
+% ./configure
+% make
+make  all-am
+make[1]: Entering directory '/home/local/hello'
+gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.c
+mv -f .deps/hello.Tpo .deps/hello.Po
+gcc  -g -O2   -o hello hello.o
+make[1]: Leaving directory '/home/local/hello'
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{NEWS}
-  (Neuigkeiten oder leere Datei)
+\frametitle{update files in git}
+\begin{verbatim}
+% git rm --cached Makefile.in
+% git add NEWS README AUTHORS ChangeLog INSTALL COPYING
+% git add configure.ac Makefile.am
+% git commit -s
+\end{verbatim}
+create a .gitignore file for autogenerated files:
+\begin{verbatim}
+% git status -s | sed "s#?? ##" > .gitignore
+% git add .gitignore
+% git commit -s
+% git status
+On branch master
+nothing to commit, working directory clean
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{COPYING}
-  \lstinputlisting[lastline=10]{standalone/COPYING}
-  \dots
+\frametitle{extend configure.ac}
+with from autoscan suggested sanity checks for 'install' and the existence of
+a source file:
+\begin{verbatim}
+AC_PREREQ([2.69])
+AC_INIT([hello], [1.0], [manut@linutronix.de])
+AM_INIT_AUTOMAKE
+AC_CONFIG_SRCDIR([hello.c])
+AC_CONFIG_HEADERS([config.h])
+
+AC_PROG_CC
+AC_PROG_INSTALL
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+\end{verbatim}
+add the changes to git and rerun 'make'
+
+All needed steps are executed automatically!
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{AUTHORS}
-  \lstinputlisting{standalone/AUTHORS}
+\frametitle{useful make targets}
+\begin{block}{clean}
+\begin{description}
+\item[clean] deletes build outputs
+\item[distclean] removes files generated by './configure'
+\item[maintainer-clean] also deletes generated source code
+\end{description}
+\end{block}
+\begin{block}{install}
+\item[install] takes care on DESTDIR environment variable
+\end{block}
+\begin{block}{dist}
+\item[dist] generates a hello-1.0.tar.gz
+\item[distcheck] same as dist, but checks if the sw can be build with files
+	included in the tarball.
+\end{block}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{autogen.sh}
-  \lstinputlisting{standalone/autogen.sh}
+\frametitle{for your customers / distributions}
+\begin{verbatim}
+% tar xzf hello-1.0.tar.gz
+% cd hello-1.0
+% ./configure
+% make
+% sudo make install
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{configure.ac}
-  \lstinputlisting[lastline=12]{standalone/configure.ac}
+\frametitle{for developers}
+the typical workflow is
+\begin{verbatim}
+% git clone /home/devel/hello
+% cd hello
+% ./autogen.sh
+% ./configure
+% make
+% sudo make install
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{configure.ac (f.)}
-  \lstinputlisting[firstline=14, lastline=27]{standalone/configure.ac}
+\frametitle{autogen.sh}
+\dots so let's create the missing 'autogen.sh' script:
+\begin{verbatim}
+#!/bin/sh
+autoreconf -sif
+\end{verbatim}
+\begin{verbatim}
+% chmod +x autogen.sh
+% git add autogen.sh
+% git commit -s
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{configure.ac (f.)}
-  \lstinputlisting[firstline=28]{standalone/configure.ac}
+\frametitle{recap!}
+\begin{verbatim}
+% git clean -dxf
+% ls
+AUTHORS autogen.sh ChangeLog   configure.ac COPYING
+hello.c INSTALL    Makefile.am NEWS         README
+\end{verbatim}
+'AUTHORS, ChangeLog, COPYING, INSTALL, NEWS' and 'README' are
+mandatory text files, that describe the project.
+
+'autogen.sh' is an (optional) one-liner script
+
+'Makefile.am' are two lines and even simpler than the inital Makefile
+
+'configure.ac' a template can be generated with 'autoscan' at least
+'AM\_INIT\_AUTOMAKE' needs to be added manually.
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{Makefile.am}
-  \lstinputlisting[language=make, lastline=5]{standalone/Makefile.am}
+\frametitle{let's extend our software}
+\begin{enumerate}
+\item add gui.c and gui.h to display text with ncurses
+\item use pkg-config to specify compiler and linker options
+\item make the gui an optional component
+\end{enumerate}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{Makefile.am (f.)}
-  \lstinputlisting[language=make, firstline=6]{standalone/Makefile.am}
+\frametitle{gui.h}
+\begin{verbatim}
+int gui_init (void);
+void gui_free (void);
+int gui_display (char *msg);
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{hello.c}
-  \lstinputlisting{standalone/hello.c}
+\frametitle{gui.c}
+\begin{verbatim}
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <curses.h>
+#include <errno.h>
+#include <string.h>
+#include "gui.h"
+
+static WINDOW *mainwin;
+
+int gui_init (void) {
+	mainwin = initscr ();
+	if (!mainwin) return -ENOMEM;
+	return 0;
+}
+
+void gui_free (void) {
+	delwin (mainwin); endwin (); refresh ();
+}
+
+int gui_display (char *msg) {
+	mvaddstr (strlen (msg), 33, msg); refresh ();
+}
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{Erstellen der Applikation}
-  \begin{lstlisting}
-    # Erstellen der zu generierenden Dateien
-    ./autogen.sh
-    # Konfiguration der Applikation
-    ./configure
-    # Bauen der Applikation
-    make
-    # Testen der Quelltext-Distribution der Applikation
-    make distcheck
-    # Löschen aller generierten Dateien
-    make maintainer-clean
-  \end{lstlisting}
+\frametitle{hello.c}
+\begin{verbatim}
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include "gui.h"
+
+int main (int argc, char **argv)
+{
+	printf (PACKAGE_STRING "\n\n");
+	if (gui_init ()) {
+		perror("init gui failed:");
+		return -1;
+	}
+	gui_display ("Hello GUI!");
+	sleep (10);
+	gui_free ();
+	return ret;
+}
+\end{verbatim}
 \end{frame}
 
-\subsection{Libraries}
 \begin{frame}[fragile]
-  \lstinputlisting{library/hello.h}
-  \lstinputlisting{library/hello-orig.c}
+\frametitle{How to find compiler and linker options?}
+\begin{verbatim}
+% cat /usr/lib/x86_64-linux-gnu/pkgconfig/ncurses.pc
+prefix=/usr
+exec_prefix=${prefix}
+libdir=/usr/lib/x86_64-linux-gnu
+includedir=${prefix}/include
+abi_version=5
+major_version=6
+version=6.0.20160319
+
+Name: ncurses
+Description: ncurses 6.0 library
+Version: ${version}
+URL: http://invisible-island.net/ncurses
+Requires.private:
+Libs:  -L${libdir} -lncurses -ltinfo
+Libs.private:
+Cflags:  -D_GNU_SOURCE
+\end{verbatim}
 \end{frame}
 
-\begin{frame}
-\frametitle{Minimalkonfiguration}
+\begin{frame}[fragile]
+\frametitle{pkg-config}
+\dots more user friendly
+\begin{verbatim}
+% pkg-config --list-all | grep curses
+menu                             menu - ncurses 6.0 add-on library
+ncurses                          ncurses - ncurses 6.0 library
+...
+\end{verbatim}
+we use 'ncurses' so let's retrieve the compiler and linker options:
+\begin{verbatim}
+% pkg-config --cflags ncurses
+-D_GNU_SOURCE
+% pkg-config --libs ncurses
+-lncurses -ltinfo
+\end{verbatim}
+
+\begin{frame}[fragile]
+\frametitle{simply add the output to Makefile.am?}
+NO!! (but it will work on \_YOUR\_ machine)
+
+what needs to be done on your customers machine?
 \begin{itemize}
-\item README
-\item NEWS
-\item COPYING
-\item AUTHORS
-\item autogen.sh
-\item libhello.pc.in
-\item libhello-uninstalled.pc.in
-\item configure.ac
-\item Makefile.am
+\item check if the ncurses.pc file is availabe
+\item print an error if it's not installed
+\item maybe the headers and libs are installed in another path
+\item run pkg-config ncurses --libs/cflags and pass the output to Makefile.am
 \end{itemize}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{README}
-  \lstinputlisting[lastline=14]{library/README}
+\frametitle{autoconf and pkg-config}
+add a function call to configure.ac:
+\begin{verbatim}
+AC_PREREQ([2.69])
+AC_INIT([hello], [1.0], [manut@linutronix.de])
+AM_INIT_AUTOMAKE
+AC_USE_SYSTEM_EXTENSIONS
+AC_CONFIG_SRCDIR([hello.c])
+AC_CONFIG_HEADERS([config.h])
+
+AC_PROG_CC
+AC_PROG_INSTALL
+
+PKG_CHECK_MODULES([NCURSES], [ncurses])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+\end{verbatim}
+the first argument of PKG\_CHECK\_MODULES specifies a variable name, the
+second one the name of the package as displayed in pkg-config --list-all
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{if ncurses is not installed}
+./configure produces a human readable error message
+\begin{verbatim}
+% ./configure
+checking dependency style of gcc... (cached) gcc3
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for NCURSES... no
+configure: error: Package requirements (ncurses) were not met:
+
+No package 'ncurses' found
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables NCURSES_CFLAGS
+and NCURSES_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+Makefile:318: recipe for target 'config.status' failed
+make: *** [config.status] Error 1
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{final steps}
+add compile and linker options to Makefile.am:
+\begin{verbatim}
+bin_PROGRAMS = hello
+hello_SOURCES = hello.c gui.c gui.h
+hello_CFLAGS = @NCURSES_CFLAGS@
+hello_LDFLAGS = @NCURSES_LIBS@
+\end{verbatim}
+compile and test application:
+\begin{verbatim}
+% make
+...
+% ./hello
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{README - (f.)}
-  \lstinputlisting[firstline=15]{library/README}
+\frametitle{add changes to version control}
+\begin{verbatim}
+% git status
+...
+	gui.o
+	hello-gui.o
+	hello-hello.o
+...
+% echo '*.o' >> .gitignore
+% git add gui.c gui.h Makefile.am configure.ac hello.c .gitignore
+% git commit -s
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{NEWS}
-  (Neuigkeiten oder leere Datei)
+\frametitle{gui as optional feature}
+implement a './configure' switch '--with-gui'
+
+only if this parameter is given, the existence of ncurses.pc is tested
+and the gui components are build.
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{COPYING}
-  \lstinputlisting[lastline=10]{library/COPYING}
-  \dots
+\frametitle{implement configure switch}
+add this in 'configure.ac':
+\begin{verbatim}
+AC_ARG_WITH([gui], AS_HELP_STRING([--with-ncurses-gui], [Build with GUI]))
+if test "x$with_gui" = "xyes"; then
+  PKG_CHECK_MODULES([NCURSES], [ncurses],
+                    [AC_DEFINE([HAVE_GUI],[1],["ncurses available"])])
+fi
+AM_CONDITIONAL([HAVE_GUI], [test x$with_gui = xyes])
+\end{verbatim}
+\begin{description}
+\item[AC\_ARG\_WITH] adds the parameter to the configure script
+\item[PKG\_CHECK\_MODULES] is extended to define HAVE\_GUI in config.h
+\item[AM\_CONDITIONAL] exports a value as conditional to automake
+\end{description}
+\end{frame}
+
+\begin{frame}
+\frametitle{only build GUI if specified}
+'Makefile.am':
+\begin{verbatim}
+bin_PROGRAMS = hello
+hello_SOURCES = hello.c
+hello_CFLAGS = @NCURSES_CFLAGS@
+hello_LDFLAGS = @NCURSES_LIBS@
+if HAVE_GUI
+hello_SOURCES += gui.c gui.h
+endif
+\end{verbatim}
+\end{frame}
+
+\begin{frame}
+\frametitle{only call gui if compiled in}
+'hello.c':
+\begin{verbatim}
+...
+#ifdef HAVE_GUI
+#include "gui.h"
+#endif
+...
+#ifdef HAVE_GUI
+	ret = gui_init ();
+	if (ret) {
+		perror("init gui failed:");
+		return ret;
+	}
+
+	gui_display ("Hello GUI!");
+	sleep (10);
+
+	gui_free ();
+#endif
+...
+\end{verbatim}
+\end{frame}
+
+\begin{frame}
+\frametitle{build with and without gui}
+\begin{verbatim}
+% ./configure --with-gui
+...
+% make
+...
+gcc -DHAVE_CONFIG_H -I.    -D_GNU_SOURCE -g -O2 -MT hello-hello.o...
+mv -f .deps/hello-hello.Tpo .deps/hello-hello.Po
+gcc -DHAVE_CONFIG_H -I.    -D_GNU_SOURCE -g -O2 -MT hello-gui.o -...
+mv -f .deps/hello-gui.Tpo .deps/hello-gui.Po
+gcc -D_GNU_SOURCE -g -O2 -lncurses -ltinfo  -o hello hello-hello....
+...
+% ./configure
+...
+% make
+...
+gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT hello-hello.o -MD -MP -MF ...
+mv -f .deps/hello-hello.Tpo .deps/hello-hello.Po
+gcc  -g -O2   -o hello hello-hello.o
+...
+\end{verbatim}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{add changes to version control}
+\begin{verbatim}
+% git add Makefile.am configure.ac hello.c
+% git commit -s
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{AUTHORS}
-  \lstinputlisting{library/AUTHORS}
+\frametitle{increase program version}
+time to release a new version of our sw component, edit 'configure.ac':
+\begin{verbatim}
+AC_INIT([hello], [1.1], [manut@linutronix.de])
+\end{verbatim}
+add the version bump to vcs and release a tarball:
+\begin{verbatim}
+% git add configure.ac
+% git commit -s
+% make distcheck
+===========================================
+hello-1.1 archives ready for distribution:
+hello-1.1.tar.gz
+===========================================
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{autogen.sh}
-  \lstinputlisting{library/autogen.sh}
+\frametitle{libraries and libtoolize}
+add a versioned library called 'libfib' to the project
+\begin{verbatim}
+% mkdir fib
+% echo "SUBDIRS = fib" >> Makefile.am
+\end{verbatim}
+create an interface 'fib/fib.h':
+\begin{verbatim}
+unsigned int fibonacci (unsigned int fib);
+\end{verbatim}
+and 'fib/fib.c':
+\begin{verbatim}
+#include "fib.h"
+
+unsigned int fibonacci (unsigned int fib) {
+  if (fib == 0) return 0;
+  else if (fib == 1) return 1;
+  else return fibonacci (fib-1) + fibonacci (fib-2);
+}
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{libhello.pc.in}
-  \lstinputlisting{library/libhello.pc.in}
+\frametitle{Makefile.am for libfib}
+'fib/Makefile.am':
+\begin{verbatim}
+lib_LTLIBRARIES = libfib.la
+# 1) If the library source code has changed at all since the last update, then
+#    increment revision ("c:r:a" becomes "c:r+1:a").
+# 2) If any interfaces have been added, removed, or changed since the last
+#    update, increment current, and set revision to 0.
+# 3) If any interfaces have been added since the last public release,
+#    then increment age.
+# 4) If any interfaces have been removed or changed since the last public
+#    release, then set age to 0.
+libfib_la_LDFLAGS = -release @PACKAGE_VERSION@ -version-info 0:0:0
+libfib_la_SOURCES = fib.c
+include_HEADERS = fib.h
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{libhello-uninstalled.pc.in}
-  \lstinputlisting{library/libhello-uninstalled.pc.in}
+\frametitle{libtoolize and autoconf}
+add libtoolize and new Makefile to 'configure.ac':
+\begin{verbatim}
+...
+AC_USE_SYSTEM_EXTENSIONS
+LT_INIT
+AC_CONFIG_SRCDIR([hello.c])
+...
+AC_CONFIG_FILES([Makefile
+                 fib/Makefile])
+AC_OUTPUT
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{configure.ac}
-  \lstinputlisting[lastline=13]{library/configure.ac}
+\frametitle{that's it?}
+\dots no :( but autoreconf -sif is our friend!
+\begin{verbatim}
+% make
+ cd . && /bin/bash /home/local/hello/missing automake-1.15 --gnu
+configure.ac:5: error: required file './config.guess' not found
+configure.ac:5:   'automake --add-missing' can install 'config.guess'
+configure.ac:5: error: required file './config.sub' not found
+configure.ac:5:   'automake --add-missing' can install 'config.sub'
+configure.ac:5: error: required file './ltmain.sh' not found
+Makefile:298: recipe for target 'Makefile.in' failed
+make: *** [Makefile.in] Error 1
+% autoreconf -sif
+libtoolize: putting auxiliary files in '.'.
+libtoolize: linking file './ltmain.sh'
+libtoolize: Consider adding 'AC_CONFIG_MACRO_DIRS([m4])' to configure.ac,
+libtoolize: and rerunning libtoolize and aclocal.
+libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
+configure.ac:4: installing './compile'
+configure.ac:5: installing './config.guess'
+configure.ac:5: installing './config.sub'
+configure.ac:3: installing './missing'
+Makefile.am: installing './depcomp'
+% make
+...
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{configure.ac (f.)}
-  \lstinputlisting[firstline=14, lastline=27]{library/configure.ac}
+\frametitle{what about the m4 macros warnings?}
+libtool wants to install its m4 scripts into the project.
+
+This is useful if you pass the project to other people that might have other
+versions of libtool installed on their machine.
+
+prepare a directory for these scripts in 'autogen.sh':
+\begin{verbatim}
+#!/bin/sh
+mkdir -p m4
+autoreconf -sif
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{configure.ac (f.)}
-  \lstinputlisting[firstline=28]{library/configure.ac}
+\frametitle{local libtoolize}
+add a macro into 'configure.ac' that specifies the destination of the local
+libtoolize scripts
+\begin{verbatim}
+...
+LT_INIT
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_SRCDIR([hello.c])
+...
+\end{verbatim}
+include this directory in 'Makefile.am' and regenerate everything:
+\begin{verbatim}
+% echo 'ACLOCAL_AMFLAGS = -I m4' >> Makefile.am
+% ./autogen.sh
+% make
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{Makefile.am}
-  \lstinputlisting[language=make, lastline=10]{library/Makefile.am}
+\frametitle{do a test installation}
+\begin{verbatim}
+% make DESTDIR=`pwd`/tmp install
+...
+% find tmp
+tmp/
+tmp/usr
+tmp/usr/local
+tmp/usr/local/lib
+tmp/usr/local/lib/libfib-1.1.so.0
+tmp/usr/local/lib/libfib-1.1.so.0.0.0
+tmp/usr/local/lib/libfib.la
+tmp/usr/local/lib/libfib.so
+tmp/usr/local/lib/libfib.a
+tmp/usr/local/include
+tmp/usr/local/include/fib.h
+tmp/usr/local/bin
+tmp/usr/local/bin/hello
+\end{verbatim}
+looks sane, but the pkg-config .pc file is missing
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{Makefile.am (f.)}
-  \lstinputlisting[language=make, firstline=11, lastline=22]{library/Makefile.am}
+\frametitle{add a libfib pkg-config .pc file}
+Remember, the .pc file contains the paths where the library and headers are
+installed.
+
+These paths are defined by './configure' parameters. So we have to generate
+a template 'fib/fib.pc.in':
+\begin{verbatim}
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+
+Name: libfib
+Description: fibonacci library
+Version: @VERSION@
+Libs: -lfib
+Cflags: -I${includedir}
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{Makefile.am (f.)}
-  \lstinputlisting[language=make, firstline=23]{library/Makefile.am}
+\frametitle{generate fib.pc file from .in file}
+add fib.pc to AC\_CONFIG\_FILES in 'configure.ac':
+\begin{verbatim}
+...
+AC_CONFIG_FILES([Makefile
+                 fib/Makefile
+                 fib/fib.pc])
+...
+\end{verbatim}
+config in 'fib/Makefile.am' to install the fib.pc file:
+\begin{verbatim}
+% echo 'pkgconfigdir = $(datadir)/pkgconfig' >> fib/Makefile.am
+% echo 'pkgconfig_DATA = fib.pc' >> fib/Makefile.am
+% make DESTDIR=`pwd`/tmp install
+% find tmp | grep fib.pc
+% tmp/usr/local/share/pkgconfig/fib.pc
+% export PKG_CONFIG_PATH=tmp/usr/local/share/pkgconfig
+% pkg-config --list-all | grep fib
+fib                              libfib - fibonacci library
+% pkg-config fib --cflags --libs
+-I/usr/local/include -lfib
+% pkg-config fib --modversion
+1.1
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{hello.c}
-  \lstinputlisting{library/hello.c}
+\frametitle{make a new release \#1}
+'configure.ac':
+\begin{verbatim}
+...
+AC_INIT([hello], [2.0], [manut@linutronix.de])
+...
+\end{verbatim}
+update '.gitignore' add the following lines:
+\begin{verbatim}
+config.guess
+config.sub
+.libs
+*.lo
+*.pc
+*.la
+*.tar.gz
+libtool
+ltmain.sh
+m4/
+\end{verbatim}
+add changes to git:
+\begin{verbatim}
+% git add Makefile.am autogen.sh configure.ac .gitignore
+% git add fib/Makefile.am fib/fib.c fib/fib.h fib/fib.pc.in
+% git commit -s
+\end{verbatim}
 \end{frame}
 
 \begin{frame}[fragile]
-  \frametitle{Erstellen der Bibliothek}
-  \begin{lstlisting}
-    # Erstellen der zu generierenden Dateien
-    ./autogen.sh
-    # Konfiguration der Bibliothek
-    ./configure
-    # Bauen der Bibliothek
-    make
-    # Testen der Quelltext-Distribution der Bibliothek
-    make distcheck
-    # Löschen aller generierten Dateien
-    make maintainer-clean
-  \end{lstlisting}
+\frametitle{make a new release \#2}
+\begin{verbatim}
+% git clean -dxf
+% ./autogen.sh
+...
+% ./configure --with-gui
+...
+% make distcheck
+...
+===========================================
+hello-2.0 archives ready for distribution:
+hello-2.0.tar.gz
+===========================================
+\end{verbatim}
 \end{frame}
 
+\begin{frame}
+\frametitle{Conclusion}
+\begin{itemize}
+\item autotools looks complicated, because the generated tarballs contain
+  auto generated files and a copy of the libtool m4 scripts, etc
+\item only edit 'configure.ac' and 'Makefile.am' and your sources!
+\item autotools projects are very portable
+\item autotools defines a well-known standard howto build software, this
+  makes packaging of software a lot easier.
+\end{itemize}
+\end{frame}
-- 
cgit v1.2.3

