thomie
thomie

Reputation: 1434

GNU make: add a file as a dependency only if it doesn't exist yet

GNU make has the following option to avoid recompilation:

   -o file, --old-file=file, --assume-old=file
        Do not remake the file file even if it is older than  its  dependen‐
        cies,  and  do  not  remake  anything on account of changes in file.
        Essentially the file is treated  as  very  old  and  its  rules  are
        ignored.

So given the following Makefile:

A : B
    touch A
B : C
    touch B
C :
    touch C

Assuming all files exist at some point, I can run the following commands:

$ touch C
$ make A -o B
make: `A' is up to date.     # Good. C is out-of-date, but A does not get updated.

Question

How can I change my Makefile such that B is always assumed old, but only when rebuilding A?

A : <WHAT_GOES_HERE> B
    touch A
B : C
    touch B
C :
    touch C

I'm specifically looking for the following results:

Result 1: when no files exist yet, make A should create all of them, as before.

$ make A
touch C
touch B
touch A

Result 2: when C is out-of-date, make B should update B, as before. This means we can't have an order-only dependency between B and C (i.e. B : | C). Assuming all files exist again:

$ touch C
$ make B
touch B    # Good. Don't loose this property.

Result 3: when C is out-of-date, make A should be a no-op, without extra flags necessary.

$ touch C
$ make A
make: `A' is up to date.

Upvotes: 5

Views: 1906

Answers (2)

bobbogo
bobbogo

Reputation: 15483

In other words, when deciding whether to rebuild A, make should ignore the timestamp of B. In other words, B is not a pre-requisite of A. Just leave B off in A's dependency line.

Reading your answer though, it appears that you want to build B iff it doesn't already exist.

A: $(if $(wildcard B),,B)
    ⋮

Upvotes: 8

thomie
thomie

Reputation: 1434

Here is one solution. Check if B exists explicitly, and call make recursively if it doesn't:

A :
    @if [ ! -f B ]; \
        then $(MAKE) --no-print-directory B && echo touch A && touch A; \
    fi
B : C
    touch B
C :
    touch C

It works, but I was hoping for a solution using only Makefile directives, no shell script.

$ make A
touch C
touch B
touch A
$ touch C
$ make B
touch B
$ touch C
$ make A
make: `A' is up to date.

Upvotes: 0

Related Questions