如何使用生成文件独立编译和更新一个文件夹中的所有文件



我有一个文件夹,其中包含多个.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文件被更改或添加到文件夹中,如果我这样做,所有其他文件都将更新并重新编译。

请让我知道如何解决这个问题。

谢谢。

生成文件将每个源文件列为每个可执行文件和每个对象文件的先决条件。

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

这些就是问题所在。

话虽如此,您根本不需要此生成文件中的规则。

一个刚刚

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 定义和重新定义模式规则和 4.12 静态模式规则。

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构建特定的它们。

.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:

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

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

如果您不需要创建.o文件,那么您还可以从all:中删除$(OBJECTS)以及定义它的行。这样就无需为链接线重新定义$(CC),但您需要向$(CXXFLAGS)添加-Wall

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

给你悲伤的两行是:

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

第一个说"每个对象文件都依赖于每个源文件;如果任何源文件发生更改,则每个对象文件都已过期"。 第二个对可执行文件说同样的话。

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表示法的现代规则,而显示的代码并不假设这一点。

相关内容

最新更新