implicit rule not run although its depedency is missing - makefile

I have a Makefile similar to this:
.PRECIOUS: do/%.build
do/%.install: do/%.build
touch $#
do/%.build:
touch $#
My intention is that all do/.install targets depend on the do/.build target, and that the rule for the build target is run if the stamp file for the build target is missing, and that the install target is run if the build stamp is newer. This works fine during the first run:
$ make do/foo.install
touch do/foo.build
touch do/foo.install
It also works fine if the build stamp is newer:
$ touch do/foo.build
$ make do/foo.install
touch do/foo.install
However, it doesn't work as intended if the install stamp is present and the build stamp is missing:
$ rm do/foo.build
$ make do/foo.install
make: `do/foo.install' is up to date.
The install target is not run. What should I do? Does this have something to do with the fact that I have to add the .PRECIOUS line to avoid the automatic deletion of the build stamp?
Regards,
Tino

From the manual:
"If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file [i.e inferred from a pattern rule], then make can leave well enough alone. It won't bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target."
There are a couple of ways to solve this problem, but I know of no really clean way. Do any other targets depend on the build or install files?

Related

make dependency on all files in a subdirectory (git submodule)

I want to write a (GNU) make rule that depends on the existence of some file (any arbitrary file) in a subdirectory. In my specific case, that subdirectory is a git submodule.
This is what I have:
DEP = submod/.git
$(DEP):
git submodule update --init $(#D)
submod/%: | $(DEP)
# # why do I need this?
install: submod/junk.c
echo installing
If I then type make install, the git command is run (change it to mkdir -p $(#D); touch $# for a non-git-specific test), and make doesn't complain.
I have two questions. Primarily, are there any side effects to the dummy recipe for submod/% I should be concerned about? Secondly, and more interestingly, why do I need that recipe at all? If I remove it, make errors out:
make: *** No rule to make target 'submod/junk.c', needed by 'install'. Stop.
My only hypothesis is that make is doing some optimization based on the files that exist at startup, and with the no-recipe version, it thinks that it can just expect the file to exist when it's needed, but with any recipe there, it can't do that optimization, and it reevaluates when it's needed. If that's true, is it a bug, or something that should be changed?

Make "keeps" the old modification-time, although it has changed

Given a makefile:
# Create the following sequence of files, in the following order: 1)'old' then 2)'all', finally 3)'new'.
$(shell touch 'old')
$(shell sleep 1)
$(shell touch 'all')
$(shell sleep 1)
$(shell touch 'new')
all: new
echo '$#'
# Let the modification-time of 'new', to be like 'old' ("older" than 'all').
new : phony
cp -p old new
.PHONY : phony
.INTERMEDIATE: new
Running, we get:
$ make -Wnew
cp -p old new
echo 'all'
all
rm new
Now, although all was older than the file new before parsing the build, things changed after Make finished building the new file, with the recipe cp -p old new, which basically copied the modification-time of old into new, hence: all is now "newer" than the file new.
Then, why does build the up-to-date file all, given, that running through its dependencies - after their respective build - we find that all modification-time is "after" that of its dependency "new".
Explanation of Effect of -Wnew
The -Wnew option tells make to assume that new has been modified and that we must update the targets of which it is a prerequisite. Regardless of what happens to the file new in our makefile make must update all of the targets new is a prerequisite of.
I have provided an explanation and demonstration, using your example, that make does not keep the old modification time but that it is the effect of the -Wnew option which causes make to rebuild all, below.
Process of Execution with -Wnew
So in executing make -Wnew make first reads your makefile and sees
all: new
echo '$#'
so it knows regardless of what happens to new later on it has to update the target all because we've specified the -Wnew option.
make then proceeds to execute your shell commands and creates the files old, all and new. It now traverses through your targets and prerequisites noting that phony does not exist so we must remake it. After making phony we then make new as its target phony is newer than it. This actually modifies new's modification time to be older than all. However, we specified -Wnew so regardless of what happened to new we've told make we want it to rebuild targets that have new as a prerequisite such as all. This is why make then proceeds to build all.
Demonstration That make Does Not Keep Old Modification Times
If we were to execute your example with make, (note no -Wnew option), the output would be
$ make
cp -p old new
Aha! make didn't update all. It realised that by remaking new the modification time of new changed and it is now older than all thus all is up to date and we can finish.

Make command using default target name 'Makefile'

Why is the following makefile using Makefile target?
Makefile1:
Initially I have the following makefile which worked as expected when invoked as make abc xyz -s.
%::
echo $#
I would get
abc
xyz
Makefile2:
Now after adding an empty rule named test.
%:: test
echo $#
test:
the following invocation
make abc xyz -s
results in
Makefile
abc
xyz
Why am I getting Makefile as my output even though I am giving only abc and xyz as targets? Thanks in advance.
Because make always tries to rebuild the build files before building the actual targets. If it finds a rule for Makefile and if it is out-of-date, it will be rebuilt and reloaded and the requested targets will be built according to the new makefile. This is a feature so that if the build-files are themselves generated (rather common with autotools, cmake and similar), it won't use stale build instructions.
For more details see GNU Make Manual section 3.5
In the specific examples above the rule has target % and that matches absolutely anything, including Makefile. So make will find it as rule for remaking makefile and will evaluate it.
Now in the first case Makefile exists and is newer than all of it's dependencies trivially because there are none and none of it's dependencies need to be remade also because there are none. So make will conclude that Makefile does not need to be remade.
In the second case however Makefile exists, but it's dependency test needs to be remade. So make runs the (empty) rule and than comes back and runs the rule for Makefile. Because make does not check the timestamps after making dependencies. It simply assumes that when it remade them, the dependent targets need to be remade as well.

Make - autogenerated file issue

Here is the context :
I am working on a makefile to create a .h at every build, including another makefile that will use this header. I can't edit the second one.
Using a target all depending on my file, it compiles the first time, creating the missing MyHeader.h. The problem is, when I recompile, the header is not regenerated...
My makefile looks like this :
all: myHeader.h
myHeader.h:
scriptToBuildMyHeader.sh
include obscureAndPrivateMakefile.make
I also tried with a .phony target at the beginning. Same result : once created, it won't be regenerated at every build.
PS : I can't call a script before make.
Do some makfile-Masters have any ideas how to deal with that ?
Thanks!
Because myHeader.h has no dependencies, it will never be rebuilt once it exists. You can work around this by creating a dependency from myHeader.h to a phony target, eg:
forcebuild:
# dummy; do nothing and don't create this file
.PHONY: forcebuild
myHeader.h: forcebuild
scriptToBuildMyHeader.sh
This will however slow down your build considerably, as the header (and any source files including it) will need to be rebuilt every time.
The trouble is that because myHeader.h does not depend on anything, it exists and is therefore up to date on the second build. To make sure it is built each time, it has to depend on a non-existent file:
myHeader.h: .FORCE
scriptToBuildMyHeader.sh
.FORCE:
The name '.FORCE' (or, sometimes, FORCE) is used classically.
If you use GNU Make, you could make the 'non-existent' file into a phony target:
.PHONY: .FORCE
The advantage of this is that (GNU) make does not create the file .FORCE even if you run make -t - which would break the automatic rebuild of the header because that rule depends on there not being a file .FORCE that actually exists.
Here's another possible approach:
all: clean foo.txt
clean:
rm foo.txt
foo.txt:
echo > foo.txt
where I'm using echo > foo.txt to simulate creation of your header.

What is the purpose of .PHONY in a Makefile?

What does .PHONY mean in a Makefile? I have gone through this, but it is too complicated.
Can somebody explain it to me in simple terms?
By default, Makefile targets are "file targets" - they are used to build files from other files. Make assumes its target is a file, and this makes writing Makefiles relatively easy:
foo: bar
create_one_from_the_other foo bar
However, sometimes you want your Makefile to run commands that do not represent physical files in the file system. Good examples for this are the common targets "clean" and "all". Chances are this isn't the case, but you may potentially have a file named clean in your main directory. In such a case Make will be confused because by default the clean target would be associated with this file and Make will only run it when the file doesn't appear to be up-to-date with regards to its dependencies.
These special targets are called phony and you can explicitly tell Make they're not associated with files, e.g.:
.PHONY: clean
clean:
rm -rf *.o
Now make clean will run as expected even if you do have a file named clean.
In terms of Make, a phony target is simply a target that is always out-of-date, so whenever you ask make <phony_target>, it will run, independent from the state of the file system. Some common make targets that are often phony are: all, install, clean, distclean, TAGS, info, check.
Let's assume you have install target, which is a very common in makefiles. If you do not use .PHONY, and a file named install exists in the same directory as the Makefile, then make install will do nothing. This is because Make interprets the rule to mean "execute such-and-such recipe to create the file named install". Since the file is already there, and its dependencies didn't change, nothing will be done.
However if you make the install target PHONY, it will tell the make tool that the target is fictional, and that make should not expect it to create the actual file. Hence it will not check whether the install file exists, meaning: a) its behavior will not be altered if the file does exist and b) extra stat() will not be called.
Generally all targets in your Makefile which do not produce an output file with the same name as the target name should be PHONY. This typically includes all, install, clean, distclean, and so on.
NOTE: The make tool reads the makefile and checks the modification time-stamps of the files at both the side of ':' symbol in a rule.
Example
In a directory 'test' following files are present:
prerit#vvdn105:~/test$ ls
hello hello.c makefile
In makefile a rule is defined as follows:
hello:hello.c
cc hello.c -o hello
Now assume that file 'hello' is a text file containing some data, which was created after 'hello.c' file. So the modification (or creation) time-stamp of 'hello' will be newer than that of the 'hello.c'. So when we will invoke 'make hello' from command line, it will print as:
make: `hello' is up to date.
Now access the 'hello.c' file and put some white spaces in it, which doesn't affect the code syntax or logic then save and quit. Now the modification time-stamp of hello.c is newer than that of the 'hello'. Now if you invoke 'make hello', it will execute the commands as:
cc hello.c -o hello
And the file 'hello' (text file) will be overwritten with a new binary file 'hello' (result of above compilation command).
If we use .PHONY in makefile as follow:
.PHONY:hello
hello:hello.c
cc hello.c -o hello
and then invoke 'make hello', it will ignore any file present in the pwd 'test' and execute the command every time.
Now suppose, that 'hello' target has no dependencies declared:
hello:
cc hello.c -o hello
and 'hello' file is already present in the pwd 'test', then 'make hello' will always show as:
make: `hello' is up to date.
.PHONY: install
means the word "install" doesn't represent a file name in this
Makefile;
means the Makefile has nothing to do with a file called "install"
in the same directory.
It is a build target that is not a filename.
The special target .PHONY: allows to declare phony targets, so that make will not check them as actual file names: it will work all the time even if such files still exist.
You can put several .PHONY: in your Makefile :
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
There is another way to declare phony targets : simply put :: without prerequisites :
all :: prog1 prog2
...
clean ::
...
distclean ::
...
The :: has other special meanings, see here, but without prerequisites it always execute the recipes, even if the target already exists, thus acting as a phony target.
The best explanation is the GNU make manual itself: 4.6 Phony Targets section.
.PHONY is one of make's Special Built-in Target Names. There are other targets that you may be interested in, so it's worth skimming through these references.
When it is time to consider a .PHONY target, make will run its recipe
unconditionally, regardless of whether a file with that name exists or
what its last-modification time is.
You may also be interested in make's Standard Targets such as all and clean.
There's also one important tricky treat of ".PHONY" - when a physical target depends on phony target that depends on another physical target:
TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
You'd simply expect that if you updated TARGET2, then TARGET1 should be considered stale against TARGET1, so TARGET1 should be rebuild. And it really works this way.
The tricky part is when TARGET2 isn't stale against TARGET1 - in which case you should expect that TARGET1 shouldn't be rebuild.
This surprisingly doesn't work because: the phony target was run anyway (as phony targets normally do), which means that the phony target was considered updated. And because of that TARGET1 is considered stale against the phony target.
Consider:
all: fileall
fileall: file2 filefwd
echo file2 file1 >fileall
file2: file2.src
echo file2.src >file2
file1: file1.src
echo file1.src >file1
echo file1.src >>file1
.PHONY: filefwd
.PHONY: filefwd2
filefwd: filefwd2
filefwd2: file1
#echo "Produced target file1"
prepare:
echo "Some text 1" >> file1.src
echo "Some text 2" >> file2.src
You can play around with this:
first do 'make prepare' to prepare the "source files"
play around with that by touching particular files to see them updated
You can see that fileall depends on file1 indirectly through a phony target - but it always gets rebuilt due to this dependency. If you change the dependency in fileall from filefwd to file, now fileall does not get rebuilt every time, but only when any of dependent targets is stale against it as a file.
I often use them to tell the default target not to fire.
superclean: clean andsomethingelse
blah: superclean
clean:
#echo clean
%:
#echo catcher $#
.PHONY: superclean
Without PHONY, make superclean would fire clean, andsomethingelse, and catcher superclean; but with PHONY, make superclean won't fire the catcher superclean.
We don't have to worry about telling make the clean target is PHONY, because it isn't completely phony. Though it never produces the clean file, it has commands to fire so make will think it's a final target.
However, the superclean target really is phony, so make will try to stack it up with anything else that provides deps for the superclean target — this includes other superclean targets and the % target.
Note that we don't say anything at all about andsomethingelse or blah, so they clearly go to the catcher.
The output looks something like this:
$ make clean
clean
$ make superclean
clean
catcher andsomethingelse
$ make blah
clean
catcher andsomethingelse
catcher blah

Resources