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

时间:2015-01-20 03:07:07

标签: c++ c makefile

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

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

感谢。

4 个答案:

答案 0 :(得分:4)

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

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

这些都是问题。

所有人都说你根本不需要这个makefile中的规则。

只是

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

将允许您从make A运行A并构建A.cpp(尽管它不会构建A.o来执行此操作,因为它不需要)。如果您不需要设置AA.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 Rules4.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符号表示现代规则,而显示的代码不假设。