diff options
| author | Manuel Traut <manut@linutronix.de> | 2016-05-19 16:13:03 +0200 |
|---|---|---|
| committer | Manuel Traut <manut@linutronix.de> | 2016-05-19 16:13:03 +0200 |
| commit | 32a1ea434d0dd0bac45ee849b836df11470757e8 (patch) | |
| tree | 8186df2e193ef8d9eccab924315103ccdba99284 /distribution | |
| parent | afdcd4518929b4f6ad03b096edd7166f01b9ddda (diff) | |
first version of my-way to teach autotools
Signed-off-by: Manuel Traut <manut@linutronix.de>
Diffstat (limited to 'distribution')
| -rw-r--r-- | distribution/autotools/autotools.tex | 984 |
1 files changed, 878 insertions, 106 deletions
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} |
