Linux快速入门之 静态库和动态库 (07)
文章目录
- 7.静态库和动态库
- 7.1 Linux下静态库
- 7.1.1生成静态库
- 7.1.2静态库使用
- 7.2 Linux下动态库
- 7.2.1 生成动态库
- 7.2.2 制作动态库
- 7.2.3 动态库的使用
- 7.2.4 动态库无法加载问题
7.静态库和动态库
程序中调用的库分为: 静态库 、动态库
,在Linux和Windows中虽然库文件的格式和后缀有所不同,但是其工作原理是一样的,(编译好的二进制格式的源文件)
使用库文件时还需要这些库中提供的API函数的声明(头文件),添加到项目中便可以使用。
使用库文件的目的:
- 为了使
项目更加简洁
,不同添加过多源码(.c /.cpp) - 为了保证
源码保密
,不希望其他人获得源码(库文件为二进制文件,人看不懂)
使用库文件例子:
A公司做一个项目 已经有500个cpp了,部分功能委托给B公司,B公司完成该功能写了300个cpp文件,B公司会打包成库文件交付给A公司 ;
对于A公司来说,避免了多出现300个cpp 导致代码繁多 ,对于B公司来说,自己的源码不会泄露,如果需要迭代功能自己可以反复收取服务费;
静态库和动态库是什么 ?有什么区别?
静态库: 为啥叫静态库,是在链接阶段,将汇编生成目标文件(.o格式)与引用到的库一起链接打包到可执行文件中,这种链接方式称为静态链接。
- 静态库对函数库的链接是放在编译时期完成的。
- 程序在运行时与函数库再无瓜葛,移植方便。
- 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
静态库在内存中存在多份拷贝导致空间浪费,例如一个静态库1m,有1000个同样程序,会占用1G内存,静态库对程序的更新、部署也会相对麻烦,一旦更新,使用它的所有程序都需要重新编译,发布给用户
动态库: 动态库在编译时不会链接到目标代码中 , 在程序运行时才被载入,不同的程序如果调用相同的库,内存中只存在一份共享库,解决了空间浪费的问题,同时因为在运行时加载库文件,也解决了静态库更新麻烦的问题,用户只需要更新动态库,增量更新
- 动态库把对一些库函数的链接载入推迟到程序运行的时期。
- 可以实现进程之间的资源共享。(因此动态库也称为共享库)
- 将一些程序升级变得简单。
- 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。
7.1 Linux下静态库
Linux系统下静态库由
ar程序
完成 (现在大部分程序使用动态库)
Linux中静态库以 lib 为前缀 , 以 .a 为后缀 ,中间为自己取的名字(例如 :libDemo
.a)
Windows中静态库通常 lib 为前缀 , 以 lib 为后缀 中间为自己取的名字(例如 :libDemo
.lib)
7.1.1生成静态库
制作静态链接库需要分两部 :
- 将目标文件(各种源文件)进行汇编操作(-c) 生成二进制代码
- 通过
ar工具
将目标文件打包成静态库文件
ar 工具参数 :使用的时候
直接 rcs
参数c:创建一个库,不管库是否存在,都将创建。
参数s:创建目标文件索引,这在创建较大的库时能加快时间。
参数r:在库中插入模块 (替换)。默认新的成员添加在库的结尾处,如果模块名已经在库中存在,则替换同名的模块。
#将目标文件进行汇编处理
$ gcc 源文件(*.c) -c#将获得的二进制文件(.o) 使用ar工具打包
$ ar rcs 静态库的名字(libDemo.a) 原材料 (*.o)#发布静态库
1.提供头文件 **.h
2.提供制作好的静态库
举例
liu@liu-Ubuntu:~/StutyLinux$ tree
.
├── addNum.cpp #包含一个加法函数
├── diviNum.cpp #包含一个初法函数
├── include #将头文件放置在子文件夹中
│ └── head.h #包含各个函数的函数声明
├── multNum.cpp #包含一个乘法函数
└── subNum.cpp #包含一个减法函数1 directory, 5 files
liu@liu-Ubuntu:~/StutyLinux$ gcc *.cpp -c -I ./include/ #目标文件 汇编处理 并指定头文件路径
liu@liu-Ubuntu:~/StutyLinux$ ar rcs libMyNum.a *.o #使用ar 工具打包为静态库
liu@liu-Ubuntu:~/StutyLinux$ ls
addNum.cpp diviNum.cpp include multNum.cpp subNum.cpp
addNum.o diviNum.o libMyNum.a multNum.o subNum.o#将生成的静态库 libMyNum.a 和库文件对应的头文件 head.h 一并发布给使用者
head.h #函数声明
libMyNum #函数定义(二进制)
7.1.2静态库使用
当我们得到了一个可用的静态库之后,需要将其放到一个目录中,然后根据得到的头文件编写测试代码,对静态库中的函数进行调用
# 4. 编译的时候指定库信息-L: 指定库所在的目录(相对或者绝对路径)-l: 指定库的名字, 掐头(lib)去尾(.a) ==> MyNum
# -L -l, 参数和参数值之间可以有空格, 也可以没有 -L./ -lcalcliu@liu-Ubuntu:~/StutyLinux/test$ ls
head.h libMyNum.a main.cpp
liu@liu-Ubuntu:~/StutyLinux/test$ g++ main.cpp -o APP -L ./ -l MyNum
liu@liu-Ubuntu:~/StutyLinux/test$ ./APP
a + b = 30
a - b = 10
a * b = 200
a / b = 2
使用静态库时,注意 -L
添加库的路径 -l
添加库的名称(掐头去尾)
静态库中不会出现动态库中可能无法被加载的问题
7.2 Linux下动态库
动态链接库是程序运行时加载的库,当动态链接库正确部署之后,运行的多个程序可以使用同一个加载到内存中的动态库,因此在 Linux 中动态链接库也可称之为共享库。
Linux中静态库以 lib 为前缀 , 以 .so为后缀 ,中间为自己取的名字(例如 :libDemo
.so)
Windows中静态库通常 lib 为前缀 , 以 dll 为后缀 中间为自己取的名字(例如 :libDemo
.dll)
7.2.1 生成动态库
生成动态链接库是直接使用 gcc 命令并且需要添加
-fPIC(-fpic)
以及-shared 参数。
-fPIC 或 -fpic 参数
的作用是使得 gcc 生成的代码是与位置无关的,也就是使用相对位置。
-shared参数
的作用是告诉编译器生成一个动态链接库。
#源文件进行汇编操作 ,使用参数 -c
#还需要添加额外参数 -fpic
$ gcc 源文件(*.c) -c -fpic #将若干个 .o文件打包成动态库
$ gcc -shared 目标文件(*.o) -o 动态库 (libMyNum.so)#发布动态库和头文件
1.提供头文件 xxx.h
2.提供动态库 libxxx.so
7.2.2 制作动态库
以以上静态库案例中 (加减乘除文件为例),制作动态库
- 使用 gcc 将源文件进行汇编 (参数-c), 生成与位置无关的目标文件,需要使用参数 -fpic或者-fPIC
- 使用 gcc 将得到的目标文件打包生成动态库,需要使用参数 -shared
liu@liu-Ubuntu:~/StutyLinux$ tree #显示当前文件夹结构
.
├── addNum.cpp
├── diviNum.cpp
├── include
│ └── head.h
├── multNum.cpp
├── subNum.cpp
└── test├── APP├── head.h├── libMyNum.a└── main.cpp2 directories, 9 files
liu@liu-Ubuntu:~/StutyLinux$ g++ *.cpp -c -fpic -I ./include/ #汇编源文件 并指定头文件目录 -fpic
liu@liu-Ubuntu:~/StutyLinux$ ls
addNum.cpp diviNum.cpp include multNum.o subNum.o
addNum.o diviNum.o multNum.cpp subNum.cpp test
liu@liu-Ubuntu:~/StutyLinux$ g++ *.o -o libAP.so -shared #打包为动态库 -shared#发布 库文件 和 相关头文件
1.head.h
2.libAP.so
7.2.3 动态库的使用
当我们得到了一个可用的动态库之后,需要将其放到一个目录中,然后根据得到的头文件编写测试代码,对动态库中的函数进行调用。
和使用静态库一样,在编译的时候需要指定库相关的信息: 库的路径 -L
和 库的名字 -l
$ g++ main.cpp -o myDll -L ./include -l APliu@liu-Ubuntu:~/StutyLinux/testdll$ g++ main.cpp -o myDll -L ./ -l AP
liu@liu-Ubuntu:~/StutyLinux/testdll$ ./
bash: ./: 是一个目录
liu@liu-Ubuntu:~/StutyLinux/testdll$ ./myDll
a + b = 30
a -b = -10
a * b = 200
a /b = 0
检查动态库是否可以加载
#检查命令
$ ldd 可执行文件名#如发现动态库无法加载 ,会显示 not found
liu@liu-Ubuntu:~/StutyLinux/testdll/bb$ ldd myDll linux-vdso.so.1 (0x00007fff207d9000)libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1e0476c000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1e0437b000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1e03fdd000)/lib64/ld-linux-x86-64.so.2 (0x00007f1e04cf7000)libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1e03dc5000)
7.2.4 动态库无法加载问题
在程序编译的最后一个阶段也就是链接阶段:
在 gcc 命令中虽然指定了库路径 (使用参数 -L ), 但是这个路径并没有记录到可执行程序中,只是检查了这个路径下的库文件是否存在。
同样对应的动态库文件也没有被打包到可执行程序中,只是在可执行程序中记录了库的名字。
可执行程序被执行起来之后:
程序执行的时候会先检测需要的动态库是否可以被加载
,加载不到就会提示上边的错误信息
当动态库中的函数在程序中被调用
了, 这个时候动态库才加载
到内存,如果不被调用就不加载
动态库的检测和内存加载操作都是由动态连接器来完成的
动态连接器
动态链接器是一个独立于应用程序的进程,属于操作系统,当用户的程序需要加载动态库的时候动态连接器就开始工作了,很显然动态连接器根本就不知道用户通过 gcc 编译程序的时候通过参数 -L 指定的路径。
可执行文件内部的
DT_RPATH
段 (不可改)系统的环境变量
LD_LIBRARY_PATH
系统动态库的缓存文件
/etc/ld.so.cache
( 通常不能修改,但是可以通过/etc/idso.config 同步进缓存文件)
存储动态库 / 静态库的系统目录
/lib/, /usr/lib 等
按照以上四个顺序,依次搜索,找到之后结束遍历,最终还是没找到,动态连接器就会提示动态库找不到的错误信息。
解决方案
可以提供三种解决方案,我们只需要将动态库的路径放到对应的环境变量或者系统配置文件中,同样也可以将动态库拷贝到系统库目录(或者是将动态库的软链接文件放到这些系统库目录中)。
方案 1:
将库路径添加到环境变量 LD_LIBRARY_PATH
中
找到相关的配置文件
用户级别: ~/.bashrc
(家目录下隐藏文件)—> 设置对当前用户有效
系统级别: /etc/profile
—> 设置对所有用户有效
使用 vim 打开配置文件,在文件最后添加这样一句话
# 自己把路径写进去就行了
export LIBRARY_PATH=$LIBRARY_PATH:动态库的绝对路径
让修改的配置文件生效
修改了用户级别的配置文件,关闭当前终端,打开一个新的终端配置就生效了
修改了系统级别的配置文件,注销或关闭系统,再开机配置就生效了
或者使用命令行更新
# 修改的是哪一个就执行对应的那个命令
# source 可以简写为一个 . , 作用是让文件内容被重新加载
$ source ~/.bashrc (. ~/.bashrc)
$ source /etc/profile (. /etc/profile)
方案 2
: 更新 /etc/ld.so.cache 文件
找到动态库所在的绝对路径(不包括库的名字)比如:/home/robin/Library/
使用 vim 修改 /etc/ld.so.conf
这个文件,将上边的路径添加到文件中 (独自占一行)
# 1. 打开文件
$ sudo vim /etc/ld.so.conf# 2. 添加动态库路径, 并保存退出#更新 /etc/ld.so.conf 中的数据到 /etc/ld.so.cache 中
# 必须使用管理员权限执行这个命令
$ sudo ldconfig
方案 3:
拷贝动态库文件到系统库目录 /lib/
或者 /usr/lib
中 (或者将库的软链接文件放进去)
# 库拷贝
sudo cp /xxx/xxx/libxxx.so /usr/lib# 创建软连接
sudo ln -s /xxx/xxx/libxxx.so /usr/lib/libxxx.so
Linux快速入门之 静态库和动态库 (07)相关推荐
- linux静态库与动态库整理
简化版本 静态库: 制作: gcc -g -c ./*.c -I ../include/ ar crs libmod.a *.o 使用 gcc -g main.c -L ./ -lmod -I ../ ...
- Linux下用gcc生成静态库和动态库及练习使用OpenCV
我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为 静态库和动态库两种.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而 ...
- 关于Linux静态库和动态库的分析
From: http://hi.baidu.com/bdccutysj/blog/item/5bae7f0202abac7c3912bb15.html 1.什么是库 在windows平台和linux平 ...
- linux 中如何将文件粘贴到usr下的lib内,学会在Linux下GCC生成和使用静态库和动态库...
一.基本概念1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主 ...
- Linux中gcc的编译、静态库和动态库的制作
欢迎大家关注笔者,你的关注是我持续更博的最大动力 Linux中gcc的编译.静态库.动态库 文章目录: 1 gcc的编译过程 1.1 gcc的编译过程 1.2 gcc的常用参数 2 gcc 静态库的制 ...
- Linux下的静态库、动态库和动态加载库
from: http://www.techug.com/linux-static-lib-dynamic-lib 库的存在极大的提高了C/C++程序的复用性,但是库对于初学者来说有些难以驾驭,本文从L ...
- linux下的共享库(动态库)和静态库
1.什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的本质不同,因此二者库的二进 ...
- Linux基础——gcc编译、静态库与动态库(共享库)
Linux基础--gcc编译.静态库与动态库(共享库) https://blog.csdn.net/daidaihema/article/details/80902012 Linux基础--gcc编译 ...
- Linux下制作和使用静态库和动态库
写在前面: ldd + 可执行文件 可以查看可执行文件所依赖的库 概述: Linux操作系统支持的函数库分为静态库和动态库,动态库又称共享库.linux系统有几个重要的目录存放相应的函数库,如/lib ...
最新文章
- PPC中检查某程序是否运行
- 中小企业大数据应用之道:思维在于借力
- hbuilder 个推登记应用
- 使用T-SQL管理数据中的Unicode字符
- php之include的使用
- C# 特性(Attribute)之Flag特性
- 安装Exchange2007邮件系统
- 新手必看:PS钢笔抠图教程
- FTP服务器搭建详细步骤
- 2022年起重机械指挥判断题及答案
- data.unity3d 文件过大解决方法
- C#将word文档转为PDF
- 如何使用MATLAB coder将MATLAB代码转换成C/C++语言(详细图文教程)
- API网关(什么是API网关、如何设计统一网关?)
- Android强大的控件——RecyclerView
- APP运营中地推应该怎么做
- 【C++程序设计技巧】NVI(Non-Virtual Interface )
- 有没有可以测试手速的软件,我的第一个Mac小程序 — 手速测试器
- Comparable
- XXE漏洞详解与利用
热门文章
- JSD-2204-JDBC-SpringBoot-Day11
- 最强思维导图训练营教程
- 机器学习模型设计准则:“无免费午餐”定理和“奥卡姆剃刀”原则
- BSC 再现闪电贷攻击 BUNNY 闪崩
- 英文会议论文出版地信息汇总
- [从头读历史] 第241节 根据天时定历法
- (root用户)bash: ./xx: Permission denied解决方法
- python里row是什么意思_row python
- Python输出菱形图案
- redis集群拓扑_Redis拓扑