如何使用生成文件独立编译和更新一个文件夹中的所有文件
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文件被更改或添加到文件夹中,如果我这样做,所有其他文件都将更新并重新编译。
请让我知道如何解决这个问题。
谢谢。
生成文件将每个源文件列为每个可执行文件和每个对象文件的先决条件。
它也不喜欢将目标文件作为可执行文件的先决条件(这意味着make无法自动为您构建它们)。
这些就是问题所在。
话虽如此,您根本不需要此生成文件中的规则。
一个刚刚
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 定义和重新定义模式规则和 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
表示法的现代规则,而显示的代码并不假设这一点。
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 挂起和取消挂起一个文件DLL
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- C++试图读取一个文件并输出到另一个文本文件
- 如何从另一个文件继承私有成员变量和公共函数
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 如何打开并写入一个名称取自C++中字符串的文件
- 构建一个由C和C++文件组成的库
- c++多进程编写一个唯一的文件
- 如何使用CLion在Mac上创建一个新的.txt文件
- 如何将class.cpp和class.hpp编译为一个.o文件
- 写入文件会产生一个空文件或根本没有文件
- 如何将不同的可执行文件合并到一个窗口框架中进行编码?像浏览器一样
- 生成一个生成文件,该生成文件使用Automake在一个步骤中编译和链接所有源文件
- 为什么我的 heap.h 文件给我一个LNK2001错误?
- Pantheios 不使用 MFC 应用程序写入一个文件(一个 exe + 两个 DLL)
- 在C++中一次读取一个文件一个int
- 输入/输出文件(一个字母的大写)
- 如何使用两个预编译的头文件.一个用于托管代码,另一个用于非托管代码.xxx.PCH不是一个有效的预编译头文件