Dear all,

please bear with me if I'm doing something wrong here, this is the first
time that I'm trying to contribute to GNU Make.

The attached patch would add a minor (but imho useful) feature to GNU
Make. Here is an extract of the (changed) documentation (changes are in
red), giving a quite comprehensive idea as to why this feature would be
useful:


         4.3 Types of Prerequisites

   There are actually three different types of prerequisites understood
   by GNU |make|: normal prerequisites such as described in the
   previous section, /order-only/ prerequisites, and /dependency-only/
   prerequisites.

   A normal prerequisite makes two statements: first, it imposes an
   order in which recipes will be invoked: the recipes for all
   prerequisites of a target will be completed before the recipe for
   the target is run. Second, it imposes a dependency relationship: if
   any prerequisite is newer than the target, then the target is
   considered out-of-date and must be rebuilt.

   Normally, this is exactly what you want: if a target’s prerequisite
   is updated, then the target should also be updated.

   Occasionally, however, you have a situation where you want to impose
   a specific ordering on the rules to be invoked /without/ forcing the
   target to be updated if one of those rules is executed. In that
   case, you want to define /order-only/ prerequisites. Order-only
   prerequisites can be specified by placing a pipe symbol (|||) in the
   prerequisites list: any prerequisites to the left of the pipe symbol
   are normal; any prerequisites to the right are order-only:

   targets  :normal-prerequisites  |order-only-prerequisites

   The normal prerequisites section may of course be empty. Also, you
   may still declare multiple lines of prerequisites for the same
   target: they are appended appropriately (normal prerequisites are
   appended to the list of normal prerequisites; order-only
   prerequisites are appended to the list of order-only prerequisites).
   Note that if you declare the same file to be both a normal and an
   order-only prerequisite, the normal prerequisite takes precedence
   (since they have a strict superset of the behavior of an order-only
   prerequisite).

   Consider an example where your targets are to be placed in a
   separate directory, and that directory might not exist before |make|
   is run. In this situation, you want the directory to be created
   before any targets are placed into it but, because the timestamps on
   directories change whenever a file is added, removed, or renamed, we
   certainly don’t want to rebuild all the targets whenever the
   directory’s timestamp changes. One way to manage this is with
   order-only prerequisites: make the directory an order-only
   prerequisite on all the targets:

   OBJDIR := objdir
   OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

   $(OBJDIR)/%.o : %.c
            $(COMPILE.c) $(OUTPUT_OPTION) $<

   all: $(OBJS)

   $(OBJS): | $(OBJDIR)

   $(OBJDIR):
            mkdir $(OBJDIR)

   Now the rule to create the objdir directory will be run, if needed,
   before any ‘.o’ is built, but no ‘.o’ will be built because the
   objdir directory timestamp changed.

   Finally, the third type of prerequisites, i.e. depenency-only
   prerequisites, may be specified by placing a "smaller than" symbol
   (|<|) in the prerequisite list: any prerequisites to the left of the
   "smaller than" symbol are normal (or order-only); any prerequisites
   to the right are dependency-only (and possibly order-only as well).

   Dependency-only prerequisites behave almost identical to the other
   two prerequisite types, with one important exception: They do not
   contribute to any of their list-type related automatic variables.
   Thus, dependency-only prerequisites are not added to neither of the
   automatic variable lists $^, $+, $?, $*, $(^F), $(+F), $(?F), $(*F),
   $(^D), $(+D), $(?D) and $(*D), and prerequisites that are both
   dependency-only and order-only are not added to neither of the
   automatic variable lists $|, $(|F), $(|D).

   The rationale behind dependency-only dependencies is to make it more
   easy to extend dependency lists of existing Makefiles. An example
   may illustrate this:

   The following code may be considered as a snippet of a large and
   maybe rather complex Makefile:

   myappl: main.o file1.o file2.o gcc -o $ $^

   At a first glance, it lists all the relevant prerequisites, but a
   second thought reveals that this is just not true: The target
   certainly also depends on the compiler frontend, the linker backend
   and the Makefile itself.

   Thus, a more complete snippet should look more like this:

   myappl: main.o file1.o file2.o /usr/bin/gcc /usr/bin/ld Makefile gcc
   -o $ $(filter %.o, $^)

   Please note the need for the newly introduced GNU Make’s $(filter )
   function besides the additional prerequisites.

   But for big projects, say the Linux kernel or a toolchain build, it
   would be rather laborious to change and fix all the Makefiles
   accordingly, and it would be more than questionable if such patches
   would be welcomed by every project. Fortunately, with
   dependency-only prerequisites at hand, the upstream Makefiles do not
   need to be changed at all. Instead, it’s sufficient to list the
   additional dependencies as dependency-only prerequisites in another
   Makefile that just includes the upstream Makefile. To continue with
   our example (and assuming the related upstream Makefile was just
   called |Makefile|, we could most conviniently add a |GNUmakefile|
   with the following content:

   include Makefile myappl: < /usr/bin/gcc /usr/bin/ld Makefile

   Calling |make| now would prefer |GNUmakefile| over |Makefile|, thus
   respecting the additional prerequisites without affecting the
   related reciepe

What do you think: Do I have any chance to have my patch included? I'm
certainly more that willing to do any modifications desired.

Thanks in advance for any help,

Chris


diff --git a/doc/make.texi b/doc/make.texi
index 12f70c6..9e58802 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -155,7 +155,7 @@ Writing Rules

 * Rule Example::                An example explained.
 * Rule Syntax::                 General syntax explained.
-* Prerequisite Types::          There are two types of prerequisites.
+* Prerequisite Types::          There are three types of prerequisites.
 * Wildcards::                   Using wildcard characters such as `*'.
 * Directory Search::            Searching other directories for source files.
 * Phony Targets::               Using a target that is not a real file's name.
@@ -1883,7 +1883,7 @@ the makefile (often with a target called @samp{all}).
 @menu
 * Rule Example::                An example explained.
 * Rule Syntax::                 General syntax explained.
-* Prerequisite Types::          There are two types of prerequisites.
+* Prerequisite Types::          There are three types of prerequisites.
 * Wildcards::                   Using wildcard characters such as `*'.
 * Directory Search::            Searching other directories for source files.
 * Phony Targets::               Using a target that is not a real file's name.
@@ -2022,10 +2022,13 @@ extra features (@pxref{Recipes, ,Writing Recipes in Rules}).
 @cindex normal prerequisites
 @cindex prerequisites, order-only
 @cindex order-only prerequisites
-There are actually two different types of prerequisites understood by
+There are actually three different types of prerequisites understood by
 GNU @code{make}: normal prerequisites such as described in the
-previous section, and @dfn{order-only} prerequisites.  A normal
-prerequisite makes two statements: first, it imposes an order in which
+previous section, @dfn{order-only} prerequisites, and @dfn{dependency-only}
+prerequisites.
+
+A normal prerequisite makes two statements:
+first, it imposes an order in which
 recipes will be invoked: the recipes for all prerequisites of a target
 will be completed before the recipe for the target is run.  Second, it
 imposes a dependency relationship: if any prerequisite is newer than
@@ -2085,6 +2088,69 @@ Now the rule to create the @file{objdir} directory will be run, if
 needed, before any @samp{.o} is built, but no @samp{.o} will be built
 because the @file{objdir} directory timestamp changed.

+Finally, the third type of prerequisites, i.e. depenency-only
+prerequisites, may be specified by placing a "smaller than" symbol
+(@code{<}) in the prerequisite list: any prerequisites to the left
+of the "smaller than" symbol are normal (or order-only); any prerequisites
+to the right are dependency-only (and possibly order-only as well).
+
+Dependency-only prerequisites behave almost identical to the other
+two prerequisite types, with one important exception: They do not
+contribute to any of their list-type related automatic variables.
+Thus, dependency-only prerequisites are not added to neither
+of the automatic variable lists $^, $+, $?, $*, $(^F), $(+F), $(?F),
+$(*F), $(^D), $(+D), $(?D) and $(*D), and prerequisites that are both
+dependency-only and order-only are not added to neither of the
+automatic variable lists $|, $(|F), $(|D).
+
+The rationale behind dependency-only dependencies is to make it more
+easy to extend dependency lists of existing Makefiles. An example may
+illustrate this:
+
+The following code may be considered as a snippet of a large and
+maybe rather complex Makefile:
+
+@example
+myappl: main.o file1.o file2.o
+	gcc -o $@ $^
+@end example
+
+At a first glance, it lists all the relevant prerequisites, but a
+second thought reveals that this is just not true: The target
+certainly also depends on the compiler frontend, the linker backend
+and the Makefile itself.
+
+Thus, a more complete snippet should look more like this:
+
+@example
+myappl: main.o file1.o file2.o /usr/bin/gcc /usr/bin/ld Makefile
+	gcc -o $@ $(filter %.o, $^)
+@end example
+
+Please note the need for the newly introduced GNU Make's $(filter )
+function besides the additional prerequisites.
+
+But for big projects, say the Linux kernel or a toolchain build,
+it would be rather laborious to change and fix all the Makefiles
+accordingly, and it would be more than questionable if such patches
+would be welcomed by every project. Fortunately, with dependency-only
+prerequisites at hand, the upstream Makefiles do not need to be
+changed at all. Instead, it's sufficient to list the additional
+dependencies as dependency-only prerequisites in another Makefile
+that just includes the upstream Makefile. To continue with our
+example (and assuming the related upstream Makefile was just called
+@code{Makefile}, we could most conviniently add a @code{GNUmakefile}
+with the following content:
+
+@example
+include Makefile
+myappl: < /usr/bin/gcc /usr/bin/ld Makefile
+@end example
+
+Calling @code{make} now would prefer @code{GNUmakefile} over
+@code{Makefile}, thus respecting the additional prerequisites
+without affecting the related reciepe.
+
 @node Wildcards, Directory Search, Prerequisite Types, Rules
 @section Using Wildcard Characters in File Names
 @cindex wildcard
diff --git a/src/commands.c b/src/commands.c
index dd47851..7c08c01 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -178,7 +178,7 @@ set_file_variables (struct file *file)
     bar_len = 0;
     for (d = file->deps; d != 0; d = d->next)
       {
-        if (!d->need_2nd_expansion)
+        if (!d->need_2nd_expansion && !d->ignore_automatic_vars)
           {
             if (d->ignore_mtime)
               bar_len += strlen (dep_name (d)) + 1;
@@ -200,7 +200,7 @@ set_file_variables (struct file *file)

     qmark_len = plus_len + 1;   /* Will be this or less.  */
     for (d = file->deps; d != 0; d = d->next)
-      if (! d->ignore_mtime && ! d->need_2nd_expansion)
+      if (! d->ignore_mtime && ! d->need_2nd_expansion && ! d->ignore_automatic_vars)
         {
           const char *c = dep_name (d);

@@ -247,7 +247,7 @@ set_file_variables (struct file *file)

     for (d = file->deps; d != 0; d = d->next)
       {
-        if (d->need_2nd_expansion)
+        if (d->need_2nd_expansion || d->ignore_automatic_vars)
           continue;

         slot = hash_find_slot (&dep_hash, d);
@@ -269,7 +269,7 @@ set_file_variables (struct file *file)
       {
         const char *c;

-        if (d->need_2nd_expansion || hash_find_item (&dep_hash, d) != d)
+        if (d->need_2nd_expansion || d->ignore_automatic_vars || hash_find_item (&dep_hash, d) != d)
           continue;

         c = dep_name (d);
diff --git a/src/dep.h b/src/dep.h
index baa64df..bedf41a 100644
--- a/src/dep.h
+++ b/src/dep.h
@@ -48,7 +48,8 @@ struct nameseq
     unsigned short changed : 1;                 \
     unsigned short ignore_mtime : 1;            \
     unsigned short staticpattern : 1;           \
-    unsigned short need_2nd_expansion : 1
+    unsigned short need_2nd_expansion : 1;      \
+    unsigned short ignore_automatic_vars : 1

 struct dep
   {
diff --git a/src/file.c b/src/file.c
index c20fcf8..f624836 100644
--- a/src/file.c
+++ b/src/file.c
@@ -442,17 +442,41 @@ remove_intermediates (int sig)
 struct dep *
 split_prereqs (char *p)
 {
-  struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL,
+  struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE|MAP_DEP, NULL,
                                     PARSEFS_NONE);

-  if (*p)
+  if (*p == '<')
+    {
+      /* Files that follow '<' are "dependency-only" prerequisites that do not
+         contribute to the automatic variables $^, $+, $*, $? and their
+         $(xF) and $(xD) counterparts.  */
+      struct dep *dod;
+
+      ++p;
+      dod = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, PARSEFS_NONE);
+
+      if (! new)
+        new = dod;
+      else
+        {
+          struct dep *dp;
+          for (dp = new; dp->next != NULL; dp = dp->next)
+            ;
+          dp->next = dod;
+        }
+
+      for (; dod != NULL; dod = dod->next)
+        dod->ignore_automatic_vars = 1;
+    }
+
+  if (*p == '|')
     {
       /* Files that follow '|' are "order-only" prerequisites that satisfy the
          dependency by existing: their modification times are irrelevant.  */
       struct dep *ood;

       ++p;
-      ood = PARSE_SIMPLE_SEQ (&p, struct dep);
+      ood = PARSE_FILE_SEQ (&p, struct dep, MAP_DEP, NULL, PARSEFS_NONE);

       if (! new)
         new = ood;
@@ -468,6 +492,32 @@ split_prereqs (char *p)
         ood->ignore_mtime = 1;
     }

+  if (*p)
+    {
+      /* Files that follow '<' and '|' are "dependency-only" and "order-only" prerequisites,
+         their modification times are irrelevant and they do not contribute to the automatic variable $|.  */
+      struct dep *ood_dod;
+
+      ++p;
+      ood_dod = PARSE_SIMPLE_SEQ (&p, struct dep);
+
+      if (! new)
+        new = ood_dod;
+      else
+        {
+          struct dep *dp;
+          for (dp = new; dp->next != NULL; dp = dp->next)
+            ;
+          dp->next = ood_dod;
+        }
+
+      for (; ood_dod != NULL; ood_dod = ood_dod->next)
+        {
+          ood_dod->ignore_automatic_vars = 1;
+          ood_dod->ignore_mtime = 1;
+        }
+    }
+
   return new;
 }

diff --git a/src/main.c b/src/main.c
index afc7fd9..c3fe228 100644
--- a/src/main.c
+++ b/src/main.c
@@ -637,6 +637,7 @@ initialize_stopchar_map (void)
   stopchar_map[(int)'='] = MAP_EQUALS;
   stopchar_map[(int)':'] = MAP_COLON;
   stopchar_map[(int)'|'] = MAP_PIPE;
+  stopchar_map[(int)'<'] = MAP_DEP;
   stopchar_map[(int)'.'] = MAP_DOT | MAP_USERFUNC;
   stopchar_map[(int)','] = MAP_COMMA;
   stopchar_map[(int)'('] = MAP_VARSEP;
diff --git a/src/makeint.h b/src/makeint.h
index dd6e894..2d38efc 100644
--- a/src/makeint.h
+++ b/src/makeint.h
@@ -402,6 +402,7 @@ extern int unixy_shell;
 #define MAP_PIPE        0x0100
 #define MAP_DOT         0x0200
 #define MAP_COMMA       0x0400
+#define MAP_DEP         0x0800

 /* These are the valid characters for a user-defined function.  */
 #define MAP_USERFUNC    0x2000
_______________________________________________
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make

Reply via email to