\documentclass{slides}

\onlyslides{1-666}

\begin{document}

\begin{slide}
\begin{center}
Shameless Plug

SIPB

The MIT Student Information Processing Board

www.mit.edu

W20-557

\end{center}
\end{slide}

\begin{note}

This class is sponsored by SIPB, the MIT Student Information
Processing Board, a volunteer student group that provides
computer-related services to the MIT community.  For more information,
you know what to do: (point at board).

\end{note}


\begin{slide}
 \begin{center}
  Background and Purpose of Autoconf
 \end{center}

{\bf Problem:} Different hardware architectures run different kinds of
machine code.

{\bf Solution:} Portable programming languages, like C, allow the same
source code to be {\it compiled\/} into machine code appropriate for
running on the host computer.

\end{slide}

\begin{note}

For example, machine code for a Pentium doesn't make sense on an
Alpha.

The C compiler is often called ``cc'' or similar (``gcc'') by
convention.

\end{note}

\begin{slide}
 \begin{center}
  Background and Purpose of Autoconf
 \end{center}

{\bf Problem:} Different OSes provide different interfaces (or {\em
APIs}) to programs.

{\bf Solution:} OS standards, for example, POSIX.

\end{slide}

\begin{note}

For example, programs written for Linux generally won't run under
Windows, or even sometimes under a similar OS like HP-UX.

POSIX specifies many aspects of the OS interface for UNIX-like OSes.

\end{note}

\begin{slide}
 \begin{center}
  Background and Purpose of Autoconf
 \end{center}

{\bf Problem:} POSIX doesn't specify enough for modern development,
and not all OSes implement POSIX fully and correctly.

{\bf Solution:} {\it GNU Autoconf\/}is a tool for producing shell
scripts that automatically configure software source code packages to
adapt to many kinds of UNIX-like systems.

\end{slide}

\begin{note}

A lot of OSes are broken.  Autoconf helps you work around their
brokennesses so that your code will run on pretty much any system.
Autoconf helps to ensure that software dependencies are fulfilled.

\end{note}

\begin{slide}
 \begin{center}
  Background and Purpose of Autoconf
 \end{center}

{\bf Problem:} Autoconf is boring and complicated to learn.

\end{slide}

\begin{note}

{\bf Solution:} That's why this class is only two hours long;
hopefully, by the end of this, you'll be able to autoconfize simple
programs, and you'll know where to look for more information when you
have to autoconfize a complex project.

Feel free to interrupt me with questions during the lecture, and I
hope to finish early to leave some time for questions at the end.

\end{note}

\begin{slide}
 \begin{center}
  The Example Program
 \end{center}

{\tt {\bf picard} --- goes where no man has gone before}

\begin{verbatim}
*** picard.c ***

#include <enterprise.h>

int main(int argc, char *argv[])
{
#if HAVE_WARP_CORE
  engage("gamma-alpha-gamma");
#else
  make_it_so();
#endif
  return 0;
}
\end{verbatim}

\end{slide}

\begin{note}

We'll autoconfize this program so that we can have a sexy bald captain
on every desktop in the world.

\end{note}

\begin{slide}
 \begin{center}
  The Build Process from the User's Perspective
 \end{center}

{\tiny
\begin{verbatim}
% gunzip trek.tar.gz
% tar -xf trek.tar.gz
% cd trek/picard
% ./configure
creating cache ./config.cache
checking for gcc... gcc
checking whether the C compiler (gcc  ) works... yes
checking whether the C compiler (gcc  ) is a cross-compiler... no
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes
checking for a BSD compatible install... /usr/bin/ginstall -c
checking for make_it_so in -lenterprise... yes
updating cache ./config.cache
creating ./config.status
creating Makefile
% make
gcc -g -O2 -DHAVE_LIBENTERPRISE=1   -c picard.c -o picard.o
gcc  -o picard picard.o -lenterprise 
% make install
/usr/bin/ginstall -c picard /usr/local/bin
\end{verbatim}
}

\end{slide}

\begin{note}

Note that once the package is unpacked, the simple sequence
``./configure'', ``make'', ``make install'' should be the entire build
process.

\end{note}

\begin{slide}
 \begin{center}
   From the Maintainer's Perspective
 \end{center}

The source files in trek/picard are {\tt picard.c}, {\tt
configure.in}, and {\tt Makefile.in}:

{\tiny \begin{verbatim}
% ls
Makefile.in   configure.in  install-sh*   picard.c
% cat configure.in
dnl Process this file with autoconf to produce a configure script.
AC_INIT(picard.c)

AC_PROG_CC
AC_PROG_INSTALL

AC_CHECK_LIB(enterprise, make_it_so)

AC_ARG_ENABLE(warp-core,
[  --enable-warp-core        the enterprise has a warp core],
[if test x$enableval = xyes; then
  AC_DEFINE(HAVE_WARP_CORE)
fi])

AC_OUTPUT(Makefile)
\end{verbatim} }

\end{slide}

\begin{note}

``install-sh'' comes with autoconf --- it is a replacement for the
standard BSD-compatible ``install'' program in case the build system
doesn't have one.

``configure.in'' is a bare-bones autoconf source, which I'll explain
line-by-line.

\end{note}

\begin{slide}
 \begin{center}
  dnl
 \end{center}

{\tiny \begin{verbatim}
dnl Process this file with autoconf to produce a configure script.
\end{verbatim} }

{\tt dnl} starts a comment which continues up to the end of the line.

\end{slide}

\begin{slide}
 \begin{center}
   AC\_INIT
 \end{center}

\begin{verbatim}
AC_INIT(picard.c)
\end{verbatim}

All autoconf files have to begin with an {\tt AC\_INIT} on the first
line ({\tt dnl}'ed lines don't count).

\end{slide}

\begin{note}

Its argument must be a file in the distribution that's unlikely to be
in another distribution (it's used to make sure that the user is
invoking configure in the right directory).

\end{note}

\begin{slide}
 \begin{center}
   AC\_PROG\_CC, AC\_PROG\_INSTALL
 \end{center}

\begin{verbatim}
AC_PROG_CC
AC_PROG_INSTALL
\end{verbatim}

{\tt AC\_PROG\_CC} determines a C compiler to use.

{\tt AC\_PROG\_INSTALL} locates a BSD-compatible ``install'' program;
uses ``install-sh'' in the build directory if none is found. \\
({\tt install} == fancy {\tt cp})

\end{slide}

\begin{note}

AC\_PROG\_CC looks for gcc first, and then cc.  It also determines the
correct options to pass the compiler.

``install'' is a program very similar to ``cp'', but with options for
setting the mode and ownership of the copied file.

\end{note}

\begin{slide}
 \begin{center}
  AC\_CHECK\_LIB
 \end{center}

\begin{verbatim}
AC_CHECK_LIB(enterprise, make_it_so)
\end{verbatim}

Ensures that the library {\tt libenterprise} is available on the build
system, and that it contains the function {\tt make\_it\_so}.  The
full prototype is:

\begin{verbatim}
AC_CHECK_LIB( library, function,
              [ action-if-found,
              [ action-if-not-found,
              [ other-libs ] ] ] )
\end{verbatim}

Default {\tt action-if-found} adds {\tt -l{\it library}} to {\tt LIBS}
and defines {\tt HAVE\_LIB{\it library}}.

\end{slide}

\begin{note}

action-if-found is executed if the link is successful, otherwise
action-if-not-found is executed.  If the library depends on other
libraries (for example, libX11), put them into other-libs as -lX11.

\end{note}

\begin{slide}
 \begin{center}
  AC\_ARG\_ENABLE
 \end{center}

{\tiny \begin{verbatim}
AC_ARG_ENABLE(warp-core,
[  --enable-warp-core        the enterprise has a warp core],
[if test x$enableval = xyes; then
  AC_DEFINE(HAVE_WARP_CORE)
fi])
\end{verbatim} }

Creates a new command-line option \\ {\tt --enable-warp-core}.

The full prototype is:

\begin{verbatim}
AC_ARG_ENABLE( feature, help-text,
               [ action-if-given,
               [ action-if-not-given ] ] )
\end{verbatim}

\end{slide}

\begin{note}

\end{note}

\begin{slide}
 \begin{center}
  AC\_ARG\_ENABLE examples
 \end{center}

{\tiny \begin{verbatim}
% ./configure --help
Usage: configure [options] [host]
Options:
...
  --enable-warp-core        the enterprise has a warp core

% ./configure
% ./configure --enable-warp-core
% ./configure --enable-warp-core=no
% ./configure --disable-warp-core
\end{verbatim} }

\end{slide}

\begin{note}

The first one executes action-if-not-given; the second executes
action-if-given with \$enableval equal to ``yes''; the third and
fourth execute action-if-given with \$enableval equal to ``no''.

\end{note}

\begin{slide}
 \begin{center}
  AC\_DEFINE
 \end{center}

\begin{verbatim}
AC_DEFINE(HAVE_WARP_CORE)
\end{verbatim}

Defines the C preprocessor symbol {\tt HAVE\_WARP\_CORE} to 1.  This
affects the {\tt \#ifdef} in {\tt picard.c}.

\end{slide}

\begin{note}

If a second argument is provided, it will be the value of the symbol
(instead of 1).

\end{note}

\begin{slide}
 \begin{center}
  Example
 \end{center}

{\tiny \begin{verbatim}
% ./configure --enable-warp-core
\end{verbatim} }

Results in {\tt picard.c} being compiled as:

{\tiny \begin{verbatim}
#include <enterprise.h>

int main(int argc, char *argv[])
{
  engage("gamma-alpha-gamma");
  return 0;
}
\end{verbatim} }

\end{slide}

\begin{note}

\end{note}

\begin{slide}
 \begin{center}
  Example
 \end{center}

{\tiny \begin{verbatim}
% ./configure --disable-warp-core
\end{verbatim} }

or just

{\tiny \begin{verbatim}
% ./configure
\end{verbatim} }

Results in {\tt picard.c} being compiled as:

{\tiny \begin{verbatim}
#include <enterprise.h>

int main(int argc, char *argv[])
{
  make_it_so();
  return 0;
}
\end{verbatim} }

\end{slide}

\begin{note}

\end{note}

\begin{slide}
 \begin{center}
  AC\_OUTPUT
 \end{center}

\begin{verbatim}
AC_OUTPUT(Makefile)
\end{verbatim}

Takes a whitespace-separated list of files to output.  This should be
the last command in configure.in.

\end{slide}

\begin{note}

This tells configure to create the file Makefile from the file
Makefile.in, which I'll explain momentarily.

\end{note}


\begin{slide}
 \begin{center}
  Creating {\tt configure}
 \end{center}

\begin{verbatim}
% autoconf
% file configure
configure: Bourne Shell script text
\end{verbatim}

\end{slide}

\begin{note}

That's it.  autoconf processes the configure.in to create a Bourne shell
script which you distribute with your package.

\end{note}

\begin{slide}
 \begin{center}
  A Quick Look Under the Hood
 \end{center}

{\it GNU M4}, a programmable macro language, processes macros of the form
{\tt NAME( ARG, ARG, ARG, ... ) } and transforms them into shell
script text according to the rules set down by Autoconf.

``['' and ``]'' are quoting characters
under Autoconf.

Roll your own macros using the AC\_DEFUN macro, which has the form
\begin{verbatim}
AC_DEFUN( macro-name, macro-body )
\end{verbatim}

\end{slide}

\begin{note}

While this may look like the ugliest programming language you've ever
set eyes upon, there is actually a rhyme and reason to it.

\end{note}

\begin{slide}
 \begin{center}
  A Quick Look Under the Hood
 \end{center}

Because M4 passes non-macros through transparently, you can also put
arbitrary Bourne shell code in configure.in.  For example, in the
processing of the AC\_ARG\_ENABLE:

{\tiny \begin{verbatim}
AC_ARG_ENABLE(warp-core,
[  --enable-warp-core        the enterprise has a warp core],
[if test x$enableval = xyes; then
  AC_DEFINE(HAVE_WARP_CORE)
fi])
\end{verbatim} }

\end{slide}

\begin{note}

Note the use of the ``if'' shell primitive, and the ``test'' command.

Be careful to use only {\it minimal} functionality of the shell.  Some
OSes have seriously broken Bourne shells.

\end{note}

\begin{slide}
 \begin{center}
  Invoking configure: System Types
 \end{center}

Configure can be invoked as:

\begin{verbatim}
./configure system-type
\end{verbatim}

The canonical name for a system type has the form
{\tt CPU-COMPANY-SYSTEM}.  Examples:

\begin{verbatim}
i386-unknown-linux
sparc-sun-solaris2.6
mips-sgi-irix6.2
\end{verbatim}

configure also recognizes short aliases for many system types,
i.e.

\begin{verbatim}
decstation == mips-dec-ultrix4.2
\end{verbatim}

\end{slide}

\begin{note}

The program config.guess is usually distributed with autoconfized
packages.  It guesses the system type based on the output of uname and
C preprocessor symbols.

\end{note}

\begin{slide}
 \begin{center}
  Support for Cross-Compiling
 \end{center}

In the most complex case of cross-compiling, three system types are
involved.  The options to specify them are:

{\tt --build=BUILD-TYPE :} the type of system on which the package is
being configured and compiled (rarely needed)

{\tt --host=HOST-TYPE :} the type of system on which the package will
run

{\tt --target=TARGET-TYPE :} the type of system for which any compiler
tools in the package will produce code.

\end{slide}

\begin{note}

This is hairy and complicated.  Read the manual if you are stuck doing
this.

\end{note}

\begin{slide}
 \begin{center}
  Invoking configure:  Install Directories
 \end{center}

Can independently set: {\tt prefix, exec-prefix, bindir, sbindir,
libexecdir, datadir, sysconfdir, sharedstatedir, localstatedir,
libdir, includedir, oldincludedir, infodir, mandir, and srcdir.}

Important ones:

{\tt prefix:} Default root of all other dirs, defaults to /usr/local. \\
{\tt exec-prefix:} Default root of all executable files, defaults to
the same. \\
{\tt bindir:} User executable files, defaults to {\it exec-prefix}/bin. \\
{\tt mandir:} Manuals, defaults to {\it prefix}/man. \\
{\tt srcdir:} Make finds the sources here.  This is the only
non-destination directory.

\end{slide}

\begin{note}

autoconf allows the user almost complete control over where the
components of the package are installed.

\end{note}

\begin{slide}
 \begin{center}
  Back to AC\_OUTPUT
 \end{center}

{\tt Makefile} is created from {\tt Makefile.in} by substituting
expressions of the form {\tt @FOO@} with values determined in the
script.  For example, {\tt @CC@} might become {\tt gcc}, and {\tt
@DEFS@} might become {\tt -DHAVE\_WARP\_CORE=1}.

\end{slide}

\begin{note}

\end{note}


\begin{slide}
 \begin{center}
  Makefile.in
 \end{center}

{\tiny \begin{verbatim}
# Makefile for the picard program.

prefix      = @prefix@
exec_prefix = @exec_prefix@

bindir = @bindir@

srcdir = @srcdir@
VPATH  = @srcdir@

CC       = @CC@
DEFS     = @DEFS@
CPPFLAGS = @CPPFLAGS@ $(DEFS)
CFLAGS   = @CFLAGS@
LIBS     = @LIBS@
LDFLAGS  = @LDFLAGS@

INSTALL         = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA    = @INSTALL_DATA@

all: picard

clean:
	rm -f a.out core *.o picard

distclean: clean
	rm -f confdefs.h config.status config.log config.cache conf.h
	rm -f Makefile

install: picard
	$(INSTALL_PROGRAM) picard $(bindir)

picard: picard.o
	$(CC) $(LDFLAGS) -o $@ $? $(LIBS)
\end{verbatim} }

\end{slide}

\begin {note}

Don't panic --- it's just a fairly simple makefile.

\end{note}


\begin{slide}
 \begin{center}
  Makefile.in Header
 \end{center}

{\tiny \begin{verbatim}
prefix      = @prefix@
exec_prefix = @exec_prefix@

bindir = @bindir@

srcdir = @srcdir@
VPATH  = @srcdir@

CC       = @CC@
DEFS     = @DEFS@
CPPFLAGS = @CPPFLAGS@ $(DEFS)
CFLAGS   = @CFLAGS@
LIBS     = @LIBS@
LDFLAGS  = @LDFLAGS@

INSTALL         = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA    = @INSTALL_DATA@
\end{verbatim} }

It's customary to put all substituted variables into Make variables,
and required for most.  For example, {\tt @bindir@} by default
substitutes as {\tt \$\{prefix\}/bin}.

\end{slide}

\begin{note}

\end{note}

\begin{slide}
 \begin{center}
  Makefile.in Rules
 \end{center}

{\tiny \begin{verbatim}
all: picard

clean:
	rm -f a.out core *.o picard

distclean: clean
	rm -f confdefs.h config.status config.log config.cache conf.h
	rm -f Makefile

install: picard
	$(INSTALL_PROGRAM) picard $(bindir)

picard: picard.o
	$(CC) $(LDFLAGS) -o $@ $? $(LIBS)
\end{verbatim} }

\end{slide}

\begin{note}

A pretty standard makefile.  Note the distclean target, which removes
all the files that configure creates.  This is so that the user will
have to run configure on his host machine.

INSTALL\_PROGRAM is used for installing executable files, while
INSTALL\_DATA is used for installing data files.

(Be prepared to explain Makefiles briefly.)

\end{note}


\begin{slide}
 \begin{center}
  AC\_SUBST
 \end{center}

If {\tt AC\_SUBST(var)} is placed into a configure.in, then all
instances of @var@ will be replaced with whatever value the shell
variable \$var had when AC\_OUTPUT was reached.  Example:

\begin{verbatim}
foo=bar
AC_SUBST(foo)
\end{verbatim}

\end{slide}

\begin{note}

\end{note}

\begin{slide}
 \begin{center}
  Checking for Programs, Libraries, Headers, Structures and Typedefs
 \end{center}

Finding programs:  {\tt AC\_CHECK\_PROG, AC\_CHECK\_TOOL, AC\_PATH\_PROG}

Finding libraries:  {\tt AC\_CHECK\_LIB, AC\_CHECK\_FUNC}

Finding header files: {\tt AC\_CHECK\_HEADER}

Finding structures: {\tt AC\_HEADER\_ and AC\_STRUCT\_} families

Finding typedefs: {\tt AC\_CHECK\_TYPE}

\end{slide}

\begin{note}

These are all well documented in the manual, and you will find
yourself using them often.  However, always check first if autoconf
comes with a specific test for a particular program: for example, to
find awk, you use AC\_PROG\_AWK.

\end{note}

\begin{slide}
 \begin{center}
  Tools: autoscan
 \end{center}

\begin{verbatim}
% autoscan
% more configure.scan
  ... verify the results, and if you like them:
% cp configure.scan configure.in
% rm -f configure.scan
\end{verbatim}

\end{slide}

\begin{note}

Autoscan is fairly worthless.  However, it doesn't hurt to try it out
to get a framework for configure.in.

\end{note}


\begin{slide}
 \begin{center}
  Tools:  Automake
 \end{center}

While Autoconf takes much of the pain out of porting software from
platform to platform, Makefiles are still a pain to write.

Automake is a tool for automatically generating {\tt Makefile.in}s
from files called {\tt Makefile.am}.

\end{slide}

\begin{note}

Makefile.am's are usually easy to write, {\bf if} you keep the
automake manual handy.

Instead of explaining every feature of Automake in depth (because we'd
be here all night), I'll just replace picard's bulky Makefile.in with
a Makefile.am.

\end{note}

\begin{slide}
 \begin{center}
  Makefile.am
 \end{center}

\begin{verbatim}
bin_PROGRAMS = kirk
kirk_SOURCES = kirk.c
\end{verbatim}

\end{slide}

\begin{note}

That's it.  Automake can generate a fully functional Makefile.in from
this.

\end{note}

\begin{slide}
 \begin{center}
  configure.in
 \end{center}

{\tiny \begin{verbatim}
dnl Process this file with autoconf to produce a configure script.
AC_INIT(kirk.c)
AM_INIT_AUTOMAKE(kirk, 1.0)

AC_PROG_CC
AC_PROG_INSTALL

AC_CHECK_LIB(enterprise, make_it_so)

AC_ARG_ENABLE(warp-core,
[  --enable-warp-core        the enterprise has a warp core],
[if test x$enableval = xyes; then
  AC_DEFINE(HAVE_WARP_CORE)
fi])

AC_OUTPUT(Makefile)
\end{verbatim} }

\end{slide}

\begin{note}

It is virtually identical to picard's, except for the addition of the
AM\_INIT\_AUTOMAKE command.

\end{note}

\begin{slide}
 \begin{center}
  Other Changes
 \end{center}

\begin{verbatim}
% aclocal
% automake --foreign --add-missing
% autoconf

% ./configure
% make
% make install
\end{verbatim}

``Foreign'' means that the project does not comply to GNU coding
standards in such things as having README, NEWS, and ChangeLog files.

\end{slide}

\begin{note}

Running aclocal causes the Automake macros to be copied into the
``aclocal.m4'' file.  You shouldn't touch this file.

Running automake adds several necessary files to the directory, and
creates Makefile.in from Makefile.am.

\end{note}


\begin{slide}
 \begin{center}
  Makefile.am
 \end{center}

Usually consist of a list of variable assignments.

Primary variables have the form {\tt dir\_PRIMARY}, where dir is one
of {\tt bin, lib, info, man}, etc... and {\tt PRIMARY} is one of {\tt
PROGRAMS, LIBRARIES, LISP, SCRIPTS, DATA, HEADERS, MANS, or TEXINFOS}.

Derived variables have the form {\tt prog\_ASPECT}, where {\tt ASPECT}
could be {\tt SOURCES, LDADD, DEPENDENCIES, LDFLAGS}, etc...

\end{slide}

\begin{note}

The ``PRIMARY'' part determines what sort of objects the files are and
how they are to be built; the ``dir'' part specifies where they are to
be installed.

For example, prog\_SOURCES specifies the C source code to a program,
and prog\_LDFLAGS specifies extra flags to pass to the linker.

\end{note}


\begin{slide}
 \begin{center}
  Tools: Libtool
 \end{center}

Shared library build processes vary wildly across platforms.  Libtool
exists to provide a common interface to that process.

However, libtool is still not stable on many platforms.

\end{slide}

\begin{note}

In theory, libtool exists to make building shared libraries across
platforms much simple.  In reality, though, I've found libtool to be
more trouble than it's worth --- despite being out of beta, it still
has unresolved crippling bugs on some systems.

However, if you're feeling adventurous...

\end{note}


\begin{slide}
 \begin{center}
  Using Libtool with Automake
 \end{center}

To use Libtool with Automake to build a shared library, add {\tt
AM\_INIT\_AUTOMAKE} to {\tt configure.in} as you normally would, and
also add {\tt AM\_PROG\_LIBTOOL} somewhere in the body.  Create a
Makefile.am with the following contents:

\begin{verbatim}
lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = bar.c baz.c yaddayaddayadda.c
libfoo_la_LDFLAGS = --version-info 0:0:0
\end{verbatim}

\end{slide}

\begin{note}

Then ``aclocal'', ``automake'', and ``autoconf'' as you normally
would.  Let me know if you can get it to work. :)

\end{note}


\begin{slide}
 \begin{center}
   Conclusion: RTFM
 \end{center}

Install autoconf, automake, and/or libtool

In Emacs:

\begin{verbatim}
control-h i
g (autoconf)
\end{verbatim}

These slides will be found at

\begin{verbatim}
http://www.mit.edu/iap/autoconf
or
http://www.mit.edu/~golem/autoconf-iap99/
\end{verbatim}

You can reach me by email at

\begin{verbatim}
sipb-iap-autoconf@mit.edu
\end{verbatim}

\end{slide}

\begin{note}
\end{note}

\begin {note}

All of Autoconf, Automake, and Libtool are thoroughly and clearly
documented in their manuals.  To access them, first install their
source distributions.  Enter emacs and type [Control-h i] to enter
Info mode.  Finally, type [g ``(autoconf)''] to enter the Autoconf
manual (or ``(automake)'' or ``(libtool)'' for their respective
manuals).

(Remember to ask for questions)

\end{note}

\end{document}
