更好地理解makefile - 在这种情况下如何生成.o文件

时间:2014-10-30 22:36:15

标签: c++ makefile g++

我目前有以下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文件?

3 个答案:

答案 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 $@

详细了解这些隐式规则herehere

答案 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将按优先顺序使用 - 但如果没有明确的规则,它可以反过来隐含在隐含规则上。

$*是一个内置宏,它扩展为源文件的基本名称(不带扩展名)。其中有许多仅用于源的基本名称($*)和源文件的全名($<)。还有其他一些像这样的自动变量,但从我所看到的大多数人使用它们的情况来看,他们很少需要在需要使用它们时查看它们。