makefile enforce library dependency ordering [dupl

2019-01-15 11:36发布

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?

标签: c++ makefile
1条回答
啃猪蹄的小仙女
2楼-- · 2019-01-15 12:26

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:

  1. Thou shalt invoke make to make a target (or targets) or a default target, which is the first target in thy Makefile. Targets in thy Makefile are on the left side of :

  2. 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.

  3. 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.

  4. Sources are files that are not listed as targets, and are already present before make is invoked.

  5. A target "depends" on "prerequisites" which are written after the :, after the target

  6. A 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.

  7. A phony target must not have a recipe.

  8. 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.

  9. 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 $@

  1. If you want to use other makefiles, but do not satisfy the above exception, 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.

查看更多
登录 后发表回答