如何使用makefile独立编译和更新一个文件夹下的所有文件

How to use makefile to compile and update all files in one folder independently

我有一个包含多个 .cpp 文件的文件夹,例如A.cpp、B.cpp 和 C.cpp。它们都是相互独立的。我可以将 A.cpp 编译为 A.o,然后编译为二进制文件 A。B.cpp 和 C.cpp 也是如此。

我想编写一个可以一次编译所有这些文件的生成文件。而且以后如果有新的文件,比如D.cpp放到这个文件夹里,makefile还是可以自动处理的。

我当前的文件是

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=$(SOURCES:.cpp=)

all: $(SOURCES) $(OBJECTS) $(EXECUTABLE)

$(OBJECTS): $(SOURCES)  
    $(CC) $(CFLAGS) $(@:.o=.cpp) -o $@

$(EXECUTABLE): $(SOURCES)
    $(CC) $(LDFLAGS) $(@:=.o) -o $@

问题是,一旦一个 .cpp 文件被更改或添加到文件夹中,所有其他文件将被更新并重新编译,如果我这样做的话。

请告诉我如何解决这个问题。

谢谢。

.SUFFIXES: .o .cpp 放在 all 行上方。

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=$(SOURCES:.cpp=)

.SUFFIXES: .o .cpp

all: $(SOURCES) $(OBJECTS) $(EXECUTABLE)

$(OBJECTS): $(SOURCES)  
    $(CC) $(CFLAGS) $(@:.o=.cpp) -o $@

$(EXECUTABLE): $(SOURCES)
    $(CC) $(LDFLAGS) $(@:=.o) -o $@

额外

使用这个

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=$(SOURCES:.cpp=)

.SUFFIXES: .o .cpp

all: $(EXECUTABLE)

.cpp.o:
    $(CC) $(CFLAGS) $(@:.o=.cpp) -o $@

$(EXECUTABLE): $(OBJECTS)
    $(CC) $(LDFLAGS) $(OBJECTS) -o $@

您不需要将 $(SOURCES) 或 $(OBJECTS) 放入 all。你必须在下面写

DESTINATION: SOURCE

关于.SUFFIXES.cpp.o,这是一个特别的。它作为 .SOURCE.DESTINATION:

您的 makefile 将每个源文件都列为每个可执行文件和每个目标文件的先决条件。

它也不喜欢将目标文件作为可执行文件的先决条件(这意味着 make 无法自动为您构建它们)。

就是这些问题。

综上所述,您根本不需要此 makefile 中的规则。

只是

的makefile
CC=g++
CXXFLAGS=-c -Wall

会让你 运行 make A 并从 A.cpp 构建 A (尽管它不会构建 A.o 因为它没有'不需要)。如果您不需要设置 CCCXXFLAGS(或者不介意设置它们),您甚至根本不需要 makefile 来从 A.cpp 构建 A在命令行上。

$ mkdir test
$ cd test
$ ls
$ touch A.cpp
$ make CC=g++ CXXFLAGS='-c -Wall' A
g++ -c -Wall    A.cpp   -o A

但是如果你要求它A.o它会。

$ make CC=g++ CXXFLAGS='-c -Wall' A.o
g++ -c -Wall   -c -o A.o A.cpp

此时 make 将尝试从 A.o.

构建 A
$ make CC=g++ CXXFLAGS='-c -Wall' A
g++   A.o   -o A

要重新获得对 make 构建所有可执行文件的支持,您需要这样一行:

all: $(subst .cpp,,$(wildcard *.cpp))

如果您 想要手动指定所有内容(并强制 .o 构建),您需要更像这样的东西。 (其中使用 10.5 Defining and Redefining Pattern Rules and 4.12 Static Pattern Rules。)

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=$(SOURCES:.cpp=)

all: $(EXECUTABLE)

%.o: %.cpp
    $(CC) $(CFLAGS) $^ -o $@

$(EXECUTABLE): % : %.o
    $(CC) $(LDFLAGS) $^ -o $@

然后您可以编写 make 来构建它们,并 make A 来构建特定的。

您只需更改 all: 行,然后删除其后的所有其他行。

CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=$(SOURCES:.cpp=)

all: $(OBJECTS) $(EXECUTABLE)

如果您不需要创建 .o 文件,那么您也可以从 all: 中删除 $(OBJECTS) 以及定义它的行。这消除了为 link 行重新定义 $(CC) 的需要,但您需要将 -Wall 添加到 $(CXXFLAGS).

CXXFLAGS=-Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
EXECUTABLE=$(SOURCES:.cpp=)

all: $(EXECUTABLE)

让你伤心的两行是:

$(OBJECTS): $(SOURCES)

$(EXECUTABLE): $(SOURCES)

第一个说 "every object file depends on every one of the source files; if any source file changes, every object file is out of date"。第二个关于可执行文件的说法相同。

make 知道如何直接从源文件构建可执行文件;您不需要目标文件作为中介。

我会从 all 行中删除 $(OBJECTS)(因为您实际上并不需要目标文件)。

然后你可以删除我识别的行和它们后面的命令(删除问题中显示的最后四个非空行)。

如果您仍然希望能够创建所有目标文件,请添加:

objects: $(OBJECTS)

并使用 make objects 使它们全部。

FWIW:创建对象的编译规则应直接指定 -c,而不是将其包含在 $(CFLAGS) 宏中。构建可执行文件的编译规则可以(并且应该)使用 $(CFLAGS)(以及 $(LDFLAGS),也许 $(LDLIBS))。

$(OBJECTS):
    $(CC) -c $(CFLAGS) $(@:.o=.cpp) -o $@

$(EXECUTABLE):
    $(CC) -o $@ $(CFLAGS) $@.cpp $(LDFLAGS) $(LDLIBS)

对象编译行中的 -o $@ 在很大程度上是不必要的,至少根据我的经验。 C 编译器无论如何都会生成 $@。如果源不在当前目录中可能很重要,但这不是你遇到的情况。

通常最好只使用内置规则,这样您就不必像 ${@:.o=.cpp} 这样的神秘咒语就正确了。对于 make 的大多数版本,内置规则将与我展示的非常相似(使用 make -p 找出它们与您的 make 的内容)。 GNU make 具有使用 %.o: %.cpp 表示法的现代规则,而显示的代码并不假设。