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

Understanding a makefile better - How the .o file gets generated in this case

本文关键字:何生成 文件 这种情况下 makefile 更好      更新时间:2023-10-16

我目前有以下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,因为这些依赖项是作为一个文件存在的,然后执行配方(命令),即$(CXX) $(CXXFLAGS) -c main.cpp。这是我不明白的部分。当出现第二个依赖car.o turn时,make查找car.h并找到它,但没有命令告诉它生成.o文件。这里是如何生成.o文件的?

make包含几个隐式规则。这意味着make拥有关于如何从.cpp文件创建.o文件的内置知识,而无需明确告诉它如何创建。

来自文件:

编译C++程序

n.o由n.cc、n.cpp或n.C,配方形式为"$(CXX)$(CPPFLAGS)$(CXXFLAGS)-C"。我们鼓励您对C++源文件使用后缀".cc",而不是'.C'

你可能会认为这是一个内置规则,看起来很像:

%.o : %.cpp
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@

点击此处阅读更多关于这些隐含规则的信息。

有一个内置规则,用于从.cpp文件生成.o文件。

你已经告诉它,is对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

它也会使用内置规则来构建它。这里记录了它。

如果您没有同时运行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

大多数make(和类似的)程序都预先定义了隐式规则,用于将源文件(具有许多常见扩展名中的任何一个)转换为对象文件(使用默认扩展名)。

通常,这相当于这样的东西:

.c.o:
    $(CC) $(CFLAGS) -o $*.o -c $*.c
.cc.o:
    $(CXX) $(CXXFLAGS) -o $*.o -c $*.cc

对于其他常见的扩展有更多,因此它不仅知道如何将大多数典型的扩展(.c、.cc、.cpp、.c等)编译为.o文件,而且还隐式地获取一些变量的内容,您可以将其指定为一组标志,以便在编译器这样做时传递给它。

至于这些规则的细节:像.cc.o:这样的规则是一个隐式规则——它基本上说"如果你有一个.cc文件,你可以使用这个规则从中创建一个.o文件"。它们被用作一种后盾——如果你有一个明确的规则来告诉你如何创建某个特定的.o文件,make会优先使用它——但如果没有明确的规则,它可以依靠隐式规则。

$*是一个内置的宏,它扩展到源文件的基本名称(没有扩展名)。其中有许多仅用于源的基本名称($*)和源文件的全名($<)。还有很多其他类似的自动变量,但据我所见,大多数人很少使用它们,以至于他们必须在需要使用它们时查找它们。