Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

prevent order-only prerequisite from being rebuilt if out of date

Tags:

makefile

A collegue just came across this, and I thought I'd ask if there's any neat solution to the following problem: I have a GNU makefile:

a: | b
    touch $@
b:c
    touch $@
c:
    touch $@

Then I run:

~/tmp> make a
touch c
touch b
touch a
~/tmp> make a
make: `a' is up to date.
~/tmp> touch b
~/tmp> make a
make: `a' is up to date.
~/tmp> touch c
~/tmp> make a
touch b

It rebuilds b but not a if I touch c. Is there a way to NOT rebuild b if it is being invoked by an order-only prerequisite? ( in the real-life case b is a file with hundreds of dependencies, which may not be around when make a is invoked. I can't make b's prerequisites be order-only as that would break make b)

like image 357
John Avatar asked Nov 01 '22 00:11

John


1 Answers

The behavior is fully correct. You instructed make to ignore the tight dependency between a and b and depend only on b presence. Whilst a and c share a date dependency.

This is the difference between a: b and a: | b.


If one wants to investigate that case (or other make magic :) ):

Try the following, you'll see that make is keen and tells you what it is doing for b target:

% touch b
% LANG=C make -rd | awk '/^Considering/,/^$/ {print}'
Considering target file `a'.
  Considering target file `b'.
    Considering target file `c'.
     Finished prerequisites of target file `c'.
    No need to remake target `c'.
   Finished prerequisites of target file `b'.
   Prerequisite `c' is older than target `b'.
  No need to remake target `b'.
 Finished prerequisites of target file `a'.
 Prerequisite `b' is order-only for target `a'.      <--- "order-only"
No need to remake target `a'.

Now, add a tight dependency:

% echo "a:b" >> Makefile 

And compare results:

% touch b
% LANG=C make -rd | awk '/^Considering/,/^$/ {print}'
Considering target file 'a'.
  Considering target file 'b'.
    Considering target file 'c'.
     Finished prerequisites of target file 'c'.
    No need to remake target 'c'.
   Finished prerequisites of target file 'b'.
   Prerequisite 'c' is older than target 'b'.
  No need to remake target 'b'.
  Pruning file 'b'.
 Finished prerequisites of target file 'a'.
 Prerequisite 'b' is order-only for target 'a'.
 Prerequisite 'b' is newer than target 'a'.          <--- additional "date dependency"
Must remake target 'a'.
touch a                                              <--- 'a' is rebuilt
Putting child 0x1b09ec0 (a) PID 5940 on the chain.
Live child 0x1b09ec0 (a) PID 5940 
Reaping winning child 0x1b09ec0 PID 5940 
Removing child 0x1b09ec0 PID 5940 from chain.
Successfully remade target file 'a'.

I used make -r (no implicit rules) as this example doesn't use them and it's boring to read.

like image 162
levif Avatar answered Dec 19 '22 22:12

levif