[英]Makefile Dependencies, What Should Be a Dependency?
我有一个关于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
我对依赖项以及链接的工作方式有些迷失。
任何帮助,将不胜感激! 谢谢!
依赖项是需要更改源代码才能进行更改的所有内容。 这不仅包括您的#include
-d标头,还包括间接包含的系统标头,甚至(原则上)还包括编译器和构建链本身(在升级C ++编译器时,应重新编译所有软件)。 如果您的某些C ++代码是从某些源生成的(例如,通过GNU bison或Qt moc之类的工具或您自己的脚本生成),则源和生成工具都是依赖项。 另请参阅有关程序包管理器的信息 。
实际上, GCC编译器能够输出大多数make
依赖项,尤其是使用-M
和相关的处理器选项 。 阅读有关自动依赖项生成的信息 。 另请参见本 。
(实际上,您通常不会在Makefile
编写对编译器本身的某些显式依赖关系;但是,在升级编译器时,请不要忘记make clean
)
除非您的main.cpp
包含my_strings.cpp
(这不是常规的并且味道很差),否则您的make
规则将不会从my_strings.cpp
到main.o
进行依赖。 但是您的main.cpp
可能是#include
-ing(直接或间接) my_strings.h
因此main.o
应依赖于main.cpp
还应依赖于my_strings.h
根据经验,目标文件my_strings.o
取决于源文件my_strings.cpp
和所有直接或间接包含在其中的#include
-d 头文件 。 你的主要program
执行依赖于它的所有目标文件和要链接到它的库。 g++
程序参数的顺序非常重要。
它像图书馆一样使用它,对不对?
根据显示的内容,您没有任何自己的库 (但您可能使用标准的C ++库,也许还使用其他一些系统库)。 在Linux上,这些文件是lib*.a
文件(静态库)或lib*.so
文件(共享库)。 库是目标代码(有时是其他资源)的有组织的集合。
我对依赖项以及链接的工作方式有些迷失。
了解源代码文件, 目标文件 (它们包含重定位信息)和可执行文件 (在Linux上,目标文件和可执行文件以及共享库使用ELF格式)之间的区别。 另请阅读有关编译器 , 链接器 ( g++
程序可以同时运行)和构建自动化 (要使用make
的角色)的作用。
阅读程序库HowTo以及有关翻译单元和链接器 (及名称修改 )的更多信息,尤其是Levine的有关链接器和加载器的书。
参见这 & 该 & 此 (约实例Makefile
为C ++程序)。
顺便说一句,在编译C ++代码时,应该使用g++
(不是gcc
)。 有很大的区别(即使gcc
有时能够编译C ++或Fortran代码,您也大多会使用gcc
来编译C代码)。 并且(假设您专门使用GNU make)您的Makefile
应该提到$(CXX)
(不是g++
)。 您需要了解make
的内置规则(运行一次make -p
来获取它们),然后最好利用它们(例如,使用$(COMPILE.cc)
或$(COMPILE.cpp)
等)。 您当然应该将-Wall -Wextra
(以获取所有警告,甚至更多)和-g
(以获取调试信息)传递给g++
。 实际上,您应该在Makefile
设置CXXFLAGS
变量。
花时间仔细阅读GNU make文档和Invoking GCC 。
查看现有自由软件项目的Makefile
-s。 由于各种原因,一些项目正在使用诸如autoconf
或cmake
类的工具生成其Makefile
-s。 但是大多数简单的项目不需要这种通用性,因此您应该能够为C ++项目编写自己的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
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构建时,它将建立一个依赖树,其根目录以main.o为基础,然后尝试构建main所需的所有.o文件。 当所有.o文件构建完毕后,它们将被链接。
通过遵循依赖关系树,Make可以确保在更改其中一个依赖模块时,将链接/构建main。
但是,如果您从包含的头文件之一#define MAXSTRING 32
使用了诸如说常量之类的内容,则您不再仅依赖于.o文件,而是依赖于头文件的内容,因此需要确保main.o如果因为链接不够而更改了标头,则会构建此链接,因此您需要在依赖项中添加.h
main.o
/ | \
my_math.o my_strings.o my_strings.h
当然,有一些方法可以使报头更健壮,从而避免这种依赖性,但这是另一个问题。
您的cpp
文件在编译方面不依赖于其他cpp
文件。 简单的cpp
文件应仅依赖于h
文件。
在您的问题中,您说main.cpp
取决于my_math.cpp
和my_strings.cpp
,但我认为这是不正确的。 我猜你那里有#include
,这是你的依赖。
一般来说, cpp
文件的依赖项都是#include
d h
文件。
通常, cpp
文件之间没有依赖关系。 您只需通过编译即可生成o
文件。 然后,最终的二进制文件取决于所有o
文件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.