首页 > 解决方案 > 为 C++ 项目创建 makefile

问题描述

我目前正在尝试编写一个 Makefile,它在当前目录和所有子目录中搜索 C++ 文件,然后将它们一一编译(如果它们自上次编译以来尚未编译或编辑)成在最终使用目标文件并将它们全部链接到最终程序之前,位于 ./Objects 位置的单个目标文件。

我已经弄清楚如何使用“shell find”命令查找所有文件。但是,我一直在试图弄清楚如何一次将源文件编译成对象文件。

这是我的代码:

Appname := App
#The Directory
ObjectsDir := ./Objects

#Find all the source files
SrcFiles = $(shell find . -name "*.cpp")
#Get their names only
SrcFilesName = $(notdir $(SrcFiles))
#Add a .o suffix for the Object files name
ObjectsSuffix = $(addsuffix .o, $(SrcFilesName))
#Add the prefix "Objects/" as I wish to output all the objects to ./Objects
#A Source Files such as "./Test/Source/Test.cpp" becomes "./Objects/Test.cpp.o"
Objects = $(addprefix ./Objects/, $(ObjectsSuffix))

#Compiler related Variables
CXX = g++
CXXFLAGS = -Wall -std=c++20 -fsanitize=address  
CPPFLAGS = -DDEBUG -I ./Game/Headers -I ./Engine/Headers -I ./Engine/Headers/External
LDLIBS = $(shell sdl2-config --libs) -l dl

all : $(Appname)

$(Appname) : $(Objects)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(Objects) -o $(Appname) $(LDLIBS)

#The Problematic rule
#I would like this to run once per source file if they haven't been compiled or changed/edited, so that I don't end up recompiling the entire code base
$(ObjectsDir)/%.o: %.cpp
    mkdir -p Objects
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -c $^ -o $@ $(LDLIBS)

注意:当所有源文件都在基本目录中时,makefile 当前可以工作。但是,当有更复杂的布局时,会出现多个子目录等错误make: *** No rule to make target 'Objects/Engine.cpp.o', needed by 'App'. Stop.

标签: c++makefile

解决方案


在模式规则中,词干(与 匹配的部分%)在目标和先决条件中将是相同的。因此,如果您的目标是,./Objects/foo.o那么词干是foo,前提是foo.cpp

但是,您没有foo.cpp,因此该规则不匹配。Make 找不到任何其他匹配的规则,因此它说它不知道如何构建该目标。

仅仅因为您可能有其他文件,例如some/subdir/foo.cpp,并不意味着它不是在寻找那个文件,而是在寻找foo.cpp.

一般来说,从许多不同的目录中获取源文件并将构建输出全部放到同一个目录中并不是 make 想要的工作方式(此外,这通常是一个坏主意;如果你不小心创建了两个不同的源文件,会发生什么情况?在两个不同的目录中命名?)

但是,make 确实提供了一个可以使这项工作发挥作用的功能:VPATH允许 make 在其他目录中搜索源文件。如果你在你的 makefile 中使用它:

SrcFiles := $(shell find . -name "*.cpp")

SrcFileDirs := $(sort $(dir $(SrcFiles))

VPATH := $(SrcFileDirs)

那么它应该可以工作(您应该始终使用:=with$(shell ...)来提高效率)。


推荐阅读