How should you use .PHONY in included Makefiles? - makefile

Say I have a set of Makefile modules:
# foo.mk
rule1: prereq1
recipe1
and
# bar.mk
rule2: prereq2
recipe2
and a primary Makefile:
# Makefile
include foo.mk
include bar.mk
Should .PHONY: be included in each individual .mk file for the phony targets just in that file, or should there be some acculmulated list that is included only in the primary Makefile?
# foo.mk
TARGETS += rule1
...
# bar.mk
TARGETS += rule2
...
# Makefile
.PHONY: $(TARGETS)
I didn't find anything relevant in the GNU Make docs or similar questions.

The statement
.PHONY: rule1
tells Make that it should not consider "rule1" the name of a file to be built. Suppose you put it in the Makefile. What happens when you run another makefile, either foo.mk or a makefile that includes it?
When you run the rule1 rule, do you want Make to treat it as a PHONY target? If your answer isn't "that depends on which makefile I'm using", then you should have the statement in the makefile that defines the rule.

As with other targets, you can add to .PHONY multiple times cumulatively. So giving each file its own .PHONY is can be a nice way of keeping things compartmentalized.

Related

Remove duplication in a Makefile: Target files are written once under Phony variable `all` and again as recipe targets

Below I have copied an example of a Makefile for executing some scripts to clean and merge data.
This Makefile format requires me to list each target file twice: once under all and once as the target of each recipe. As the makefile gets long I sometimes forget to add new targets to all after creating a new recipe.
Without an all variable Make will only build the first target and its prerequisites.
How can I remove this source of duplication from my Makefile and still have all recipe targets checked and rebuilt if their prerequisites change?
DIR_DATA = ./data
DIR_RAW = $(DIR_DATA)/raw
DIR_MUNGE = ./munge
VPATH = $(DIR_RAW) $(DIR_DATA) $(DIR_MUNGE)
########################################################
####################### Recipes ########################
########################################################
ds_mtcars.rds: ds_mtcars.R ds_mt_raw.csv
Rscript $<
ds_mt_agg.rds: ds_mt_agg.R ds_mtcars.rds
Rscript $<
ds_mt_temp.rds: ds_mt_temp.R ds_mtcars.rds ds_mt_agg.rds
Rscript $<
########################################################
####################### Phony vars #####################
########################################################
.Phony: all
all: ds_mtcars.rds ds_mt_agg.rds ds_mt_temp.rds
clean:
rm -f ./data/*.rds
Often, you can avoid such duplication by using patterns and lists. In your case, because the dependencies do not seem to follow a simple pattern, you have to explicitly define any unique dependencies associated with a file. Assuming that each .rds depends on the corresponding .R file, you could eliminate some of the duplication using a static pattern rule as follows:
RDS_FILES := ds_mtcars.rds ds_mt_agg.rds ds_mt_temp.rds
all:
# define any unique dependencies explicitly:
ds_mtcars.rds: ds_mt_raw.csv
ds_mt_agg.rds: ds_mtcars.rds
ds_mt_temp.rds: ds_mtcars.rds ds_mt_agg.rds
# use Static pattern rule --
# explicit dependencies will be stacked
$(RDS_FILES) : %.rds : %.R
Rscript $<
.Phony: all
all: $(RDS_FILES)
You would still have to list each target with special dependencies in both the starting list (RDS_LIST), and in the special dependency rules.

Explicitly make a target with a variable name

I have a Makefile with the following format:
.PHONY: all
target1 := file1
target2 := $(target1).txt
all: $(target2)
$(target1): prerequisite1
recipe
$(target2): $(target1)
recipe
target2 depends on target1, and make will correctly substitute the strings to create the file names. However, on my system, the file names and paths are quite tedious to type out; I'm wondering if there is any
way to specifically make target1 while referring to its name not as the file path, but as the variable.
For example, I would like to be able to invoke:
$ make $(target1)
rather than
$ make path/to/file1
I want to do this because I change the variables quite a bit and the structure of my Makefile has many intermediates that are occasionally difficult to trace back to their literal file paths, but are easy to make based on the variable names that I have assigned them.
The above does not work, and I have read the man page as well as done quite a bit of searching here and on Google. Just wondering if anyone has come across this problem before and found a solution.
This is a bit clunky to due use of recursion, but it does what you want:
target1 := file1
$(target1):
#echo "Hello from $#"
variable-%:
$(MAKE) $($*)
gives
$ make variable-target1
make file1
Hello from file1
That's what phony targets are for. A phony target is a target that isn't the name of an output file. Often, the default target (that's whatever target appears first in the Makefile) is phony and by convention called all. So just modify your Makefile to something like this:
.PHONY: all target1 target2
target1 := file1
target2 := $(target1).txt
# phony rules with dependencies
all: target2
target2: $(target2) target1
target1: $(target1)
# file rules with prerequisites
$(target1): prerequisite1
recipe
$(target2):
recipe
As a "best practice", list the dependencies that aren't directly used for creating the real targets in the prerequisite list of the phony targets and the dependencies that are indeed input files in the prerequisite list of the actual file targets.
Note this will work without declaring the targets in .PHONY as long as there's not by accident a file with the name of the phony target. Such a file would confuse make, therefore always list all your phony targets in .PHONY, so make knows they don't produce a file of their name.

Makefile dependency-iterating generic rule

I've been looking through makefile syntax manuals and haven't found anything that really helps the usage case I'm trying to enact here.
What I have is a list of source files with varying directories under a common directory, like so:
src/a.h
src/b.h
src/dir/c.h
src/dir/dir/d.h
and would like make to use these individually as a dependency for a rule that ultimately creates:
build/a.h
build/b.h
build/c.h
build/d.h
which then are used as dependencies individually for more rules.
What I have so far:
LIST := src/a.h src/b.h src/dir/c.h src/dir/d.h
all : $(addprefix build/,$(notdir ${LIST}))
#echo 'All rule invoked'
What doesn't work:
$(LIST) : build/$(notdir %).h : %.h
#echo 'dst $* dat $# din $<'
target 'item' doesn't match the target pattern
build/%.h: %.h
no rule to make target 'build/a.h' needed by 'all'.
I'm guessing make got mad at me at this point, as the errors started telling me to stop.
Basically, I am reading in a list of files with a path prefix that is relevant for the search path and dependency, and want to dump each individual one only when the source file is updated. After this, these files in that single directory are used as dependencies for another batch of rules. How can I accomplish this?
Note: I've gotten it done by ignoring the dependency chain, but that's not going to work. I can also use make to run scripts that generate an explicit makefile that can do it properly, but that feels like overkill and a waste of resources, and make ought to be able to create a rule that does that by itself, as powerful as it is. I just don't know how to create generic rules that focus on the dependency variable for its text matching, rather than the target.
There's no good way of using a pattern rule here, as all the headers are (potentially) in different directories and you want to move them out to a common directory. If you're using GNU make, you can write a macro rule that expands to all the rules you need:
define copy_header_rule
build/$(notdir $(1)): $(1)
cp $$< $$#
endef
$(foreach hdr,$(LIST),$(eval $(call copy_header_rule,$(hdr))))
This goes through each of the headers in your $(LIST) a creates a rule to copy it to the build directory
You can make things pretty simple with vpath:
TARGS:= $(addprefix build/, $(notdir $(LIST)))
vpath %.h $(dir $(LIST))
all: $(TARGS)
build/%.h: %.h
#echo building $# from $<
...

make implicit rule with force vs .phony

Can someone shed light on the difference here:
$(tsdir)/proj has prerequisites $(tsdir)/proja and $(tsdir)/projb. I want proja's and projb's makefile to be called every time I have to build proj. If proja or projb are out of date and are updated, then their makefile will touch $(tsdir)/proja and $(tsdir)/projb respectively. If those files are then newer than $(tsdir)/proj, then rebuild proj.
I have this working by using the below code and the FORCE target. If I try and switch to use .PHONY targets, this doesn't work. I prefer .PHONY as that is supposedly the more 'correct' way of doing this. But it doesen't work and I don't know why. proja's and projb's makefiles aren't called with .PHONY targets, but proj is rebuilt.
I am using GNU make 3.81.
Thanks
Nachum
$(tsdir)/proj: $(tsdir)/proja $(tsdir)/projb
...
$(tsdir)/%: FORCE
make -C $(prereqdir)/$*
FORCE:
#or
$(tsdir)/proj: $(tsdir)/proja $(tsdir)/projb
...
.PHONY: $(addprefix $(tsdir)/, $(projects))
$(tsdir)/%:
make -C $(prereqdir)/$*
.PHONY targets are supposed to represent tasks, not real files, where implicit rule search works only for files. Thus, there is no way to build a phony target with an implicit rule.
From Phony Targets chapter:
Since it knows that phony targets do not name actual files that could be remade from other files, make skips the implicit rule search for phony targets
In your case I would just use explicit rule, may be with a static pattern:
.PHONY: $(addprefix $(tsdir)/, $(projects))
$(addprefix $(tsdir)/, $(projects)) : $(tsdir)/% :
make -C $(prereqdir)/$*
I suspect you can get the result you want by adding a phony dependency to the (real) time-stamp files, one removed from the master project proj.
.PHONY: phony
phony: ; : $#
ts := $(addprefix $(tsdir)/, $(projects))
${ts} : $(tsdir)/%: phony
make -C $(prereqdir)/$*
$(tsdir)/proj: $(tsdir)/proja $(tsdir)/projb
...

making all rules depend on the Makefile itself

When I change a Makefile, its rules may have changed, so they should be reevaluated, but make doesn't seem to think so.
Is there any way to say, in a Makefile, that all of its targets, no matter which, depend on the Makefile itself?
(Regardless of its name.)
I'm using GNU make.
This looks like one more simple, useful, logical thing that Make should be able to do, but isn't.
Here is a workaround. If the clean rule is set up correctly, Make can execute it whenever the makefile has been altered, using an empty dummy file as a marker.
-include dummy
dummy: Makefile
#touch $#
#$(MAKE) -s clean
This will work for most targets, that is targets that are actual files and that are removed by clean, and any targets that depend on them. Side-effect targets and some PHONY targets will slip through the net.
Since GNU make version 4.3 it is now possible with the use of those two special variable:
.EXTRA_PREREQS
To add new prerequisite to every target
MAKEFILE_LIST
To get the path of the make file
To have every target depend on the current make file:
Put near the top of the file (before any include since it would affect the MAKEFILE_LIST) the following line:
.EXTRA_PREREQS:= $(abspath $(lastword $(MAKEFILE_LIST)))
To have every target depend on the current make file and also the make files which were included
Put the following line at the end of your file:
.EXTRA_PREREQS+=$(foreach mk, ${MAKEFILE_LIST},$(abspath ${mk}))
The only answer I know to this is to add makefile explicitly to the dependencies. For example,
%.o: %.c makefile
$(CC) $(CFLAGS) -c $<

Resources