我目前有以下makefile(我正在使用在线教程的示例),但是我有几个问题:
# *****************************************************
# Variables to control Makefile operation
CXX = g++
CXXFLAGS = -Wall -g
test: main.o car.o student.o house.o
$(CXX) $(CXXFLAGS) -o test main.o car.o student.o house.o
objcopy --only-keep-debug test test.debug
main.o: student.h house.h main.cpp
$(CXX) $(CXXFLAGS) -c main.cpp
car.o: car.h
student.o: student.h car.h
house.o: house.h
clean:
rm -rf *.o test *.debug
以下是我对此处发生的事情的理解,如果我错了,请纠正我。当最初测试目标被调用时,它会查找第一个依赖项main.o
这可能是文件或目标。由于没有名为main.o
的文件,因此会将main.o
作为目标。一旦找到main.o作为目标,它就会查找依赖项student.h house.h main.cpp
,因为它们作为文件make存在,然后执行$(CXX) $(CXXFLAGS) -c main.cpp
的配方(命令)。现在这是我不理解的部分。当第二个依赖关系car.o
出现时,查找car.h并找到它,但是没有命令告诉它生成.o文件。如何在这里生成.o文件?
答案 0 :(得分:2)
make包含几个隐式规则。这意味着make具有关于如何从.cpp文件创建.o文件的内置知识,而无需明确告诉它如何执行此操作。
来自文档:
编译C ++程序
n.o自动从n.cc,n.cpp或 n.C的配方形式为'$(CXX)$(CPPFLAGS)$(CXXFLAGS)-c'。我们 鼓励您使用后缀'.cc'代替C ++源文件 “.C”
您可能会认为这是一个内置规则看起来非常像:
%.o : %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
答案 1 :(得分:1)
有一个内置规则,用于从.cpp文件生成.o文件。
你告诉它有一个额外的car.h依赖,但不是如何制作car.o所以它回到内置规则,car.h作为一个附加的依赖。
你可以改变
main.o: student.h house.h main.cpp
$(CXX) $(CXXFLAGS) -c main.cpp
到
main.o: student.h house.h
它也会使用内置规则构建它。它记载了here。
如果你还没有运行objcopy命令,你也可以使用内置规则来制作测试二进制文件。
而不是
test: main.o car.o student.o house.o
$(CXX) $(CXXFLAGS) -o test main.o car.o student.o house.o
你可以使用
test: main.o car.o student.o house.o
答案 2 :(得分:1)
大多数make
(和类似的)程序预先定义隐式规则,例如将源文件(具有多个常见扩展中的任何一个)转换为目标文件(使用其默认扩展名)。
通常,这等同于:
.c.o:
$(CC) $(CFLAGS) -o $*.o -c $*.c
.cc.o:
$(CXX) $(CXXFLAGS) -o $*.o -c $*.cc
...对于其他常见扩展更多,因此它不仅知道如何将大多数典型扩展(.c,.cc,.cpp,.C等)编译为.o文件,还隐式地获取了一些变量的内容,你可以指定这些变量作为传递给编译器的标志集。
至于这些规则的细节:像.cc.o:
这样的规则是一个隐式规则 - 它基本上是说&#34;如果你有.cc文件,你可以用它创建一个.o文件排除&#34 ;.这些被用作一种支持 - 如果你有一个明确的规则告诉如何创建一些特定的.o文件,make
将按优先顺序使用 - 但如果没有明确的规则,它可以反过来隐含在隐含规则上。
$*
是一个内置宏,它扩展为源文件的基本名称(不带扩展名)。其中有许多仅用于源的基本名称($*
)和源文件的全名($<
)。还有其他一些像这样的自动变量,但从我所看到的大多数人使用它们的情况来看,他们很少需要在需要使用它们时查看它们。