一、库文件
-
库文件是计算机上的一类文件,是二进制文件。
-
库文件有两种:静态库与动态库
- 静态库在程序的链接阶段被复制到程序中
- 动态库在程序运行时由系统动态加载到内存中使用
-
库的优点:代码保密
C/C++反编译的还原度很低,但是Java还原度可以达到95%以上
二、静态库的制作与使用
1.命名规范
不同的操作系统,对于静态库的名称有命名规范。
- Linux: libxxx.a
- Windows: libxxx.lib
xxx为自定义库名
2.静态库的制作
-
使用g++ 获得.o文件
-
将 .o 文件打包,使用ar工具(archive)
Linux: ar rcs libxxx.a xxx.o xxx.o
Windows: ar rcs libxxx.lib xxx.o xxx.o
3.示例
我们创建四个文件;
//filename:header.h
#ifndef _HEADER_H_
#define _HEADER_H_
int add2(int x);
int add3(int x);
#endif
//filename:add2.cpp
#ifndef _ADD2_CPP_
#define _ADD2_CPP_
#include "header.h"
int add2(int x){
return x + 2;
}
#endif
//filename:add3.cpp
#ifndef _ADD3_CPP_
#define _ADD3_CPP_
#include "header.h"
int add3(int x){
return x + 3;
}
#endif
//filename:main.cpp
#include "header.h"
#include <iostream>
int main()
{
int num = 3;
std::cout << add2(num) << std::endl;
std::cout << add3(num) << std::endl;
return 0;
}
执行命令:g++ add2.cpp add3.cpp -c 后,在当前目录生成add2.o add3.o两个目标代码文件。
执行命令:ar rcs libadd.a add2.o add3.o 后,在当前目录下生成 libadd.a 静态库文件
此时,我们通过g++去编译 m a i n . c p p main.cpp main.cpp。
g++ main.cpp -o app
会出现如下错误:
/tmp/ccymQuSg.o:在函数‘main’中:
main.cpp:(.text+0x15):对‘add2(int)’未定义的引用
main.cpp:(.text+0x42):对‘add3(int)’未定义的引用
collect2: error: ld returned 1 exit status
原因是我们虽然引入了add2 add3两个函数的声明,但未将实现两个函数的静态库导入。
重新执行命令:
g++ main.cpp -o app -l add -L ./
编译成功,此时运行生成的 a p p . o u t app.out app.out,可以得到正确的结果。
- -l 后的参数是导入的库名称
- -L后的参数是导入的库的位置。
三、动态库的制作与使用
1.命名规则
-
Linux: libxxx.so
lib:固定前缀
xxx:库名,自定义
.so:固定后缀
在Linux下动态库是一个可执行文件。
-
Windows: libxxx.dll
2.动态库的制作
-
g++ 得到.o 文件,需要得到与位置无关的代码
g++ -c -fpic a.cpp b.cpp
或者
g++ -c -fPIC a.cpp b.cpp
-
g++ 得到动态库
g++ -shared a.o b.o -o libxxx.so
3.示例
-
依次执行以下命令:
g++ add2.cpp add3.cpp -c -fpic
g++ -shared add2.o add3.o -o libdyadd.so
-
与静态库编译一样,使用g++对 m a i n . c p p main.cpp main.cpp编译
g++ main.cpp -o app -L ./ -l dyadd
-
将动态库文件 l i b d y a d d . s o libdyadd.so libdyadd.so所在目录添加到系统/用户的环境变量中
-
运行生成的 a p p . o u t app.out app.out文件即可