0
votes

How do I create non-dependent phony targets in a GNU Makefile?

Requirements:

  1. A rule that checks for a specific setup - can be more complex than example below.
  2. If this rule fails, building of specific targets should fail.
  3. If this rule succeeds, building of specific targets should be done only if their sources are modified.
  4. The rule cannot be global, since that rule should not even be executed for non-specific targets

This is achievable if the rule is inserted before the compile rule of every specific target. Since they might be many specific targets, I prefer creating a phony target for this rule, and specify this phony target as a dependency for all those specific targets. This has an unwanted side effect that, when the phony target succeeds, those specific targets are rebuilt even when their sources are not modified.

In other words, how do I specify a phony target to NOT force dependent target to be rebuilt if their source are up-to-date.

$ make --version | grep Make
GNU Make 3.82

$ make -f try.mk clean setup
rm -f try.out?
touch try.c #Dummy create source

$ make -f try.mk
touch try.out1 #Dummy compile
touch try.out2 #Dummy compile
touch try.out3 #Dummy compile

$ make -f try.mk
touch try.out3 #Dummy compile

try.out3 should NOT have got compiled in the above/last make.

$ cat try.mk
#try.mk
base=try

all: $(base).out1 $(base).out2 $(base).out3 #...

clean:
    rm -f $(base).out?

setup:
    touch $(base).c #Dummy create source

.PHONY: all clean platform_ok

#------------------------------------------------------------
#Specific targets
#------------------------------------------------------------

#Attempt 1: works, but platform check is a rule, and hence needs to be inserted wherever it is needed.
$(base).out1: $(base.c)
    @if [ $(shell uname -i) == x86_64 ]; then exit 0; else exit 1; fi
    touch $(base).out1 #Dummy compile

#Attempt 2: works, but platform check is global, which gets executed even when building Non-OS specific targets
$(eval platform_check:=$(shell (if [ $(shell uname -i) == x86_64 ]; then echo 0; else echo 1; fi)))
$(base).out2:  $(base).c
    @exit $(platform_check)
    touch $(base).out2 #Dummy compile

#Attempt 3: works partially when platform check is a phony target, but target gets rebuilt even if source is uptodate.
$(base).out3:  $(base).c platform_ok
    touch $(base).out3 #Dummy compile
platform_ok:
    @if [ $(shell uname -i) == x86_64 ]; then exit 0; else exit 1; fi

#------------------------------------------------------------
#Non-Specific targets
#------------------------------------------------------------
#...
2

2 Answers

2
votes

Simply use a phony target as order-only prerequisite. Make will always execute this rule if it is found in the dependency graph, but the targets depending on it will only be executed if their normal prerequisites are more recent:

base=try

all: $(base).out1 $(base).out2 $(base).out3 #...

clean:
    rm -f $(base).out?

setup:
    touch $(base).c #Dummy create source

.PHONY: all clean platform_ok

#------------------------------------------------------------
#Specific targets
#------------------------------------------------------------

$(base).out1: $(base).c | platform_ok
    touch $(base).out1 #Dummy compile

$(base).out2:  $(base).c | platform_ok
    touch $(base).out2 #Dummy compile

$(base).out3:  $(base).c | platform_ok
    touch $(base).out3 #Dummy compile

platform_ok:
    @if [ $(shell uname -i) == x86_64 ]; then exit 0; else exit 1; fi
0
votes

I would go a little different about it:

base=try
ARCH := $(shell test `uname -i` = "x86_64"; echo $$? )

ifeq ($(ARCH),0)
define PLATFORM_64 =
out3
endef
endif

define ALL =
out1
out2
$(PLATFORM_64)
endef

all: $(addprefix $(base)., $(ALL))

and I would loose platform_ok altogether:

$(base).out3: $(base).c
    touch $(base).out3 #Dummy compile