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