[Top][All Lists]

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

Re: Feature request / patch: dependency-only prerequisites

From: Martin Dorey
Subject: Re: Feature request / patch: dependency-only prerequisites
Date: Fri, 5 Jul 2019 21:44:15 +0000

The target certainly also depends on the compiler frontend, the linker backend and the Makefile itself

It's unimaginable that it doesn't depend on compiler libraries and myriad compiler-provided header files too.  Using header files in a compilation example would make the $(filter ...) solution less tenable, strengthening your case.  Sadly, though, adding all these things to the dependency list won't really help me.  We installed this system just three days ago, yet the mtime on stdio.h is months ago: 

devadmin@ch-ep1-3:~$ ls -l /usr/include/stdio.h
-rw-r--r-- 1 root root 31494 Feb  6 21:17 /usr/include/stdio.h

That dates from when upstream built the package that included it:

If you decide to press on, then I have three minor suggestions:

the newly introduced GNU Make’s $(filter ) function

The revision history for make.texi shows that $(filter) was added some three decades ago:

address@hidden            9f8301ae1ac6d9076e38ec86f12d59ba40b851bd:Revision 1.2  1988/04/23 16:16:04  roland
address@hidden            9f8301ae1ac6d9076e38ec86f12d59ba40b851bd:* Added the `filter', `filter-out', `strip' and `join' expansion functions.

https://www.gnu.org/software/make/manual/html_node/Features.html#Features suggests that this function was an innovation of GNU make, true, but I found "newly introduced" misleading.  I'm a native English speaker.

gcc -o $ $(filter %.o, $^)

You've put a space after the comma.  I wouldn't do that in a Makefile, though I would in every other programming language.  https://www.gnu.org/software/make/manual/html_node/Text-Functions.html#Text-Functions mostly wouldn't have that space either.  $(filter) is one of those word-oriented functions where I don't think it would matter, but it's easier to have simple rules of thumb that keep you safe.  One of the spaces after a comma here is important:

martind@swiftboat:~/tmp/warlich-2019-07-05$ cat Makefile
INPUT = a.o b.o
fn = $(1)
OUTPUT = $(call fn, $(filter-out %.o, $(INPUT)))
$(if $(OUTPUT),$(error :$(OUTPUT): is non-empty!))
martind@swiftboat:~/tmp/warlich-2019-07-05$ make
Makefile:4: *** : : is non-empty!.  Stop.



From: Bug-make <bug-make-bounces+martin.dorey=address@hidden> on behalf of Christof Warlich <address@hidden>
Sent: Thursday, July 4, 2019 10:13
To: address@hidden
Subject: Feature request / patch: dependency-only prerequisites
***** EXTERNAL EMAIL *****

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)

        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,


reply via email to

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