This question already has an answer here:
In building a library that has recursive dependencies, I have this fragment:
$(LIBRARY) : $(OBJECTS) | $(LIBDIR) # objects is all the obj/*.o
$(AR) ...
obj/%.o : %.cpp obj/%.d
$(CC) ...
build : $(DEPENDENCIES) $(LIBRARY)
$(DEPENDENCIES):
$(MAKE) -C $(ROOT)/$@
This works if I run make
. Everything builds as expected in the correct order. But if I run make -jN
, the libraries build in a bad order because I don't actually have any dependency ordering rules set, which leads to lots of undefined references.
If I add the rule:
$(OBJECTS) : $(DEPENDENCIES)
then running make rebuilds every library every time, regardless of changes (DEPENDENCIES
is phony, but I don't understand why it actually rebuilds everything). How can I enforce the correct orderings for the purposes of parallel build while not having to rebuild everything every time?
I am going to give you general guidelines how to setup makefiles to guaranteee:
a. rebuild that and only that which is necessary, and
b. correctly work with parallelism.
Some people already had asked for some "good principles", so here they are.
Rewrite your makefile with these principles and you are guaranteed to work correctly.
The 10 Commandments:
Thou shalt invoke
make
to make atarget
(or targets) or a default target, which is the first target in thy Makefile. Targets in thy Makefile are on the left side of:
There are two kinds of targets: real and "phony". A real target is an actual file (or directory) that you want to (re)create. A phony target is an abstract concept, not a real file, but it typically means a group of real files.
A target listed in the Makefile may also have a
%
, in which case it is a pattern target, which can match multiple targets, real or phony.Sources are files that are not listed as targets, and are already present before
make
is invoked.A target "depends" on "prerequisites" which are written after the
:
, after the targetA real target must have a "recipe", which is a shell script under the target line. The recipe should only write one file and one file only, the target file. The target file should be referred as
$@
inside the recipe.If the recipe writes multiple files, break it down to multiple recipes for single targets.
The recipe may read many files: these must be listed as prerequisites.
A phony target must not have a recipe.
A phony target can depend on other phony targets, real targets, or sources. A real target must only depend on real targets, or sources. Everything eventually (recursively) depends on sources only.
Thou shalt not call
make
recursively in recipes, except in one case and one case only: thou hast some subdirectory that builds completely by itself, without reading any of thy sources or targets outside of itself.In that exceptional case, thou shalt have a phony target subdirectory and the recipe:
.PHONY: subdirectory subdirectory: $(MAKE) -C $@
include
them.Note: I am not saying you can't write a correct Makefile while violating these principles. You can and sometimes it is necessary. But to do that you have to know what you are doing and understand more advanced concepts. You should not start learning that way, but first start writing Makefiles following the above principles.