Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make ignoring Prerequisite that doesn't exist

make continues to build and says everything is up to date when my dependency files say an object depends on a header file that has moved.

If run make -d to capture the evaluation I see:

Considering target file `../build/out/src/manager.o'.
     Looking for an implicit rule for `../build/out/src/manager.o'.
     No implicit rule found for `../build/out/src/manager.o'.
      Pruning file `../product/build/config/product.conf'.
      Pruning file `../build/out/opt_cc.txt'.
      Considering target file `../mem/src/manager.c'.
       Looking for an implicit rule for `../mem/src/manager.c'.
       No implicit rule found for `../mem/src/manager.c'.
       Finished prerequisites of target file `../mem/src/manager.c'.
      No need to remake target `../mem/src/manager.c'.
      Pruning file `../mem/mem.h'.
     Finished prerequisites of target file `../build/out/src/manager.o'.
     Prerequisite `../product/build/config/product.conf' is older than target `../build/out/src/manager.o'.
     Prerequisite `../build/out/opt_cc.txt' is older than target `../build/out/src/manager.o'.
     Prerequisite `../mem/src/manager.c' is older than target `../build/out/src/manager.o'.
     Prerequisite `../mem/mem.h' of target `../build/out/src/manager.o' does not exist.
../build/out/src/manager.o'.
     Prerequisite `../mem/mem_in.h' is older than target `../build/out/src/manager.o'.
    No need to remake target `../build/out/src/manager.o'.

So make knows the file is needed and is not there but doesn't attempt to create it from a rule or fail.

Prerequisite `../mem/mem.h' of target `../build/out/src/manager.o' does not exist.

Why is this and how can I get make to not ignore this rule?

like image 459
Oliver Avatar asked May 30 '14 22:05

Oliver


2 Answers

Most likely you have implemented an automatic dependency generation method that tells make to essentially ignore those files if they don't exist, by defining a target for that file without a rule. When I have this makefile:

foo: foo.h ; @echo make $@ from $^

And no foo.h then make tells me:

$ make
make: **** No rule to make target 'foo.h', needed by 'foo'.  Stop.

But, if I have this makefile:

foo: foo.h ; @echo make $@ from $^
foo.h:

Now make is perfectly happy:

$ make
make foo from foo.h

That's a documented behavior that many auto-dependency generation utilities rely on: if you look in your generated dependency makefiles you'll see one of those empty targets for every header file.

The idea is that given correct dependency information there should never be a way to rename or delete a header file without modifying some other source or header file, which would cause the object file to be rebuilt anyway (hence recreating the dependency information correctly for the next time).

like image 163
MadScientist Avatar answered Sep 30 '22 14:09

MadScientist


The fix I discovered is to use static pattern rules instead of pattern rules. Pattern rules look like this:

%.o : %.c
    *recipe here*

Static pattern rules only apply to an explicit list of target files like this:

$(OBJECTS): %.o: %.c
    *recipe here*

where the variable OBJECTS is defined earlier in the makefile to be a list of target files (separated by spaces), for example:

OBJECTS := src/fileA.c src/fileB.c src/fileC.c

Note that you can use the various make utility functions to build that list of target files. For example, $(wildcard pattern), $(addsuffix), etc.

You don't show the relevant parts of your makefile, so I can't be sure this will fix your situation. But I was getting the same symptoms of make ignoring non-existant prerequisites, and the same message from make -d about "Prerequisite does not exist" but then make does nothing to create the prerequisite.

Note that make contains about 90 built-in implicit rules, most of which are pattern rules. So even if your makefile has no pattern rules, this could still be affecting you.

I noticed a few things:

  1. Asking to explicitly make the prerequisite works. This shows that make knows how to build the prerequisite.

  2. Adding an explicit target statement (not using a pattern rule) for a particular file seemed to solve the problem. (But of course only for that one target... writing a rule for each of 100's of targets is unworkable).

  3. In my research I kept encountering statements about how make's behavior differs if there is an explicit target or not.

  4. Turning off the implicit rules database with make -r did not help.

My guess why this works is that static pattern rules are a form of explicit target statements for the entire list of targets.

For the particular case that I was investigating, the target file already exists, and the (non-existant) prerequisite is not actually needed to build the target, it is only needed at runtime. So perhaps make is correct about not needing to build the prerequisite in order to build the target. If you are only asking to build the target, then make will do the minimum necessary to accomplish that.

It still seems like a bug in make. But it's probably just a mis-understanding on my part, I'm no make expert.

Update: (March 16, 2016). My current understanding is that make regarded these prerequisite files as intermediate files and therefore does not care about creating them when the target file already exists. Make treats intermediate files as "second class citizens", it only makes them when needed for creating the "first class citizens" which are the explicit target defined in the makefile, or goals requested as arguments to make on the command line.

By using static pattern rules (instead of pattern rules) those files now are listed as explicit targets and are therefore not intermediate files but are "first class citizens" which are created and updated whenever necessary.

BTW, this also explains why using .SECONDARY with no prerequisites doesn't help. Doing that prevents intermediate files from being deleted, but they are still regarded as intermediate so make will not create them unless they are needed to make a target or goal.

like image 45
owler Avatar answered Sep 30 '22 13:09

owler