如何使用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
因为它没有'不需要)。如果您不需要设置 CC
或 CXXFLAGS
(或者不介意设置它们),您甚至根本不需要 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
表示法的现代规则,而显示的代码并不假设。
我有一个包含多个 .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 中的规则。
只是
的makefileCC=g++
CXXFLAGS=-c -Wall
会让你 运行 make A
并从 A.cpp
构建 A
(尽管它不会构建 A.o
因为它没有'不需要)。如果您不需要设置 CC
或 CXXFLAGS
(或者不介意设置它们),您甚至根本不需要 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
表示法的现代规则,而显示的代码并不假设。