automake-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Documentation for conditional SUBDIRS (+ test cases)


From: Alexandre Duret-Lutz
Subject: Documentation for conditional SUBDIRS (+ test cases)
Date: 23 Aug 2002 01:49:16 +0200
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7

Here is an attempt to better document conditional SUBDIRS.  

I'm including the text version of this section in addition to
the patch; It'll be easier to read and comment.

What do you think of it?  Is there anything that should be
corrected/clarified?

The patch also add test cases for the two solutions presented
(there were no checks for DIST_SUBDIRS in the test suite).

--->8--->8--->8--->8--->8--->8---

The top-level `Makefile.am'
***************************

Recursing subdirectories
========================

   In packages with subdirectories, the top level `Makefile.am' must
tell Automake which subdirectories are to be built.  This is done via
the `SUBDIRS' variable.

   The `SUBDIRS' variable holds a list of subdirectories in which
building of various sorts can occur.  Many targets (e.g. `all') in the
generated `Makefile' will run both locally and in all specified
subdirectories.  Note that the directories listed in `SUBDIRS' are not
required to contain `Makefile.am's; only `Makefile's (after
configuration).  This allows inclusion of libraries from packages which
do not use Automake (such as `gettext').  The directories mentioned in
`SUBDIRS' must be direct children of the current directory.  For
instance, you cannot put `src/subdir' into `SUBDIRS'.

   In packages that use subdirectories, the top-level `Makefile.am' is
often very short.  For instance, here is the `Makefile.am' from the GNU
Hello distribution:

     EXTRA_DIST = BUGS ChangeLog.O README-alpha
     SUBDIRS = doc intl po src tests

   When Automake invokes `make' in a subdirectory, it uses the value of
the `MAKE' variable.  It passes the value of the variable
`AM_MAKEFLAGS' to the `make' invocation; this can be set in
`Makefile.am' if there are flags you must always pass to `make'.

   The use of `SUBDIRS' is not restricted to just the top-level
`Makefile.am'.  Automake can be used to construct packages of arbitrary
depth.

   By default, Automake generates `Makefiles' which work depth-first
(`postfix').  However, it is possible to change this ordering.  You can
do this by putting `.' into `SUBDIRS'.  For instance, putting `.'
first will cause a `prefix' ordering of directories.  All `clean'
targets are run in reverse order of build targets.

Conditional subdirectories
==========================

   It is possible to define the `SUBDIRS' variable conditionally if,
like in the case of GNU `Inetutils', you want to only build a subset of
the entire package.

   To illustrate how this works, let's assume we have two directories
`src/' and `opt/'.  `src/' should always be built, but we want to
decide in `./configure' whether `opt/' will be built or not.  (For this
example we will assume that `opt/' should be built when the variable
`$want_opt' was set to `yes'.)

   Running `make' should thus recurse into `src/' always, and then
maybe in `opt/'.

   However `make dist' should always recurse into both `src/' and
`opt/'.  Because `opt/' should be distributed even if it is not needed
in the current configuration. This means `opt/Makefile' should be
created unconditionally.  (1)

   There is two ways to setup a project like this.  You can use Automake
conditionals (*note Conditionals::) or use Autoconf `AC_SUBST'
variables (*note Setting Output Variables: (autoconf)Setting Output
Variables.).  Automake conditionals is the preferred solution.

Conditional subdirectories with `AM_CONDITIONAL'
------------------------------------------------

   `configure' should output the `Makefile' for each directory and
define a condition into which `opt/' should be built.

     ...
     AM_CONDITIONAL([COND_OPT], [test "$want_opt" = yes])
     AC_CONFIG_FILES([Makefile src/Makefile opt/Makefile])
     ...

   Then `SUBDIRS' can be defined in the top-level `Makefile.am' as
follows.

     if COND_OPT
       MAYBE_OPT = opt
     endif
     SUBDIRS = src $(MAYBE_OPT)

   As you can see, running `make' will rightly recurse into `src/' and
maybe `opt/'.

   As you can't see, running `make dist' will recurse into both `src/'
and `opt/', always.  How comes?  Because `make dist', unlike `make',
doesn't use the `SUBDIRS' variable, it uses the `DIST_SUBDIRS' variable
instead.

   In this case Automake will define `DIST_SUBDIRS = src opt'
automatically because it knows that `MAYBE_OPT' can contain `opt' in
some condition.

   The `DIST_SUBDIRS' variable will also be used when the user runs
`make distclean' or `make maintainer-clean'.

Conditional subdirectories with `AC_SUBST'
------------------------------------------

   Another idea is to define `MAYBE_OPT' from `./configure' using
`AC_SUBST':

     ...
     if test "$want_opt" = yes; then
       MAYBE_OPT=opt
     else
       MAYBE_OPT=
     fi
     AC_SUBST([MAYBE_OPT])
     AC_CONFIG_FILES([Makefile src/Makefile opt/Makefile])
     ...

   In this case the top-level `Makefile.am' should look as follows.

     SUBDIRS = src $(MAYBE_OPT)
     DIST_SUBDIRS = src opt

   The drawback is that since Automake cannot guess what the possible
values of `MAYBE_OPT' are, we have to define `DIST_SUBDIRS' ourselves.

--->8--->8--->8--->8--->8--->8---

2002-08-23  Alexandre Duret-Lutz  <address@hidden>

        * automake.texi (Top level): More words about conditional
        subdirectories.  Don't mention AC_PROG_MAKE_SET.
        * tests/subdircond2.test, tests/subdircond3.test: New files.
        * tests/Makefile.am (TESTS): Add them.

Index: automake.texi
===================================================================
RCS file: /cvs/automake/automake/automake.texi,v
retrieving revision 1.297
diff -u -r1.297 automake.texi
--- automake.texi       22 Aug 2002 17:23:03 -0000      1.297
+++ automake.texi       22 Aug 2002 23:44:50 -0000
@@ -1756,6 +1756,8 @@
 @node Top level, Alternative, configure, Top
 @chapter The top-level @file{Makefile.am}
 
address@hidden Recursing subdirectories
+
 @cindex SUBDIRS, explained
 
 In packages with subdirectories, the top level @file{Makefile.am} must
@@ -1783,42 +1785,11 @@
 SUBDIRS = doc intl po src tests
 @end example
 
address@hidden SUBDIRS, overriding
address@hidden Overriding SUBDIRS
-
-It is possible to override the @code{SUBDIRS} variable if, like in the
-case of GNU @code{Inetutils}, you want to only build a subset of the
-entire package.  In your @file{Makefile.am} include:
-
address@hidden
-SUBDIRS = @@MY_SUBDIRS@@
address@hidden example
-
-Then in your @file{configure.in} you can specify:
-
address@hidden
-MY_SUBDIRS="src doc lib po"
-AC_SUBST(MY_SUBDIRS)
address@hidden example
-
-(Note that we don't use the variable name @code{SUBDIRS} in our
address@hidden; that would cause Automake to believe that every
address@hidden should recurse into the listed subdirectories.)
-
-The upshot of this is that Automake is tricked into building the package
-to take the subdirs, but doesn't actually bind that list until
address@hidden is run.
-
-Although the @code{SUBDIRS} variable can contain configure substitutions
-(e.g. @samp{@@DIRS@@}); Automake itself does not actually examine the
-contents of this variable.
-
-If @code{SUBDIRS} is defined, then your @file{configure.in} must include
address@hidden  When Automake invokes @code{make} in a
-subdirectory, it uses the value of the @code{MAKE} variable.  It passes
-the value of the variable @code{AM_MAKEFLAGS} to the @code{make}
-invocation; this can be set in @file{Makefile.am} if there are flags you
-must always pass to @code{make}.
+When Automake invokes @code{make} in a subdirectory, it uses the value
+of the @code{MAKE} variable.  It passes the value of the variable
address@hidden to the @code{make} invocation; this can be set in
address@hidden if there are flags you must always pass to
address@hidden
 @vindex MAKE
 @vindex MAKEFLAGS
 
@@ -1833,13 +1804,115 @@
 directories.  All @samp{clean} targets are run in reverse order of build
 targets.
 
-Sometimes, such as when running @code{make dist}, you want all possible
-subdirectories to be examined.  In this case Automake will use
address@hidden, instead of @code{SUBDIRS}, to determine where to
-recurse.  This variable will also be used when the user runs
address@hidden or @code{maintainer-clean}.  It should be set to the
-full list of subdirectories in the project.  If this variable is not set,
-Automake will attempt to set it for you.
address@hidden Conditional subdirectories
address@hidden Subdirectories, building conditionally
address@hidden Conditional subdirectories
address@hidden @code{SUBDIRS}, conditional
address@hidden Conditional @code{SUBDIRS}
+
+It is possible to define the @code{SUBDIRS} variable conditionally if,
+like in the case of GNU @code{Inetutils}, you want to only build a
+subset of the entire package.
+
+To illustrate how this works, let's assume we have two directories
address@hidden/} and @file{opt/}.  @file{src/} should always be built, but we
+want to decide in @code{./configure} whether @file{opt/} will be built
+or not.  (For this example we will assume that @file{opt/} should be
+built when the variable @code{$want_opt} was set to @code{yes}.)
+
+Running @code{make} should thus recurse into @file{src/} always, and
+then maybe in @file{opt/}.
+
+However @code{make dist} should always recurse into both @file{src/} and
address@hidden/}.  Because @file{opt/} should be distributed even if it is
+not needed in the current configuration. This means @file{opt/Makefile}
+should be created unconditionally.  @footnote{Don't try seeking a
+solution where @file{opt/Makefile} is created conditionally, this is a
+lot trickier than the solutions presented here.}
+
+There is two ways to setup a project like this.  You can use Automake
+conditionals (@pxref{Conditionals}) or use Autoconf @code{AC_SUBST}
+variables (@pxref{Setting Output Variables, , Setting Output Variables,
+autoconf, The Autoconf Manual}).  Automake conditionals is the preferred
+solution.
+
address@hidden Conditional subdirectories with @code{AM_CONDITIONAL}
address@hidden @code{SUBDIRS} and @code{AM_CONDITIONAL}
address@hidden @code{AM_CONDITIONAL} and @code{SUBDIRS}
+
address@hidden The test case for the setup described here is
address@hidden     test/subdircond2.test
address@hidden Try to keep it in sync.
+
address@hidden should output the @file{Makefile} for each directory
+and define a condition into which @file{opt/} should be built.
+
address@hidden
address@hidden
+AM_CONDITIONAL([COND_OPT], [test "$want_opt" = yes])
+AC_CONFIG_FILES([Makefile src/Makefile opt/Makefile])
address@hidden
address@hidden example
+
+Then @code{SUBDIRS} can be defined in the top-level @file{Makefile.am}
+as follows.
+
address@hidden
+if COND_OPT
+  MAYBE_OPT = opt
+endif
+SUBDIRS = src $(MAYBE_OPT)
address@hidden example
+
+As you can see, running @code{make} will rightly recurse into
address@hidden/} and maybe @file{opt/}.
+
address@hidden DIST_SUBDIRS
+As you can't see, running @code{make dist} will recurse into both
address@hidden/} and @file{opt/}, always.  How comes?  Because @code{make
+dist}, unlike @code{make}, doesn't use the @code{SUBDIRS} variable, it
+uses the @code{DIST_SUBDIRS} variable instead.
+
+In this case Automake will define @code{DIST_SUBDIRS = src opt}
+automatically because it knows that @code{MAYBE_OPT} can contain
address@hidden in some condition.
+
+The @code{DIST_SUBDIRS} variable will also be used when the user runs
address@hidden distclean} or @code{make maintainer-clean}.
+
address@hidden Conditional subdirectories with @code{AC_SUBST}
address@hidden @code{SUBDIRS} and @code{AC_SUBST}
address@hidden @code{AC_SUBST} and @code{SUBDIRS}
+
address@hidden The test case for the setup described here is
address@hidden     test/subdircond3.test
address@hidden Try to keep it in sync.
+
+Another idea is to define @code{MAYBE_OPT} from @file{./configure} using
address@hidden:
+
address@hidden
address@hidden
+if test "$want_opt" = yes; then
+  MAYBE_OPT=opt
+else
+  MAYBE_OPT=
+fi
+AC_SUBST([MAYBE_OPT])
+AC_CONFIG_FILES([Makefile src/Makefile opt/Makefile])
address@hidden
address@hidden example
+
+In this case the top-level @file{Makefile.am} should look as follows.
+
address@hidden
+SUBDIRS = src $(MAYBE_OPT)
+DIST_SUBDIRS = src opt
address@hidden example
+
+The drawback is that since Automake cannot guess what the possible
+values of @code{MAYBE_OPT} are, we have to define @code{DIST_SUBDIRS}
+ourselves.
 
 
 @node Alternative, Rebuilding, Top level, Top
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/automake/automake/tests/Makefile.am,v
retrieving revision 1.429
diff -u -r1.429 Makefile.am
--- tests/Makefile.am   19 Aug 2002 22:48:39 -0000      1.429
+++ tests/Makefile.am   22 Aug 2002 23:45:00 -0000
@@ -345,6 +345,8 @@
 subdir7.test \
 subdirbuiltsources.test \
 subdircond.test \
+subdircond2.test \
+subdircond3.test \
 subobj.test \
 subobj2.test \
 subobj3.test \
Index: tests/subdircond2.test
===================================================================
RCS file: tests/subdircond2.test
diff -N tests/subdircond2.test
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ tests/subdircond2.test      22 Aug 2002 23:45:01 -0000
@@ -0,0 +1,77 @@
+#! /bin/sh
+
+# The for conditional SUBDIRS.
+# SUBDIRS + AM_CONDITIONAL setup from the manual.
+# Lots of lines here are duplicated in subdircond3.test.
+
+. $srcdir/defs || exit 1
+
+set -e
+
+cat >>configure.in <<'END'
+AM_CONDITIONAL([COND_OPT], [test "$want_opt" = yes])
+AC_CONFIG_FILES([src/Makefile opt/Makefile])
+AC_OUTPUT
+END
+
+cat >Makefile.am << 'END'
+if COND_OPT
+  MAYBE_OPT = opt
+endif
+SUBDIRS = src $(MAYBE_OPT)
+
+# Testing targets.
+#
+# We want to ensure that
+#      - src/source and opt/source are always distributed.
+#      - src/result is always built
+#      - opt/result is built conditionally
+#
+# We rely on `distcheck' to run `check-local' and use
+# `sanity1' and `sanity2' as evidences that test-build was run.
+
+if COND_OPT
+test-build: all
+       test -f src/result
+       test -f opt/result
+       : > $(top_builddir)/../../sanity2
+else
+test-build: all
+       test -f src/result
+       test ! -f opt/result
+       : > $(top_builddir)/../../sanity1
+endif
+
+test-dist: distdir
+       test -f $(distdir)/src/source
+       test -f $(distdir)/opt/source
+
+check-local: test-build test-dist
+END
+
+mkdir src opt
+: > src/source
+: > opt/source
+
+cat >src/Makefile.am << 'END'
+EXTRA_DIST = source
+all-local: result
+CLEANFILES = result
+
+result: source
+       cp $(srcdir)/source result
+END
+
+# We want in opt/ the same Makefile as in src/.  Let's exercize `include'.
+cat >opt/Makefile.am << 'END'
+include ../src/Makefile.am
+END
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE --add-missing
+./configure
+$MAKE distcheck
+test -f sanity1
+$MAKE DISTCHECK_CONFIGURE_FLAGS=want_opt=yes distcheck
+test -f sanity2
Index: tests/subdircond3.test
===================================================================
RCS file: tests/subdircond3.test
diff -N tests/subdircond3.test
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ tests/subdircond3.test      22 Aug 2002 23:45:01 -0000
@@ -0,0 +1,78 @@
+#! /bin/sh
+
+# The for conditional SUBDIRS.
+# SUBDIRS + AC_SUBST setup from the manual.
+# Lots of lines here are duplicated in subdircond2.test.
+
+. $srcdir/defs || exit 1
+
+set -e
+
+cat >>configure.in <<'END'
+if test "$want_opt" = yes; then
+  MAYBE_OPT=opt
+else
+  MAYBE_OPT=
+fi
+AC_SUBST([MAYBE_OPT])
+AC_CONFIG_FILES([src/Makefile opt/Makefile])
+AC_OUTPUT
+END
+
+cat >Makefile.am << 'END'
+SUBDIRS = src $(MAYBE_OPT)
+DIST_SUBDIRS = src opt
+
+# Testing targets.
+#
+# We want to ensure that
+#      - src/source and opt/source are always distributed.
+#      - src/result is always built
+#      - opt/result is built conditionally
+#
+# We rely on `distcheck' to run `check-local' and use
+# `sanity1' and `sanity2' as evidences that test-build was run.
+
+test-build: all
+       test -f src/result
+       if test -n "$(MAYBE_OPT)"; then \
+          test -f opt/result || exit 1; \
+          : > $(top_builddir)/../../sanity2 || exit 1; \
+       else \
+          test ! -f opt/result || exit 1; \
+          : > $(top_builddir)/../../sanity1 || exit 1; \
+       fi
+
+test-dist: distdir
+       test -f $(distdir)/src/source
+       test -f $(distdir)/opt/source
+
+check-local: test-build test-dist
+END
+
+mkdir src opt
+: > src/source
+: > opt/source
+
+cat >src/Makefile.am << 'END'
+EXTRA_DIST = source
+all-local: result
+CLEANFILES = result
+
+result: source
+       cp $(srcdir)/source result
+END
+
+# We want in opt/ the same Makefile as in src/.  Let's exercize `include'.
+cat >opt/Makefile.am << 'END'
+include ../src/Makefile.am
+END
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE --add-missing
+./configure
+$MAKE distcheck
+test -f sanity1
+$MAKE DISTCHECK_CONFIGURE_FLAGS=want_opt=yes distcheck
+test -f sanity2

-- 
Alexandre Duret-Lutz





reply via email to

[Prev in Thread] Current Thread [Next in Thread]