I need pointing what I'm missing about makefiles. For given makefile:
VPATH=
targ1: VPATH=src
targ1: targ2
targ2: targ2
echo $(VPATH)
and empty src direcotry, every time calling "make targ1" I get as expected:
echo src
src
since there is not file targ2 in makefile directory and in src direcotry targ2 needs to be updated.
But the problem is that even when I create targ2 file in src directory targ2 is updated every time of calling 'make targ1'. In that case VPATH is not working as expected.
The value of the make variable VPATH specifies a list of directories that make should search. Most often, the directories are expected to contain prerequisite files that are not in the current directory; however, make uses VPATH as a search list for both prerequisites and targets of rules.
Howewer problem does not occure when I set VPATH in global scope:
VPATH=src
targ1: VPATH=src
targ1: targ2
targ2: targ2
echo $(VPATH)
Result is: make: Nothing to be done for 'targ1'.
Why there is such difference?
As with automatic variables, [target-specific] values are only available within
the context of a target’s recipe...
So in your first example, the value you gave to VPATH is not available to Make to find the prerequisite targ2.
Related
I have a directory tree like this with some "shared targets" in the file rules.Makefile:
├── Makefile
├── rules.Makefile
└── my_subdir
└── Makefile
I would like to invoke these "shared targets" in both the Makefile(s) in the parent directory and the child directory.
Also the "custom targets" in the Makefile in the child directory should be callable from the Makefile in the parent directory.
For some reason I am able to call the targets in rules.Makefile only from the sibling Makefile (the one in the parent directory). When using relative paths in the Makefile in the child directory trying to access the rules.Makefile in the parent directory I get some errors.
The content of the Makefile in the parent directory:
RULES_MAKEFILE_PATH=$(PWD)/rules.Makefile
include $(RULES_MAKEFILE_PATH)
foo-parent:
#echo $(RULES_MAKEFILE_PATH)
The content of the Makefile in the child directory (please note that double dot ..):
RULES_MAKEFILE_PATH=$(PWD)/../rules.Makefile
include "$(RULES_MAKEFILE_PATH)"
foo-child:
#echo $(RULES_MAKEFILE_PATH)
When calling from the parent directory make foo-parent then I see the expected path.
When calling from the child directyr make foo-child then I see this error:
$ make foo-child
Makefile:9: "/<PARENT_PATH>/my_subdir/../rules.Makefile": No such file or directory
make: *** No rule to make target '"/<PARENT_PATH>/my_subdir/../rules.Makefile"'. Stop.
How can I make the relative paths work in the "child directory"?
Also how can I call the targets defined in the Makefile in child directory (e.g. foo-child) from the Makefile in the parent directory?
Well first, $(PWD) is not a special variable to make. It's just a normal variable, that's imported from your shell. So it will always have the same value everywhere in your makefile and in all included makefiles, it won't change just because you're including a makefile from a different directory.
Second, even for $(CURDIR) (which is a special variable and is set by make to be the current directory when make starts), it is never reset when you include a makefile from another directory.
And, all paths in include lines are evaluated based on the directory make was in when it started, not on a path relative to the currently-parsed makefile. So if Makefile includes foo/Makefile, then foo/Makefile has an include bar.mk, make will look for bar.mk not foo/bar.mk.
The point about $(PWD) above is true. However, if that is not a concern, you could still use the shell function to execute commands to get paths of another Makefile to include: $(shell pwd)
I did something similar for a project that benefited from having the same Makefile used in many places, using git rev-parse --show-toplevel.
MAKEFILE := $(shell git rev-parse --show-toplevel)/makefiles/example.def
include $(MAKEFILE)
I read this: Makefile: Copying files with a rule but couldn't do it.
To make it simple, suppose I have two directories dir1 and dir2. Under dir1 I have three files: rabbit.c, tiger.c and bus.c .
I made Makefile like this:
dir2/rabbit.c:dir1/rabbit.c
dir2/tiger.c:dir1/tiger.c
dir2/bike.c:dir1/bike.c
dir2/%:
cp -f $< $#
I specified the prerequisites in three separate lines and specified the unified recipe for the three targets. I expected when I touch any file under dir1, make will copy that file to dir2. But this happend only for rabbit.c. What is wrong?
ADD(after selecting an answer) :
After realizing what's wrong by Takkat's answer, I fixed it and later modified it further and I think this is the correct simplest Makefile for this case.
.PHONY:all
LIST:=rabbit.c tiger.c bike.c
DSTFILES:=$(addprefix dir2/, $(LIST))
all: $(DSTFILES)
dir2/%:dir1/%
cp -f $< $#
Make chooses a default target in your makefile and, unless you specify differently on the command line, it builds just that target (and all prerequisites required to build that target).
The default target in a makefile is, by default, the first explicit target listed.
So in your makefile the first rule is:
dir2/rabbit.c:dir1/rabbit.c
so the first explicit target is dir2/rabbit.c, so that's all make builds.
If you want to build multiple targets by default, you need a first target that lists all the "real" targets as prerequisites; put this line first in your makefile:
all: dir2/rabbit.c dir2/tiger.c dir2/bike.c
and it will work. It's often considered good practice to declare targets like this, which don't relate to real files on the disk, as phony:
.PHONY: all
Consider the following Makefile which knows to clean and rebuild itself if the Makefile or its included configuration files config.mk or local.mk are changed:
include config.mk
-include local.mk
-include dummy.rebuild
all: ...
# other targets...
# https://stackoverflow.com/a/3892826/149138
dummy.rebuild: Makefile config.mk local.mk
touch $#
$(MAKE) -s clean
This works fine if config.mk and local.mk actually exist - if either is modified, the dummy.rebuild target fires and the project is rebuild.
However, imagine that local.mk is an optional file which may or may not exist. In the case that it doesn't exist, the dummy.rebuild rule never seems to run at all, even if the Makefile or config.mk is changed. This is different behavior than a normal rule where a dependency doesn't exist, usually you'd get an error like:
make: *** No rule to make target 'local.mk', needed by 'dummy.rebuild'. Stop.
... but in the case of the dummy.rebuild target implicitly added as a target via inclusion, you just get:
make: Nothing to be done for 'all'.
How can I implement the makefile so that if any of Makefile, config.mk or local.mk are changed, the dummy.rebuild target is executed, where the local.mk file may not exist?
I'm not entirely sure what you're trying to do, but maybe using this instead will give you the behavior you want:
local.mk := $(wildcard local.mk)
include $(local.mk)
...
dummy.rebuild: Makefile config.mk $(local.mk)
...
Using wildcard here expands to local.mk if the file exists, or the empty string if it doesn't exist so it will be ignored in all ways if it's not there.
I'm using Automake.
I have a few source files listed in dist_man1_MANS like this:
dist_man1_MANS = some-file.1 some-other-file.1
Now, Automake + configure eventually generate this in Makefile:
dist_man1_MANS = some-file.1 some-other-file.1
# ...
install-man1: $(dist_man1_MANS)
# generated recipe here
Since I'm not prefixing the .1 files with $(srcdir), I assume that, since I run make from the build directory (its current working directory), it should find them in the build directory.
So, I'm doing an out-of-tree build, for example, in /tmp/build:
/path/to/src/configure --prefix=$(pwd)/install
make
make install
and the build succeeds, that is, make finds the man pages and installs them. They are not in the build directory, however. I add this to the generated Makefile:
install-man1: $(dist_man1_MANS)
#echo ">>> $(^)"
#echo "::: $(dist_man1_MANS)"
# generated recipe here
Now, I would assume that both echos print the same thing, because $^ means the names of all the prerequisites, with spaces between them. To my surprise, the output is:
>>> /path/to/src/some-file.1 /path/to/src/some-other-file.1
::: some-file.1 some-other-file.1
So:
How did make find the /path/to/src/ prefix exactly? Where does it come from in this very context?
Why do $^ and $(dist_man1_MANS) differ?
I found the answer.
Automake sets the VPATH variable in its generated Makefile, a special variable for make, to something like:
VPATH = /path/to/src
From the previous links:
4.5.1 VPATH: Search Path for All Prerequisites
The value of the make variable VPATH specifies a list of directories that make should search. Most often, the directories are expected to contain prerequisite files that are not in the current directory; however, make uses VPATH as a search list for both prerequisites and targets of rules.
So make searches for the some-file.1 and some-other-file.1 prerequisites in the current working directory first, then for /path/to/src/some-file.1 and /path/to/src/some-other-file.1 if it cannot find the first ones. In this case I understand why $^ is different from $(dist_man1_MANS): $^ is the list of effective (resolved) prerequisites.
I have a makefile that depending on some properties sets vpath and generates a list of source files into one variable. I need to run the makefile without compiling anything (the compilation is actually handled by a different makefile) and just see to which real files the filenames get matched depending on the vpath settings.
Option 1: Let make do its path search:
.PHONY: whichfiles
whichfiles: $(LIST_OF_SOURCE_FILES)
#echo $+
Option 2: Simulate the path search using $(wildcard):
.PHONY: whichfiles
whichfiles:
#echo $(foreach f,$(LIST_OF_SOURCE_FILES),$(firstword $(wildcard $(VPATH:%=%/$f)) not-found:$f))
Either way, "make whichfiles" will print the list of matched files.
If some of the files can't be found, option 1 will fail with "no rule to make" reporting the first file that could not be found. Option 2 will print "not-found:" for each missing file.