我有一个关于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
我对依赖关系以及链接的工作方式有点迷失。
任何帮助将不胜感激!谢谢!
答案 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.cpp
到main.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格式)。另请阅读compilers,linkers的作用(g++
程序可以同时运行)&amp; build automation(您正在使用make
)。
阅读Program Library HowTo以及更多关于translation units和linkers(&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 documentation和Invoking GCC。
查看现有免费软件项目的Makefile
。出于各种原因,某些项目使用Makefile
或autoconf
等工具生成他们的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.cpp
和my_strings.cpp
,但我认为这不是真的。我猜你在那里有#include
,这些都是你的依赖。
一般来说,cpp
文件的依赖关系都是#include
d h
个文件。
通常cpp
个文件之间没有依赖关系。您只需通过编译生成o
个文件即可。然后,您的最终二进制文件取决于所有o
个文件。