I am studying a Makefile obtained from a compiler course project. Only a part of it is pasted here.
# Retain intermediate bitcode files
.PRECIOUS: %.bc
# The default target builds the plugin
plugin:
make -C lib/p1
# create .bc from source
%.bc: %.c
clang -emit-llvm -O0 -c $*.c -o $*.bc
# run printCode on a .bc file
%.printCode: %.bc plugin
opt -load Debug/lib/P1.so -printCode $*.bc
As you see, the target 'plugin' has no dependencies, which, if I understand correctly, should mean that its recipe never runs (unless it is declaared as a phony target, which is not the case here)
However, when I type 'make printCode', (printCode is the last target in the list) the plugin target does execute. How is this made possible? Is there some implicit rule stating that the first target of a Makefile is regarded as a phony target, such as 'all'?
You've got things a little backward.
A rule like the plugin rule can run. You can run it by executing 'make plugin', or 'make' if it's the default target (which it is in this case by virtue of being the first), or if it is a prerequisite of another target that must be built.
I'm not sure exactly what happens when you 'make printCode', since you are showing us only part of the makefile and there is no rule that fits, but judging by this rule:
%.printCode: %.bc plugin
opt -load Debug/lib/P1.so -printCode $*.bc
I'd guess that the printCode rule depends on either plugin or something like foo.printCode that depends on plugin. So Make sees that plugin is a prerequisite, sees that no such file exists, and determines therefore that plugin must be built. It then looks for a rule to build plugin, finds it and runs it.
Related
I have a make target which is not a file name.
BUILD_DIR := <my build directory path>
build : $(BUILD_DIR)
recipe
release : build
I observed that when I call build for the first time, it executes the recipe of build which is expected. However, when I call release followed by build it re-executes build. I have a clue on why this is happening, I read from GNU make references that -
If you write a rule whose recipe will not create the target file, the recipe will be executed every time the target comes up for remaking.
Do we have a way to avoid build getting re-built ? I cannot simply call release. My expectation is to call build followed by release and build should not re-execute when release is called. I know I can simply remove the dependency of release but I am not preferring it that way. Can someone recommend a better way out ?
The reason people are having a hard time replying is because your question is not at all clear. What exactly does my expectation is to call build followed by release and build should not re-execute when release is called mean? The term call build has no meaning in make: you don't "call" targets. If you showed us exactly what commands you ran and the output you got, and explained what you wanted instead, then it would be much simpler to provide correct answers.
I will assume you mean, you run make build followed by make release and you don't want to create a file named build and you don't want the build recipe to be run when you run make release even though you do want build to be listed as a prerequisite of release in the makefile.
In short, that's not possible.
Make decides whether a file should be rebuilt by comparing the modification time of the target file against the modification time of the prerequisites. If any of the latter are newer than the former, it runs the recipe. If the former (target) doesn't exist then the recipe is always invoked. Make doesn't maintain any sort of database between invocations saying when the last time a recipe was run or what targets were built the last time it ran: the only "database" it has is the modification times on the filesystem.
Since your build target doesn't create a file, how is make supposed to know when you do want the build target recipe to be invoked, and when you do not want the recipe to be invoked?
Release should have the build artifacts as prerequisites instead of the (phony) build target.
I'm going to try and give you a practical answer, but you really should look at the other answers for better practice.
You want the opposite of .PHONY. .PHONY is a phony target that is always built, you want a non-fake target that gets rebuilt conditionally... which is a regular target.
You want make to remember that it already called build, but make doesn't have any cache, it just uses files and mtime, so that's what you do:
BUILD_DIR := ./target
.PHONY: build release
$(BUILD_DIR):
mkdir $#
$(BUILD_DIR)/file.elf: $(BUILD_DIR) src.c
cp src.c $#
.built: $(BUILD_DIR)/file.elf
touch $#
build: .built
release: build
$ make release
mkdir target
cp src.c target/file.elf
touch .built
$ make build
make: Nothing to be done for 'build'.
The idea is in order to considered the codebase to be "built" (.built), a list of artifacts (in this case, just $(BUILD_DIR)/file.elf) needs to be up-to-date. And each such artifact has its own recipe.
Then make release will re-run the build target, but it will do nothing if the codebase is .built.
Notice how you could just skip .built and have build directly depend on $(BUILD_DIR)/file.elf as was suggested in the comments:
$(BUILD_DIR)/file.elf: $(BUILD_DIR) src.c
cp src.c $#
build: $(BUILD_DIR)/file.elf
If you instead go your way:
build: $(BUILD_DIR)
cp src.c $(BUILD_DIR)/file.elf
touch $#
Then when src.c gets updated, file.elf doesn't get rebuilt. To fix that, you'd have to list all the sources as dependencies of the build target, and that means your build won't be incremental: whenever it needs to rebuild anything, it will rebuild everything.
The only reason I can think of to actually use something like .built is if it's not feasible to list all the artifacts, for example if you build recipe creates a complicated, uncached set of artifacts:
.built:
bazel clean
bazel build //... # builds all packages
touch $#
build: .built
Or if the build is not specified by a file:
.has_container_image:
docker build --no-cache .
touch $#
build: .has_container_image
word.o: word.c word.h
gcc -c word.c
line.h: word.h
touch line.h
Above is the contents of the makefile. when I execute make.
I see the file word.o is created. But the file line.h is not.
What could be the reason for this? As far as I know, the make doesn't
execute those targets which don't have any dependencies.
But here the dependency list is not empty, Still, it didn't get executed
Certainly make builds targets that don't have dependencies. If a target has no dependencies, then it is considered out of date if it doesn't exist.
The problem is that make doesn't build every single target in the makefile: that would be bad because many people include clean targets, test targets, and other targets that they only want to run sometimes not every time.
You can read the introduction in the GNU make manual, specifically this section, to understand what's happening.
I just discovered this line in a makefile:
%: Makefile
To me, that says "to make any target, you need this makefile", which strikes me as somewhat obvious.
Is there any situation in which this is not a no-op?
As Etan commented, this will cause every target to be rebuilt whenever the Makefile changes. This is necessary so that anytime you make a change in the build configuration parameters the target will be rebuilt. Otherwise make won't know to rebuild with the new configuration.
I am trying to write a Make rule that says, roughly, "If you need to build target, also build prereq. However, do not rebuild target because prereq changes."
Right now I am using this hack:
target: otherprereqs
$(MAKE) prereq
RECIPE
Is there a better way of doing this?
All right, I think I know what you mean. If your version of GNUMake is recent enough, you can use order-only prerequisites:
target: otherprereqs | prereq
RECIPE
I have a project with autotools: automake, autoconf.
I want to prohibit make from remaking files configure, Makefile.in, etc; just to do compile job.
Some of files are edited by hand, and I know that I should not to do this. (Or the project was updated from CVS with all generated files stored in CVS).
But at the moment I have no correct version autotools installed.
What must be modification times of this files (which must be newer/older):
aclocal.m4
configure.in
confdb/ax_prefix_config_h.m4
Makefile.am
Makefile.in
Makefile
configure
config.status
Or: what sequence of touch commands must I do to achieve my goal?
First of all, if you edit a generated file directly, it wouldn't be rebuilt anyway, because it is then newer then its prerequisites.
Then, there are two separate things going on here: config.status and Makefile are created during the build. It's hard to prevent these from being remade during the build unless you make their timestamps newer.
The other files are generated by the various autotools. Recent versions of Automake do not create rules by default that remake them automatically. Depending on your package, you might want to use the configure option --disable-maintainer-mode. The Automake documentation contains some more interesting information about that option.
One trick I sometimes use with a package that I don't know much about or that has a pretty messed up build system is to run something like
make all AUTOCONF=: AUTOHEADER=: AUTOMAKE=: ACLOCAL=:
so that if these programs happen to be called, a noop would be substituted.
touch confdb/*.m4
touch configure.in
touch *.m4
touch *.am
touch Makefile.in */Makefile.in
touch *config.h.in */*config.h.in
touch configure
touch config.status
touch config.h
touch Makefile
Problems with automake & cvs are described here http://www.gnu.org/s/hello/manual/automake/CVS.html
Try to explicitly tell make those files should not be remade, via command-line
$ make -o configure -o Makefile.in
or by using MAKEFLAGS
$ MAKEFLAGS="-o configure -o Makefile.in" make
The excerpt from GNU make's manual
‘-o file’
‘--old-file=file’
‘--assume-old=file’
Do not remake the file file even if it is older than its prerequisites, and do not remake
anything on account of changes in file. Essentially the file is treated as very old and
its rules are ignored. See Avoiding Recompilation of Some Files.
If yours autotools template correctly uses $(MAKE) for subdirs, there should be no problems.