1 c++静态库与动态库
1.1 动机
库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层 库。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。
linux: .a .so-----库命名:libxxx.a/libxxx.so (xxx-库名)
window: .lib .dll
库制作:目的是为了提高代码复用率。同时可做代码保密。
note: 开发完成后,提供给用户的文件只需要头文件(.h)与库文件即可(.a/.so)
比较:
1. 静态库:链接时与目标文件链接成可执行文件,缺点:每次用时需要拷贝一份占用内存,相对来说浪费资源。静态链接。
2. 动态库:运行时链接载入库函数,只需要一份共享的库。节约资源。动态链接。
静态链接: 在链接阶段,将源文件中用到的库函数与汇编生成的目标文件.o合并生成可执行文件。该可执行文件可能会比较大。多个程序调用会复制多份。这种链接方式的好处是:方便程序移植,因为可执行程序与库函数再无关系,放在如何环境当中都可以执行。
动态链接: 多个程序共用一个库,这个目标文件在内存中只有一份,供所有程序使用。
并且在程序运行过程中动态调用库文件,很方便,又不占空间,但是动态链接有一个缺点就是可移植性太差。
2 静态库制作
静态库的加载:链接阶段直接复制一份到链接阶段(参考一中c++执行过程)。
# 准备文件结构
├── include
│ └── head.h
└── head.cpp
├── lib
│ └── libcalc.a
├── main.cpp
└── src
———head.cpp
# 1 生成目标文件(在include文件下执行)
g++ -c head.cpp -o head.o
# 2 制作静态库
ar rcs libcalc.a head.o
# 制作完成后可以将libcalc.a拷贝到lib文件下
#3 运行测试静态库
g++ main.cpp -o main -I ./include/ -l calc -L ./lib/
# -I 查找 head.h头文件 -l 查找calc静态库(取libcalc后半部分),-L库位置。
note: vscode运行,需要添加库路径。
动态库制作# 备注,如果要在vscode运行,需要在task.json中添加head.h,head.cpp的路径。
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
/*******************添加库链接(添加路径需要自己添加)***************/
"-I","/home/.../c++学习/lesson_2/calculate","/home/.../c++学习/lesson_2/calculate/head.cpp",
/******************************************/
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
动态库制作 ],
1.3 动态库制作
动态库加载:运行时搜索共享库路径。
# 文件结构
├── calculate
│ ├── head.cpp
│ └── head.h
├── description.md
├── include
│ └── head.h
├── lib
│ └── libcalc.a #上面制作的静态库,可有可无
├── main.cpp
└── src
└── head.cpp
# 1 生成目标文件(calculate文件下执行)
g++ -c -fpic head.cpp
# 2 制作动态库
g++ -shared *.o -o libcalc.so
#制作完成后可以将libcalc.so拷贝到lib文件下
# 3 动态库使用
g++ main.cpp -o main -I include/ -l calc -L lib/
#此时生成了main可执行文件
./main #执行,注意此时不能运行,问题在于程序main找不到库calc
#可以ldd查看动态依赖库
ldd main
# 解决方法,需要了解程序运行是寻找动态库的优先级(见上)。
# 推荐设置环境变量+/etc/设置cat /etc/ld.so.conf
# 环境变量对应三种,1)零时配置,终端关闭就消失。2 用户级配置(修改.bashrc),永久生效。3 系统级配置(修改profile)永久生效。
# 这里修改/etc..文件列表。
# 1 查看是否存在该文件,注意该文件为二进制文件,不可修改
ls /etc/ld.so.cache
# 修改配置文件
sudo vim /etc/ld.so.conf
# 在最后添加.so的局对路经
sudo ldconfig # 使生效
# 查看
cat /etc/ld.so.conf
# 此时可以运行及ldd查看。
./main
# 测试成功
1.4 附录:
#################head.h##############
#ifndef _HEAD_H
#define _HEAD_H
#include<iostream>
class Calc{
public :
Calc(int num1, int num2):a(num1),b(num2){};
~Calc(){};
void add();
void sub();
void mul();
void div();
private:
int a;
int b;
};
#endif
####################head.cpp###################
#include<iostream>
#include"head.h"
using namespace std;
void Calc::add(){
cout<<"a+b = "<<a+b<<endl;
}
cat /etc/ld.so.conf
void Calc::sub(){
cout<<"a-b = "<<a-b<<endl;
}
void Calc::mul(){
cout<<"a*b = "<<a*b<<endl;
}
void Calc::div(){
if(b == 0){
cout<<"error!"<<endl;
}
else
cout<<"a/b = "<<a/b<<endl;
}
###########################main.cpcat /etc/ld.so.confp#################
#include<iostream>
#include"head.h"
using namespace std;cat /etc/ld.so.conf
int main(){
Calc mycalculator(6,3);
mycalculator.add();
mycalculator.sub();
mycalculator.mul();
mycalculator.div();
cout<<endl;
return 0;cat /etc/ld.so.conf
}