我有一个包含几个.cpp文件的文件夹,例如A.cpp,B.cpp和C.cpp。他们都是彼此独立的。我可以将A.cpp编译为A.o然后编译为二进制文件A.因此它与B.cpp和C.cpp一起编译。
我想编写一个可以一次编译所有这些文件的makefile。并且在将来,如果将一些新文件(如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文件被更改或添加到文件夹中,如果我这样做,所有其他文件将被更新并重新编译。
请让我知道如何解决这个问题。
感谢。
答案 0 :(得分:4)
您的makefile将每个源文件列为每个可执行文件和每个目标文件的先决条件。
它也不喜欢目标文件作为可执行文件的先决条件(这意味着make不能自动为你构建它们)。
这些都是问题。
所有人都说你根本不需要这个makefile中的规则。
只是
的makefileCC=g++
CXXFLAGS=-c -Wall
将允许您从make A
运行A
并构建A.cpp
(尽管它不会构建A.o
来执行此操作,因为它不需要)。如果您不需要设置A
或A.cpp
(或者不介意设置CC
,则甚至根本不需要makefile来构建来自CXXFLAGS
的{{1}}在命令行上。
$ 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
构建A.o
。
$ 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和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
来构建特定内容。
答案 1 :(得分:1)
将.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:
答案 2 :(得分:1)
您只需要更改all:
行,然后删除其后的所有其他行。
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=$(SOURCES:.cpp=)
all: $(OBJECTS) $(EXECUTABLE)
如果您不需要创建.o
个文件,那么您也可以从$(OBJECTS)
删除all:
,以及定义它的行。这样就无需为链接行重新定义$(CC)
,但您需要将-Wall
添加到$(CXXFLAGS)
。
CXXFLAGS=-Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp)
EXECUTABLE=$(SOURCES:.cpp=)
all: $(EXECUTABLE)
答案 3 :(得分:1)
让你感到悲伤的两条线是:
$(OBJECTS): $(SOURCES)
$(EXECUTABLE): $(SOURCES)
第一个说“每个目标文件都依赖于每个源文件;如果任何源文件发生变化,每个目标文件都会过时”。第二个说的是可执行文件。
make
知道如何直接从源文件构建可执行文件;您不需要将目标文件作为中介。
我会从$(OBJECTS)
行删除all
(因为您并不真正需要目标文件)。
然后你可以删除我识别的行和它们后面的命令(删除问题中显示的最后四个非空行)。
如果您仍希望能够创建所有目标文件,请添加:
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
符号表示现代规则,而显示的代码不假设。