前言
好久不见,甚是想念~
本篇文章具体以操作为主,介绍在Linux下如何打包动静态库,并且如何使用这些库,同时,简单的阐述一下原理。让我们开始吧~
上一篇Linux文章传送地址~
【Linux】基础IO的理解与操作 - fd_柒海啦的博客-CSDN博客_io中 fd
[我们经历的每个日常也许就是连续不断的奇迹。]
目录
一、我们为什么需要库?
二、静态库 .a/.lib
1.代码实例(包含.h 和 .c 文件)
sort.h文件
sort.c文件
2.静态库的制作
3.使用静态库
1使用系统的默认路径:
2指定路径:
三、动态库 .so/.dll
1.制作动态库
1生成无序二进制文件:
2GCC/G++生成动态库:
2.使用动态库
一、我们为什么需要库?
在日常程序中,我们难免会经常使用一些重复性的代码:比如方法(函数)printf、cout、scanf、cin等;或者容器 vector、queue、stack、unordered_map等。
这些在使用过程中,难道每次一个使用项目的时候就要手动去导入这些代码或者去写吗?那样的话效率十分低下。
所以,站在写库的角度上看:1.简单。2.代码安全。并且,库的存在,可以大大的减少开发周期,并且提高了软件本身的质量。
那么库也分为两种,一种就是静态库,另一种就是动态库。静态库程序在编译链接的过程中将库的代码链接到可执行文件中。程序运行的时候就不再需要静态库。动态库则是程序在运行的时候采取链接动态库的代码,多个程序可以共享使用库的代码。
二、静态库 .a/.lib
在Linux下,静态库的扩展名为.a,windows下扩展名为.lib。
我们以下面这段排序算法的代码为例,来进行静态的库的生成和使用。
1.代码实例(包含.h 和 .c 文件)
sort.h文件
// sort.h
#pragma once
#include <iostream>
#include <assert.h>
#include <string.h>
using std::cout;
using std::cin;
using std::endl;
namespace YuShen
{
// 堆排
void HeapSort(int* arr, int len);
void AdjustDown(int* arr, int len, int parent);
// 归并排序
void _MergeSort(int* arr, int* tmp, int begin, int end);
void MergeSort(int* arr, int len);
void MergeSortNoRecursive(int* arr, int len); // 非递归实现
// 快速排序
void QuickSort(int* arr, int len);
void _quickSort(int* arr, int begin, int end);
int _quickSort1(int* arr, int begin, int end); // 原始版本实现
int _quickSort2(int* arr, int begin, int end); // 挖坑版本实现
int _quickSort3(int* arr, int begin, int end); // 双指针版本实现
}
sort.c文件
// sort.c
#include "sort.h"
void YuShen::AdjustDown(int* arr, int len, int parent)
{
int child = parent * 2 + 1;
while (child < len)
{
if (child + 1 < len && arr[child] < arr[child + 1]) ++child;
if (arr[parent] < arr[child])
{
std::swap(arr[parent], arr[child]);
parent = child;
child = parent * 2 + 1;
}
else break;
}
}
void YuShen::HeapSort(int* arr, int len)
{
assert(arr);
// 向下调整
for (int i = (len - 2) / 2; i >= 0; --i) AdjustDown(arr, len, i);
for (int i = 0; i < len; i++)
{
std::swap(arr[0], arr[len-1-i]);
AdjustDown(arr, len-1-i, 0);
}
}
void YuShen::MergeSort(int* arr, int len)
{
//....
}
void YuShen::MergeSortNoRecursive(int* arr, int len)
{
//...
}
int YuShen::_quickSort1(int* arr, int begin, int end)
{
// 原始版本
//......
}
int YuShen::_quickSort2(int* arr, int begin, int end)
{
// 挖坑版本
//......
}
int YuShen::_quickSort3(int* arr, int begin, int end)
{
// 双指针版本
//......
}
void YuShen::_quickSort(int* arr, int begin, int end)
{
if (begin >= end) return;
int trage = _quickSort3(arr, begin, end);
_quickSort(arr, begin, trage - 1);
_quickSort(arr, trage + 1, end);
}
void YuShen::QuickSort(int* arr, int len)
{
assert(arr);
_quickSort(arr, 0, len - 1);
}
2.静态库的制作
命令:
ar -rc lib[静态库名字].a .o文件
解释:
ar:是gnu归档工具,详细可以参考此网址GNU工具链 - surferqing - 博客园 (cnblogs.com)
-rc:(replace and create)替换和创建,意思就是把后面的所有.o文件打包成一个静态库。
lib[].a: []里面为自定义名字。前缀必须为lib,后缀必须为.a文件。
.o文件: 需要打包的.o文件集(中间用空格间隔)。必须是.o文件,因为静态库的本质就和在和程序文件编译的最后一步链接和主程序进行链接。所以必须是经过-c即汇编操作形成的.o文件。
比如,我们将上面的代码文件打包成静态库.a。
首先,将目标文件的源程序编译为.o文件。即反汇编操作变成二进制文件。
g++ -o sort.o sort.cpp -c
然后就可以将.o文件打包成静态库,使用ar归档工具:
ar -rc libsort.a sort.o
实际上,我们通常使用库的时候,.a文件放在一个文件夹(lib),.h文件放在一个文件夹(include),方便文件查找或者进行分类,所以这里我们也可以这样进行操作。利用makefile进行脚本操作:
libsort.a:sort.o
ar -rc libsort.a sort.o
make sort
sort.o:sort.cpp
g++ -c $^ -o $@
.PHONY:sort
sort:
mkdir ./include
mkdir ./lib
mkdir ./tempfile
cp *.h include
mv libsort.a lib
mv *.o tempfile
.PHONY:clean
clean:
make clean-sort
make clean-test
.PHONY:clean-sort
clean-sort:
rm -rf include
rm -rf lib
rm -rf tempfile
.PHONY:clean-test
clean-test:
rm -f test
上面我们.o文件放在临时文件夹内的,其实如何脚本操作完全可以看你自己的想法。运行一下make脚本:
制作成功后,如何将静态库添加到程序文件内呢(即含有main函数的程序入口)?
3.使用静态库
1使用系统的默认路径:
头文件gcc的默认搜索路径是:/user/include
云服务器库文件默认搜索路径:/lib64
自己所写的库属于第三方库 -- 不是语言和操作系统自带的,C语言的默认静态库是libc.a编译C语言会默认链接。如果直接拷贝过去还是会链接不了,需要告诉GCC gcc [...] -l库名。
但是一般不推荐上述做法,因为自己写的不一定通过代码的考验,没有经过测试的库或者软件安装在系统路径下的话有时出现问题不好解决。
2指定路径:
这种方法保险。但是操作相对麻烦,下面先介绍方法:
g++/gcc [-o ... ... .cpp/.c] -I 头文件路径(.h) -L 库文件路径(.a) -l库名
选项解释:
-I i的大写,表示include,即搜索头文件从当前目录进行搜索
-L l的大写,表示lib,即搜索库文件从当前目录进行搜素
-l库名 l的小写,库名表示指定链接库。
路径-相对和绝对路径均可。
由此,我们利用下面这个测试程序,将我们上面生成的静态库进行链接:
test.cpp文件
// test.cpp
#include "sort.h"
int main()
{
int arr[] = {3, 6, 2, 1, 4, 10, 9, 5, 7, 8};
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; ++i) cout << arr[i] << " ";
cout << endl;
YuShen::HeapSort(arr, len);
for (int i = 0; i < len; ++i) cout << arr[i] << " ";
cout << endl;
return 0;
}
静态库链接,编译,运行:
g++ -o test test.cpp -I ./include -L ./lib -lsort -std=c++11
静态库可以使用。
三、动态库 .so/.dll
在Linux下动态库扩展名为.so,windows为.dll。
动态库可以理解为编译好的一块程序加载入内存。因为首先在内存中存在了这样的一块程序,那么多个程序都可以共享这一块程序,通过进程地址空间中的共享区。这样的话动态库的效率就会很高,并且生成出来的可执行程序也不会很大。
1.制作动态库
动态库制作和静态库类似,只不过不使用ar进行规整,而是通过gcc/g++进行编译生成。
1生成无序二进制文件:
首先通过选项-fPIC 生成无序的程序二进制文件(汇编步骤-c),至于为什么可以参考这篇文章:
linux编译动态库之fPIC - 知乎 (zhihu.com)
g++ -o sort.o -c sort.cpp -fPIC
2GCC/G++生成动态库:
通过选项-shared(共享)生成动态库,可-o选项指定lib库名.so生成动态库文件。
g++ -shared sort.o -o libsort.so
和静态库类似,我们也可以将头文件放入include目录,库文件放入lib目录。
2.使用动态库
1拷贝到系统路径下:
和静态库类似,不推荐。
2临时加载入环境变量:
利用命令行export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:绝对路径(到库路径下)添加此库的路径,就可链接上动态库:
3修改配置文件:
创建 /etc/ld.so.conf.d/名字.conf。将动态库路径放入此路径即可。ldconfig -- 配置文件生效一下。
4建立软链接解决。
或者使用和静态库类似的方法,也就是直接链接:
g++ -o test2 test.cpp -I ./include -L ./lib -lsort
假设test1是先前我们链接静态库后的可执行文件。ldd命令可以查看程序链接的相关库,我们可以看到:
默认链接的是动态库。即存在同名静动态库的话。当然,如果强制链接静态库,可以加上-static。