先以单文件编译为例子 hello.cc:html
#include<iostream> using namespace std; int main() { cout << "Hello World" << endl; return 0; }
编译加运行的命令ios
g++ 'hello.cc' -o 'hello' -Wall -g -O2 -std=c++17 && hello
其含义就是将hello.cc源文件编译输出为hello这个可执行文件并运行, 获得一个"Hello World"的输出, 那么这个简单的 g++ 命令背后发生了什么呢?c++
上述gcc命令其实依次执行了四步操做:shell
1.预处理(Preprocessing)macos
2.编译(Compilation)测试
3.汇编(Assemble)ui
4.连接(Linking)spa
.c为后缀的文件:c语言源代码文件.net
.a为后缀的文件:是由目标文件构成的库文件code
.cpp为后缀的文件:是c++源代码文件
.h为后缀的文件:头文件
.o为后缀的文件:是编译后的目标文件
.s为后缀的文件:是汇编语言源代码文件
.m为后缀的文件:Objective-C原始程序
.so为后缀的文件:编译后的动态库文件
预处理阶段作的事情: 宏的替换,还有注释的消除,还有找到相关的库文件,将#include文件的所有内容插入。若用<>括起文件则在系统的INCLUDE目录中寻找文件,若用""括起文件则在当前目录中寻找文件。预处理以后获得的仍然是文本文件,但文件体积会大不少, 生成的文件是 -i 文件, 对hello.cc文件进行预处理的命令
g++ -E hello.cc -o hello.i
或者直接调用cpp命令
cpp hello.cc -o hello.i
-E
是指让编译器在预处理以后就退出,不进行后续编译过程, -o
是指指定输出文件名, 在处理成.i文件之后, 文件的体积会大的多, 变成了4w多行的文件
这里的编译不是指程序从源文件到二进制程序的所有过程,而是指将通过预处理以后的程序转换成特定汇编代码(assembly code)的过程。将.i预处理文件编译为汇编代码的命令是cc1, 使用-S能够直接从.cc文件到汇编代码
g++ -S hello.cc -o hello.s
hello.s文件的部份内容
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 14 sdk_version 10, 14 .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc ## %bb.0: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp subq $16, %rsp
汇编过程将上一步的汇编代码转换成机器码(machine code),这一步产生的文件叫作目标文件,是二进制格式。gcc
汇编过程经过as
命令完成:
as hello.s -o hello.o
等价于
g++ -c hello.s -o hello.o
输出的hello.o为二进制文件
这一步会为每个源文件产生一个目标文件。
连接过程将多个目标文件以及所需的库文件(.so等)连接成最终的可执行文件(executable file)。
命令大体以下
ld -o test.out test.o inc/mymath.o ...libraries...
因此其实简单的一行命令
g++ hello.cc
其中其实包含了好几层流程
添加两个文件 math.h
`int add(int a, int b);`
和math.cc
, 定义一下这个add方法
int add(int a, int b) { return a + b; };
而后在hello.cc
中调用一下这个add方法
#include<iostream> #include "math.h" using namespace std; int main() { cout << "Hello World" << endl; cout << add(1, 2) << endl; return 0; }
再直接运行
g++ hello.cc
试试, 发现收到以下报错
Undefined symbols for architecture x86_64: "add(int, int)", referenced from: _main in hello-9842e2.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
看到说add(int, int)这个方法是未定义符号, 但是明明将math.h引入进来了啊, 实际上是由于没有连接到math.cc生成的.o文件, 连接math.o再生成可执行文件试试
g++ -c hello.cc math.cc
这样生成了hello.o math.o两个二进制文件, 而后连接math.o和hello.o生成可执行文件
g++ hello.o math.o -o hello
再运行hello试试, 发现获得了想要的输出。或者还有一个更简单的办法
g++ hello.cc math.cc -o hello
通过我测试, 能够直接获得上面两个命令合并的效果。
上面的命令, 在中大型项目中, 通常使用makefile
文件进行整合, makefile
文件的做用和写法单独写一个文章。
https://www.cnblogs.com/ericl...
https://blog.csdn.net/csdn912...