1. 编译与链接
编译与链接的过程可分解为四个步骤,分别是预处理
、编译
、汇编
以及链接
,可以用一张图来描述此过程:
2. 预处理
我们接下来都以示例来描述相应的过程
以这样的一个示例:
#include <iostream>
using namespace std;
int main()
{
cout << "hello world\n" << endl;
return 0;
}
手动执行预处理(-E表示预处理):
g++ -E hello.cpp -o hello.i
得到hello.i文件,可以用vim hello.i
查看这一文件:
总结一下预处理过程中主要做了什么工作:
- 1.将所有的#define删除,并且展开所有的宏定义(例:#define a b,即将程序中所有a用b替换)
- 2.处理所有的条件预编译指令,比如#if, #ifdef,#elif,#else,#endif
- 3.处理#include预编译指令,将被包含的文件插入到该预编译指令的位置
- 4.过滤所有的注释"//"和’/**/'中的内容
- 5.添加行号和文件名标识,比如# 1 “hello.cpp”
- 6.保留所有的#pragma编译器指令
3. 编译与汇编
还是以上述那个示例,执行以下代码,对预处理得到的.i文件进行编译得到汇编代码(.s文件):
g++ -S hello.i -o hello.s
用vim hello.s查看汇编代码:
------------------------------------------总结-----------------------------------------------
编译过程就是把预处理完的文件进行一系列的词法分析
、语法分析
、语义分析
以及优化
后产生相应的汇编代码
以一张图来描述该过程:
4. 链接
- 把每个源代码模块独立地编译,然后按照要求将它们”组装”起来,这个组装模块的过程就是链接
- 从原理上讲,它的工作就是把一些指令对其他符号地址的引用加以修正。链接过程主要包括了地址和空间分配、符号决议和重定位等步骤
- 链接大致可分为
静态链接
与动态链接
两种方式
4.1 静态链接
- 所谓
静态链接
指的就是对函数库的链接放在编译时期完成 - 与目标文件有关联的函数库被链接合成一个可执行文件,程序在运行时与函数库无瓜葛;这些函数库被称为静态库,通常文件名为"
libxxxx.a
"的形式 - 下面以一个示例来演示该如何编译和使用静态链接库:
//add.h
#ifndef ADD_H
#define ADD_H
int add(int a, int b);
#endif
//add.cpp
#include "add.h"
int add(int a, int b)
{
return a+b;
}
//sub.h
#ifndef SUB_H
#define SUB_H
int sub(int a, int b);
#endif
//sub.cpp
#include "sub.h"
int sub(int a, int b)
{
return a-b;
}
//main.cpp
#include "add.h"
#include "sub.h"
#include <iostream>
using namespace std;
int main()
{
cout << "1+2=" << add(1,2) << endl;
cout << "1-2=" << sub(1,2) << endl;
return 0;
}
- 首先将add.cpp与sub.cpp编译成.o文件:
g++ -c add.cpp
g++ -c sub.cpp
2. 由.o文件创建静态库(.a文件):
ar cr libmymath.a sub.o add.o
ar tv libmymath.a //查看库文件中的.o文件
了解更多有关ar命令linux ar命令
- 在程序中使用静态库:
g++ -o main main.cpp -L. -lmymath //生成.main文件
g++命令生成目标文件时指定静态库名(即指定mymath而不是libmymath.a)
,g++将会从静态库中将公用函数连接到目标文件中;g++会在静态库名前加上前缀lib,然后追加扩展名.a得到静态库文件名来查找静态库文件
- 执行main文件:
4.2 动态链接
- 把对一些库函数的链接载入推迟到程序运行时期,这就是动态链接
- 通常文件名为"libxxxx.so"
- 还是以上面的程序来演示编译和使用动态链接库:
- 生成动态库文件:
//可以用以下命令
g++ -fPIC -o add.o -c add.cpp
g++ -fPIC -o sub.o -c sub.cpp
g++ -shared -o libmymath.so add.o sub.o
//也可以用以下一条命令
g++ -shared -o libmymath.so add.cpp sub.cpp
//-fPIC表示编译为位置独立的代码
- 使用g++命令生成目标文件:
g++ -o main main.cpp -L. -lmymath
我们发现这样子直接编译报错了,说找不到动态库文件libmymath.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件,若找到,则载入动态库,否则将提示上述的错误
既然找到了问题所在,那我们直接将该动态库拷贝到/usr/lib目录中
cp libmymath.so /usr/lib/
4.3 静态链接库、动态链接库各自的特点
- 1.动态链接库有利于资源共享
当某个程序在运行中要调用某个动态链接库函数的时侯,操作系统首先会查看所有正在运行的程序,看在内存中是否有此库函数的拷贝,如果有,则让其共享那一个拷贝,没有才链接载入;而静态链接库,如果系统中对各程序都要调用某个静态链接库函数,则每个程序都要将这个库函数拷贝到自己的代码段,显然更占用内存资源
- 2.将一些程序升级变得简单
用静态链接库,如果库发生变化,使用库的程序要重新编译;使用动态库,只要动态库提供给该程序的接口没变,只要重新用新生成的动态库替换原来就可以了
- 3.可以做到链接载入完全由程序员在程序代码中控制
程序员在编写程序时,可以明确指出什么时候或者什么情况下,链接载入哪个动态库函数
- 4.由于静态库在编译时,就将库函数装载到程序中,而动态库函数必须在运行时才被装载,所以程序在执行时,用静态库速度更快一些
-----------------------------------------------get-----------------------------------------------
1.编译与链接的几大步骤
2.静态链接与动态链接的使用
3.静态链接与动态链接的比较以及使用