g++编译4步骤
Build和Make意味着编译项目中所有源代码文件的代码,通常是一个递增过程,如果项目中有3个文件,只有1个文件被修改,只重新编译该文件。
Build All重新编译所有的源代码文件
g++ 编译参数
-I 指定头文件所在目录位置
-c 只做预处理,编译,汇编。得到二进制文件
-g 编译时添加调试文件,用于 gdb 调试
-Wall 显示所有警告信息
-D 向程序中“动态”注册宏定义
-l 指定动态库库名
-L 指定动态库路径
库
库是一种可执行代码的二进制形式
库有两种:静态库(.a、.lib)和动态库(.so、.dll)
静态库
链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中
静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似
一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件
Linux下使用ar工具、Windows下vs使用lib.exe,将目标文件压缩到一起,并且对其进行编号和索引,以便于查找和检索
如何使用呢?
首先编写静态库代码
a.h
#pragma once // 防止多次导入
class StaticMath
{
public:
StaticMath();
~StaticMath();
static int add(int a, int b); // 声明为静态函数不用创建对象即可使用该方法
static int sub(int a, int b);
};
a.cpp
#include <iostream>
#include "a.h"
int StaticMath::add(int a, int b)
{
return a + b;
}
int StaticMath::sub(int a, int b)
{
return a - b;
}
命令:
// 将代码文件编译成目标文件.o
g++ -c a.cpp
// 静态库名字以 lib 开头,以.a 结尾,通过ar工具将目标文件打包成.a静态库文件
ar rcs liba.a a.o
编写测试代码 b.cpp :
#include "b.h"
#include "a.h"
#include <iostream>
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
cout << StaticMath::add(a, b) << endl;
cout << StaticMath::sub(a, b) << endl;
return 0;
}
命令:
// 指定静态库的搜索路径(-L选项)、指定静态库名(不需要lib前缀和.a后缀,-l选项)
g++ b.cpp liba.a -o b
还可以将多个源代码变为一个静态库进行操作:
编写两个源代码:
a.h
#pragma once
int add(int a, int b);
a.cpp
#include "a.h"
int add(int a, int b)
{
return a + b;
}
b.h
#pragma once
int mul(int a, int b);
b.cpp
#include "b.h"
int mul(int a, int b)
{
return a * b;
}
命令:
g++ -c a.cpp b.cpp
ar rcs libaddandmul.a a.o b.o
编写测试代码:
c.h
#pragma once
#include "a.h"
#include "b.h"
c.cpp
#include <iostream>
#include "c.h"
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
cout << add(a, b) << endl;
cout << mul(a, b) << endl;
return 0;
}
g++ c.cpp libaddandmul.a -o c
动态库
不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
动态库把对一些库函数的链接载入推迟到程序运行的时期
可以实现进程之间的资源共享。(因此动态库也称为共享库)
将一些程序升级变得简单
甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)
在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数做出初始化的入口,通常在导出函数的声明时需要有_declspec(dllexport)关键字。
Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。
不需要打包工具(ar、lib.exe),直接使用编译器即可创建动态库
动态链接库的名字形式为 libxxx.so,前缀是lib,后缀名为“.so”
制作动态库的步骤:
源代码依旧使用上文中的 a.cpp 和 b.cpp,生成位置无关的.o 文件
g++ -c a.cpp b.cpp -fPIC
gcc -shared -o libmy.so a.o b.o
g++ c.cpp -o c -lmy -L.
./c
执行出错,加载共享库时:libmy,不能打开共享对象文件:没有这样的文件或目录
出错原因分析:
连接器: 工作于链接阶段,工作时需要 -l 和 -L
动态链接器: 工作于程序运行阶段,工作时需要提供动态库所在目录位置
指定动态库路径并使其生效,然后再执行文件
通过环境变量指定动态库所在位置:export LD_LIBRARY_PATH=动态库路径
环境变量是进程的概念,关闭终端之后再打开,是两个进程,环境变量发生了变化。
要想永久生效,需要修改 bash 的配置文件:vi ~./bashrc
修改后要使配置文件立即生效:. .bashrc 或者 source .bashrc 或者重开终端让其自己加载