程序编译过程及makefile依赖
编译过程
1. 预处理 (Preprocessing)
预处理器处理源代码中的预处理指令,如宏定义 (#define
)、文件包含 (#include
)、条件编译指令 (#ifdef
, #ifndef
, #endif
) 等。预处理的输出是纯C/C++代码,不再包含任何预处理指令。
预处理的命令通常是:
g++ -E source.cpp -o source.i
2. 编译 (Compilation)
编译器将预处理后的代码转换为汇编代码。这个过程中,编译器会进行语法检查、语义分析、优化代码等。编译的输出是汇编代码文件。
编译的命令通常是:
g++ -S source.i -o source.s
3. 汇编 (Assembly)
汇编器将汇编代码转换为目标机器码 (Object Code),生成目标文件。这些目标文件是二进制格式的,但还不是可执行文件。
汇编的命令通常是:
g++ -c source.s -o source.o
4. 链接 (Linking)
链接器将一个或多个目标文件和库文件合并,生成最终的可执行文件。这个过程中,链接器会处理符号解析、地址重定位等。
链接的命令通常是:
g++ source.o -o executable
makefile依赖
在编写 Makefile
时,指定的依赖关系并不是与程序的实际依赖关系。以下是对依赖关系。比如:
当 main.cpp
中包含了 test.hpp
,编译时不需要显式指定 test.hpp
作为依赖文件。这是因为在预处理阶段,预处理器会将 test.hpp
的内容直接插入到 main.cpp
中,从而使 main.cpp
内容完整。
然而,如果 main.cpp
中包含了 test.h
,情况会有所不同。头文件 test.h
仅包含函数声明,而实际的实现通常在 test.cpp
中。在这种情况下,除了需要在 main.cpp
中包含 test.h
外,还需要在 Makefile
中指定 test.cpp
进行编译,以生成可以链接的目标文件。
make使用文件的创建和修改时间来判断是否应该更新一个目标文件。即make根据Makefile中的依赖文件的修改时间是否大于目标文件的创建时间来重新编译对应的依赖文件,最后重新生成可执行文件。