编译过程
编译与链接的过程可以分解为4个步骤,分别是预处理、编译、汇编、链接,具体如下图所示:

1、预处理
g++ -E hello.cpp -o hello.i // 预处理指令
预处理主要是处理那些源代码文件只能够以 # 开始的预编译指令。比如 #include、#define等;
2、编译
g++ -S hello.i -o hello.s // 编译指令
编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析以及优化后产生相应的汇编代码文件,这部分往往是最核心和最复杂的部分;
3、汇编
将上一步的汇编代码转化为二级制的机器码,叫做目标文件;
4、链接
将多个目标文件以及库文件链接生成最终可执行文件;
在linux中的bash shell上对源文件的编译大致是这样的;
// g++编译
g++ -o server -g server.cpp xxx.cpp -l/usr/lib -L/usr/lib -lmuduo_net -lmuduo_base -lpthread
解释:
- o是生成文件类型,可选择- o可执行文件或者-E汇编文件等;
server是生成目标文件的名称,默认为 a.out ;
-g是调试、优化用的选项;
server.cpp 、 xxx.cpp 是需要编译的源文件;
-i 是头文件的搜索路径;
-L 是库文件的搜索路径;
-l 是要链接的库文件(动态库、静态库);
makefile的撰写
会不会写makefile,是是否具备完成大型工程的重要条件,makefile带来的好处就是自动化编译,一旦写好,只需要一个make命令,整个工程就会完全自动编译。make是一个命令工具,是一个解释makefile中指令的命令工具。makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。
下面写一个makefile的例子;
// 文件1 file1.h
#ifndef FILE1_H_
#define FILE1_H_
#ifdef __cplusplus
extern "C" {
#endif
void File1Print();
#ifdef __cplusplus
}
#endif
#endif
// 文件2 file1.cpp
#include<iostream>
#include"file1.h"
using namespace std;
void File1Print(){
cout<<"Print file1**********"<<endl;
}
// 文件3 file2.cpp
#include<iostream>
#include"file1.h"
using namespace std;
int main(){
cout<<"Print file2************"<<endl;
File1Print();
return 0 ;
}
// makefile 文件为:
helloworld:file1.o file2.o
g++ file1.o file2.o -o helloworld
file2.o:file2.cpp
g++ -c file2.cpp -o file2.o
file1.o:file1.cpp file1.h
g++ -c file1.cpp -o file1.o
clean:
rm -rf *.o helloworld
可见,一个makefile主要规则为:
A:B
(TAB) <command>
(TAB) <command>
每个命令行前必须有tab符号,上面的nakefile文件目的就是要编译一个helloworld的可执行文件,接下来分析一下:
1、helloworld 依赖于file1.o file2.o这两个目标文件:
helloworld: file1.o file2.o
2、编译出helloworld可执行文件,-o后面加你指定的目标文件名:
g++ file1.o file2.o -o helloworld
3、file2.o 依赖 file2.cpp 文件:
file2.o: file2.cpp
下面是编译出 file2.o 文件。-c 表示 g++ 只把给它的文件编译成目标文件,用源码的文件名命名但是把后缀由“.c” 或 “.cc” 或 “.cpp” 变成 “.o”。在这句中,可以省略 -o file2.o,编译器默认生成 file2.o 文件,这就是-c的作用:
g++ -c file2.cpp -o file2.o // 生成file2.o 可以省略
4、编译出 file1.o 文件:
file1.o: file1.cpp file1.h
g++ -c file1.cpp -o file1.o
5、当用户键入“make clean”命令时,会删除 *.o和helloworld文件。写好makefile文件,在命令行中直接键入make命令,就会执行makefile中的内容了:
clean:
rm -rf *.o helloworld
cmake文件的撰写
有时候工程文件过多,依赖关系过多,编写makefile效率低下而且容易出错,用cmake进行编写更加省时省力,下面说一下cmake的编写方法:
介绍之前还要回顾一下shell中g++编译源文件的格式:
g++ -o server -g server.cpp xxx.cpp -l/usr/lib -L/usr/lib -lmuduo_net -lmuduo_base -lpthread
具体组成上面介绍过了,而cmake大体结构框架类似于这个的组成。
我将上一篇博客中的muduo测试用作测试示例写了一个cmake:

cmake中常用的选项基本上就这些,包括链接库文件、搜索路径、生成目标文件的依赖项等。写完这个后,直接执行cmake . ,cmake会在当前(.代表当前)文件下查找CMakeLists.txt文件,然后自动去按照CMakeLists.txt文件中的内容去生成 makefile 等一系列文件:

可以看到执行cmake . 生成了一系列文件,其中由Makefile文件,再直接按照Makefile文件执行即可(与上面直接编写makefile是一样的),很方便的自动生成makefile,用熟练了真的是感觉非常方便!

可以看到生成了server可执行文件,直接运行,与上一篇博客的shell编译一样的效果:

看到效果一样的。
bye~
本文详细介绍了编译过程的四个步骤:预处理、编译、汇编和链接,并讨论了在Linux环境下使用bash shell进行编译。接着,文章深入探讨了makefile的重要性及编写规则,展示了一个简单的makefile示例。最后,对比了makefile,文章介绍了cmake的使用,指出在大型工程中cmake能更高效地管理编译过程,通过实例演示了如何编写CMakeLists.txt文件并生成makefile。

被折叠的 条评论
为什么被折叠?



