Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GNU Make: Ensure existence of prerequisite and disable implicit rule search

Question:

How can I disable implicit rule searches on a prerequisite while still ensuring that the prerequisite actually exists?

Background:

Consider the following initial Makefile:

b: a
    @echo MAKING B
    cp a b

a is a file which is required in order to make b. If the file a exists, make b runs successfully. If it doesn't exist, we obtain the following error:

make: *** No rule to make target `a', needed by `b'.  Stop.` 

This is exactly what we expected, however on inspecting the output of make --debug=a b, we see that even when a exists, make is searching through pre-defined implicit rules fitting a in order to see whether it can be re-made. For example, if the file a.c happened to exist, then make would try to compile a.c to produce the file a. To prevent this, we define an explicit rule for a with an empty recipe. This gives us the updated Makefile:

a: ;

b: a
    @echo MAKING B
    cp a b

The problem now is that the recipe for make b runs even if a does not exist, which results in a failure. Is there any other way to indicate that a should exist, while not searching for implicit rules to build a? I would like to do this without giving a recipe for a which checks its existence.

like image 459
justinpc Avatar asked Jan 13 '19 19:01

justinpc


People also ask

What is implicit rules in makefile?

Implicit rules tell make how to use customary techniques so that you do not have to specify them in detail when you want to use them. For example, there is an implicit rule for C compilation. File names determine which implicit rules are run.

What is GNU Make in Linux?

GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files. Make gets its knowledge of how to build your program from a file called the makefile, which lists each of the non-source files and how to compute it from other files.

How does GNU Make work?

GNU Make is a program that automates the running of shell commands and helps with repetitive tasks. It is typically used to transform files into some other form, e.g. compiling source code files into programs or libraries. It does this by tracking prerequisites and executing a hierarchy of commands to produce targets.

Does ordering matter in makefile?

The order of rules is not significant, except for determining the default goal: the target for make to consider, if you do not otherwise specify one. The default goal is the target of the first rule in the first makefile. If the first rule has multiple targets, only the first target is taken as the default.


1 Answers

I'll try to sum up state of our discussion so far. Perhaps someone still pop's up with another/better insight.

Besides the option also mentioned in the question itself (see bellow for explainer on latest iteration for this approach):

a:
        $(error missing file "$@")
b: a
        @echo MAKING B
        cp a b

In theory it should be possible to disable implicit pattern rule altogether or for specific (set) of target(s) by either defining a no recipe target rule (% : %.c) or defining a static pattern rule (a: % : %.c). Nonetheless the resulting behavior, in case there is an a.c file, seems to be the same as with an empty rule for a:. I.e. make b just proceeds without file a being present (and we'd later fail trying to access it).

Since at least some of the implicit rule seem to be implemented as suffix rules, it's possible to disable consideration of inputs like a.c by purging list of default suffices:

.SUFFIXES:

Or inhibit use of implicit built-in rules altogether by invoking make with -r (or --no-builtin-rules) option. These however are rather heavy handed as they impact processing of all the rules across the Makefile.


To work the comment in:

as mentioned disabling couple of the built in rules for C compilation would appear to yield the desired result, namely:

% : %.c
% : %.o

Would result with a.c present and no a in make: *** No rule to make target 'a', needed by 'b'. Stop.

However (like -r) it's rather intrusive as in all other targets relying on the implicit rule would be impacted. While at the same time it's not as very far reaching, because it does not cover other cases like a.C, a.cpp, a,v,...

Static rule should be able to replace pattern rules where applicable (a more specific rule being applied over the more generic one when matching). But indeed limiting its to a single target does basically put it on par with just a specific a: rule.

I am actually not sure what the rest of the tree looks like and what all possible build steps could occur. With current understanding I would still gravitate to explicit target with file existence check should files with colliding names be a possibility and concern.


Explanation for the latest version of simple failing rule:

As @Stein followed up on the topic, he actually very helpfully pointed out: Simple (always) failing rule for "building" a is perfectly sufficient. If a file of that name (a) exists, the rule for target a never gets to run its recipe. For the case the file is not there, we can just have a recipe that fails with an error message.

like image 187
Ondrej K. Avatar answered Sep 23 '22 00:09

Ondrej K.