为 .cpp 和 .hpp c++​​ 编写 makefile

Write makefile for .cpp and .hpp c++

我需要帮助为多个 .hpp 和 .cpp 文件创建合适的 makefile(支持增量编译)。

我一直在寻找有关如何创建正确的 makefile 的信息,但我不太确定该怎么做。

我有以下文件: 2048.cpp、game.cpp、game.hpp、gameutils.cpp、gameutils.hpp、menu.cpp、menu.hpp、saveandback.cpp、saveandback.hpp 和 tile.hpp

现在我正在使用以下 makefile:

all: 2048.cpp tile.hpp menu.hpp menu.cpp gameutils.hpp gameutils.cpp saveandback.hpp saveandback.cpp game.hpp game.cpp
    g++ -g -W -Wall --pedantic -DNDEBUG 2048.cpp -o power

clean: 
    $(RM) power

感谢您的帮助。

警告:我有一段时间没有使用 make,所以我可能对 POSIX 与 GNU-make 特定的东西有点生疏。在过去几年中可能还会发布一些我不知道的新功能。请随时进行更正。也大部分来自记忆。

这里你的知识集中缺少一些东西,你可以用它们来创建一个像样的 makefile,只需要 re-compiles 东西:

  • Generic Rules - 这些可用于提供通用规则,用于构建具有一个后缀的文件名。例如。以下定义了从其对应的 *.cpp 创建任何 *.o 的规则:

    %.o: %.cpp
        stuff
    

    在POSIX make中这些规则实际上指定为:

    .cpp.o:
        stuff
    

    下面我使用的是 GNU 语法,但您可以(并且可能想要)替换为 POSIX 语法(如果您将它们排除在外并使用隐式规则,则没有实际意义,请参见下文)。

  • Automatic Variables

    • $< 将扩展到规则的输入。
    • $@ 将扩展到规则的目标。
  • 变量 - 您可以声明变量并给它们赋值,例如:

    SOURCES=2048.cpp gameutils.cpp saveandback.cpp
    

  • 文本替换 - 您可以使用文本替换功能来替换后缀,例如:

    OBJECTS=$(SOURCES:.cpp=.o)
    

    OBJECTS 设置为 SOURCES,但 .cpp 更改为 .o

  • Multiple Rules - 如果为同一目标指定了多个规则,则合并它们的先决条件。

  • Phony Targets

将所有这些放在一起你就可以开始了,暂时不考虑 header 依赖项:

SOURCES=2048.cpp menu.cpp gameutils.cpp saveandback.cpp game.cpp
OBJECTS=$(SOURCES:.cpp=.o)

power: $(OBJECTS)
    g++ $(OBJECTS) -o $@

%.o: %.cpp
    g++ -c $< -o $@

通常定义 all 规则,这是一个虚假目标,因为实际上没有名为 "all":

的文件
.PHONY: all
SOURCES=2048.cpp menu.cpp gameutils.cpp saveandback.cpp game.cpp
OBJECTS=$(SOURCES:.cpp=.o)

all: power

power: $(OBJECTS)
    g++ $(OBJECTS) -o $@

%.o: %.cpp
    g++ -c $< -o $@

现在,make 实际上有一些 default rules already, including one for %.o: %.cpp, and also it has some default variables。所以如果你愿意,你可以将上面的内容减少到这个(我个人更喜欢明确指定规则,但那只是我):

.PHONY: all
SOURCES=2048.cpp menu.cpp gameutils.cpp saveandback.cpp game.cpp
OBJECTS=$(SOURCES:.cpp=.o)

all: power

power: $(OBJECTS)
    $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@

现在,对于您的 header,请牢记多条规则,您可以简单地根据它们的包含手动添加这些先决条件,例如:

.PHONY: all
SOURCES=2048.cpp menu.cpp gameutils.cpp saveandback.cpp game.cpp
OBJECTS=$(SOURCES:.cpp=.o)

all: power

power: $(OBJECTS)
    $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@

2048.o: menu.hpp game.hpp
menu.o: menu.hpp 
game.o: game.hpp

等等。你可能还想要一个 "clean" 规则,另一个假目标,把你的二进制名称放在一个变量中也没有坏处,因为你在几个地方使用它,例如:

.PHONY: all clean
SOURCES=2048.cpp menu.cpp gameutils.cpp saveandback.cpp game.cpp
OBJECTS=$(SOURCES:.cpp=.o)
BINARY=power

all: $(BINARY)

clean:
    $(RM) $(BINARY) $(OBJECTS)

$(BINARY): $(OBJECTS)
    $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@

实际上,如果您将 -MM 传递给 gcc,它会根据源文件的包含自动为您生成 Makefile 依赖项。有关详细信息和示例,请参阅 here