如何将不同目录中的源代码编译成一个目录(Makefile)中的目标文件?

How to compile sources in different directories into object files all in a single directory (Makefile)?

我有这样的布局:

project/
  Makefile
  core/
    a.cpp
    a.hpp
  utl/
    b.cpp
    b.hpp
  obj/

而且我想将所有 .o 文件都放在 obj 文件夹中,这样我就可以从这些目标文件创建一个共享库。但是由于我的 .cpp 文件位于不同的目录中,所以我不知道如何自动执行此操作。不仅有这两个目录,还有多个目录。任何提示表示赞赏。

我的尝试失败了,因为我假设 Make automatic rule for .o(我想使用)想要一个 .cpp 在 .o 应该在的同一目录中?

# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))

# remove the path
SRC_WITHOUT_PATH = $(notdir $(SRC))

# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(SRC_WITHOUT_PATH:%.cpp=./obj/%.o)

# error is no rule to make target obj/a.o

您可以从目标文件创建碎片库,即使它们位于不同的目录中。所以这并不是将它们放在其他地方的真正理由。

然而,更好的理由是保持源目录整洁并使其易于清理(只需删除 obj 目录)。

将不同目录中的源文件中的目标文件放到一个目录中是有问题的:如果您有两个同名的源文件,它们会相互覆盖。解决此问题的一种常见方法是保留源文件的目录结构,但将其放在新的顶级目录下; GNU make 轻松支持:

# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))

# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(addprefix obj/,$(SRC:.cpp=.o))

obj/%.o : %.cpp
        @mkdir -p $(@D)
        $(COMPILE.cpp) -o $@ $<

如果你真的,真的想把所有的目标文件都放在同一个目录下,你必须变得更高级,因为 make 对目标使用简单的字符串匹配,所以你必须为每个关系编写一个新规则,其中目标和先决条件名称不同:基本上这意味着每个单独的源目录都有一个新规则。

您可以使用 GNU make 的 the VPATH feature 来避免这种情况,如下所示:

# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))

# remove the path
SRC_WITHOUT_PATH = $(notdir $(SRC))

# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(SRC_WITHOUT_PATH:%.cpp=obj/%.o)

# Give all the source directories to make
VPATH = $(sort $(dir $(SRC))

obj/%.o : %.cpp
        $(COMPILE.cpp) -o $@ $<