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

如何将不同目录中的源代码编译成单个目录中的目标文件(Makefile)?,makefile,compilation,shared-libraries,project,gnu-make,Makefile,Compilation,Shared Libraries,Project,Gnu Make,我有这样的布局: project/ Makefile core/ a.cpp a.hpp utl/ b.cpp b.hpp obj/ 我希望所有的.o文件都在obj文件夹中,这样我就可以从这些对象文件中创建一个共享库。但是,由于我的.cpp文件位于不同的目录中,我不知道如何实现自动化。有多个目录,不仅仅是这两个。任何暗示都将不胜感激 我的尝试失败了,因为我假设Make automatic rule for.o(我想使用)希望.cpp位于.o应该位

我有这样的布局:

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使支持更容易:

# 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 $@ $<
#获取一些目录列表中的所有cpp文件及其路径
SRC=$(通配符*.cpp)$(foreach DIR,$(DIRS),$(通配符$(DIR)/*.cpp))
#将.obj/目录粘贴到.cpp文件之前并更改扩展名
OBJ=$(addprefix OBJ/,$(SRC:.cpp=.o))
obj/%.o:%.cpp
@mkdir-p$(@D)
$(COMPILE.cpp)-o$@$<
如果你真的,真的想让所有的对象文件都在同一个目录中,你就必须变得更有趣,因为make对目标使用简单的字符串匹配,所以你必须为每个目标和前提名称不同的关系编写一个新规则:基本上这意味着每个单独的源目录都有一个新规则

您可以通过使用GNU make来避免这种情况,如下所示:

# 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 $@ $<
#获取一些目录列表中的所有cpp文件及其路径
SRC=$(通配符*.cpp)$(foreach DIR,$(DIRS),$(通配符$(DIR)/*.cpp))
#移除路径
不带路径的SRC_=$(notdir$(SRC))
#将.obj/目录粘贴到.cpp文件之前并更改扩展名
OBJ=$(SRC_不带_路径:%.cpp=OBJ/%.o)
#提供所有要创建的源目录
VPATH=$(排序$(目录$(SRC))
obj/%.o:%.cpp
$(COMPILE.cpp)-o$@$<

感谢您的帮助!我在阅读了相关内容后也尝试过使用它,它的效果是:vpath%.cpp DIRS