Makefile依赖关系,什么是依赖关系?

时间:2017-01-08 07:26:40

标签: c++ c makefile

我有一个关于makefile依赖关系的概念性问题,这是因为我在网上看到有关此问题的不一致。

我们说我有以下文件:

main.cpp         uses->     my_math.cpp and my_strings.cpp
my_math.cpp      uses->     my_math.h
my_strings.cpp   uses->     my_strings.h

如果我有一个makefile,一般支出:

program: $(all_objs)
     g++ $(all_objs) -o program
main.o: ...
     .......
my_math.o: ...
     .......
my_strings.o: ...
     .......

我不知道每个依赖项应该包含哪些内容。比如,math.o #includes my_math.h和my_strings.h,这是否意味着如果我更改my_math.h,main.cpp需要重新编译?但为什么?它像图书馆一样使用它,对吗?它不需要重新编译main.cpp或者它吗?

如同,main.o的结果应该是:

1) main.o: main.cpp
         gcc -c main.cpp

2) main.o: main.cpp my_strings.cpp my_strings.h my_math.cpp my_math.h
         gcc -c main.cpp

3) main.o: main.cpp my_strings.cpp my_strings.h my_math.cpp my_math.h
         gcc -c main.cpp my_strings.cpp my_math.cpp

我对依赖关系以及链接的工作方式有点迷失。

任何帮助将不胜感激!谢谢!

3 个答案:

答案 0 :(得分:4)

依赖项是其更改需要重新编译源代码的所有内容。这不仅包括您的#include - d标头,还包括间接包含的系统标头,甚至(原则上)编译器和构建链本身(当您升级C ++编译器时,应该重新编译你的所有软件)。如果某些C ++代码是从某些源生成的(例如,通过GNU bison或Qt moc等工具,或者由您自己的脚本生成),则源和生成工具都是依赖关系。另请阅读package managers

实际上,GCC编译器能够输出大多数make个依赖项,特别是-M和相关processor options。另请阅读auto dependencies generation。另请参阅this

(实际上,您通常不会在Makefile中对编译器本身的某些显式依赖进行编码;但是在升级编译器时不应忘记make clean < / SUP>

除非您main.cpp包含my_strings.cpp(这不是传统且非常糟糕),否则您的make规则不会依赖my_strings.cppmain.o {1}}。但是,main.cpp可能#include - (直接或间接)my_strings.h因此main.o不仅应依赖于main.cpp,还应依赖于my_strings.h

根据经验,您的目标文件my_strings.o取决于源文件my_strings.cpp以及直接或间接#include的所有标头文件 - d在里面。您的主program可执行文件取决于其所有目标文件以及您链接到它的库。 g++的程序参数顺序非常重要。

  

它像图书馆一样使用它,对吗?

根据您所展示的内容,您没有自己的libraries(但您可能使用标准C ++库,也许还有其他一些系统库)。在Linux上,这些是lib*.a个文件(静态库)或lib*.so个文件(共享库)。图书馆是一个有组织的目标代码集合 - 有时是其他资源。

  

我对依赖关系以及链接的工作方式有点迷失。

了解source code个文件之间的区别,object files(它们包含relocation信息)和executables(在Linux上,目标文件和可执行文件以及共享库正在使用ELF格式)。另请阅读compilerslinkers的作用(g++程序可以同时运行)&amp; build automation(您正在使用make)。

阅读Program Library HowTo以及更多关于translation unitslinkers(&amp; name mangling)的内容,特别是Levine关于Linkers & loaders的书。

另见this&amp; that&amp; this(有关C ++程序Makefile的示例)。

顺便说一下,在编译C ++代码时应该使用g++(而不是gcc)。存在显着差异(即使gcc 有时能够编译C ++或Fortran代码,您将主要使用gcc来编译C代码。并且(假设您使用特定的GNU make),Makefile应该提及$(CXX)(而不是g++)。您需要了解make的内置规则(运行一次make -p才能获得它们)并且您最好利用它们(例如使用$(COMPILE.cc)$(COMPILE.cpp)等。 ..)。您当然应该将-Wall -Wextra(以获取所有警告,甚至更多)和-g(以获取调试信息)传递给g++。实际上,您应该在CXXFLAGS

中设置Makefile变量

请仔细阅读GNU make documentationInvoking GCC

查看现有免费软件项目的Makefile。出于各种原因,某些项目使用Makefileautoconf等工具生成他们的cmake。但是大多数简单的项目都不需要这种通用性,你应该能够为你的C ++项目编写自己的Makefile。当然,从现有代码中汲取灵感。

答案 1 :(得分:3)

如果你有

main.cpp         uses->     my_math.cpp and my_strings.cpp
my_math.cpp      uses->     my_math.h
my_strings.cpp   uses->     my_strings.h

Make的目的是通过构建.o文件和链接.o文件,以两种不同的方式维护模块之间的依赖关系。

您可以将其描绘为依赖树,其中main.o是根

                         main.o 
                       /       \
                   my_math.o   my_strings.o

对于每个.o,还有一个关于源文件的依赖树,例如

    main.o               my_math.o               my_strings.o
   /      \              /        \              /           \ 
main.cpp   main.h     my_math.cpp  my_math.h  my_strings.cpp my_strings.h

因此,当make build时,它会在main的根目录下设置一个依赖树,然后尝试构建main所需的所有.o文件。当所有.o文件都已构建完成后,它们就会被链接。

通过遵循依赖关系树Make确保在更改其中一个依赖模块时链接/构建main。

但是,如果您使用了包含标题#define MAXSTRING 32之一的常量,那么您不再仅仅依赖于.o文件,那么您需要依赖于标题内容,因此您需要确保如果标题被更改,则构建main.o,因为链接不够,所以你在依赖项中添加.h

                               main.o 
                            /     |     \
                   my_math.o my_strings.o my_strings.h

当然,有一些方法可以使标题更加健壮,以避免这种依赖,但这是另一个问题。

答案 2 :(得分:1)

您的cpp文件在编译方面不依赖于其他cpp个文件。简单cpp文件应仅依赖于h个文件。

在您的问题中,您说main.cpp取决于my_math.cppmy_strings.cpp,但我认为这不是真的。我猜你在那里有#include,这些都是你的依赖。

一般来说,cpp文件的依赖关系都是#include d h个文件。

通常cpp个文件之间没有依赖关系。您只需通过编译生成o个文件即可。然后,您的最终二进制文件取决于所有o个文件。