C++进阶 Linux相关的静态库,动态库,第三方库

1、多个源程序联合编译

g++ a.cpp b.cpp ... -o ***

一次性编译所有.cpp源码,自动完成编译 + 链接,直接生成可执行文件 app。

1.1 执行流程:

分别把 a.cpp、b.cpp 编译汇编成临时 .o

自动调用链接器 ld,合并所有目标文件、系统库,生成可执行程序 app

适用场景

小型项目、单个命令就能跑完,不需要复用目标文件。

在上述案例中,主程序要是有的源程序代码,在add.cpp中,如果项目结束后,到了交付阶段,由

于主程序的生成需要其他程序联合编译,那么就要将源程序打包一起发给老板,这样该程序的开发者自

身的价值就不大了,该项目的知识产权就很容易被窃取。为了保护我们的知识产权,我们引入了库的概

2、什么是库

2.1 概念

库在linux中是一个二进制文件,它是由 .cpp文件(不包含main函数)编译而来,其他程序如果想

要使用该源文件中的函数时,只需在编译生成可执行程序时,链接上该源文件生成的库文件即可。库中

存储的是二进制文件,不容易被窃取知识产权,做到了保护作用。

2.2 库在linux系统中分为静态库和动态库

(1)windows:

***.lib:静态库

***.dll: 动态库

(2)linux:

***.a:静态库

***.so: 动态库

3、静态库及其制作(lib开头,.a结尾)

3.1 概念:

将一个***.cpp的文件编译生成一个 lib***.a的二进制文件,当你需要使用该源文件中的函数时,

只需要链接该库即可,后期可以直接调用

静态体现在:

在使用g++编译程序时,会将你的文件和库最终生成一个可执行程序(把静态库也放入到可执行

程序中),每个可执行程序单独拥有一个静态库,体积较大,但是,执行效率较高

编译到使用静态库的步骤:

源文件生成.o-->打包静态库-->使用静态库

3.2 编译生成静态库

g++ -c ***.cpp -o ***.o

//只编译不链接生成二进制文件(main 主函数的 cpp可以不建议单独执行第一步生成.o)

ar -crs lib***.a ***.o

//编译生成静态库(库名是lib后,.a之前的部分)

如果有多个.o文件共同编译生成静态库可以使用 :ar -crs lib***.a ***.o xxx.o ...

ar:用于生成静态库的指令

c:用于创建静态库

r:将文件插入或者替换静态库中同名文件

s:重置金泰克索引

3.3 使用静态库

g++ main.cpp -L 库的路径 -l库名 -I 头文件的名字 -o 文件名(-o后面可以不写)

注意:

头文件的时大写的i,库名是小写的L(其他同理)

.表示当前路径,库名后面没有空格

..表示上级目录

分文件夹多路径编译(头文件,源文件,静态文件都各自管理在一个文件夹里)

4.4 批量生成.o怎么做

每个.cpp单独执行 -c 编译,互不干扰

g++ -c 支持一次性传入多个 cpp,自动按文件名生成同名.o,不用手动写 -o

# 写法1:指定全部cpp文件

g++ -c func1.cpp func2.cpp calc.cpp

# 写法2:通配符匹配当前目录所有cpp(最省事)

g++ -c *.cpp

自动生成:func1.o、func2.o、calc.o,不需要加 -o 参数。

注意:

这种批量写法无法自定义.o输出名,只能和 cpp 同名。

4.5 批量生成.a怎么做

把全部.o打包进静态库

ar -crs libmylib.a *.o

4、动态库及其制作

4.1 概念:

将一个***.cpp的文件编译生成一个 lib***.so的二进制文件,当你需要使用该源文件中的函数时,

只需要链接该库即可,后期可以直接调用

动态体现在:

在使用g++编译程序时,会将你的文件和库中的相关函数的索引表一起生成一个可执行程序,每个可执行程序只拥有函数的索引表,当程序执行到对应函数时,会根据索引表,动态寻找相关库所在位置进行调用,体积较小,执行效率较低,但是可以多个程序共享同一个动态库,所以,动态库也叫共享库

4.2 编译生成动态库

g++ -fPIC -c ***.cpp -o ***.o

//编译生成二进制文件

g++ -shared ***.o -o lib***.so

//依赖于二进制文件生成一个动态库

上述两个指令可以合成一个指令

g++ -fPIC -shared ***.cpp -o lib***.so

4.3 使用动态库

gcc main.cpp -L 库的路径 -l库名 -I 头文件的名字 -o 文件名(-o后面可以不写)此时还是报错

4.4 解决(包含优缺点,适合场景):

方式1:更改路径的宏

export LD_LIBRARY_PATH=库的路径

(1) 优点

不用重新编译,现成的可执行文件临时救急;

(2) 缺点

只在当前终端窗口生效,关窗口 / 新开终端就失效,每次运行都要重复输两行命令。

(3) 适配环境:

临时测试、快速验证库是否正常,不适合长期使用。

方法2:将自己的动态库放入到系统的库函数目录中 (/lib64 /usr/lib64)

mv lib***.so /lib

(1) 优点

系统全局永久生效,所有程序都能自动找到这个 so;

(2) 缺点

需要 root 权限;

污染系统动态链接缓存,项目挪走后残留无效库路径;

多项目时容易出现库版本冲突。

(3) 适配环境

自己写的公共工具库、长期安装在服务器的软件,不适合你当前课堂分目录练习。

方式3:编译加 -Wl,-rpath(工程开发 / 学习练习最建议)

g++ main.cpp -L 库目录 -l库名 -I 头文件目录 -Wl,-rpath=库目录 -o 文件名

注意:

头文件的时大写的i,库名是小写的L,-W后面的是小写的L(其他同理)

(1) 优点

一次编译,到处运行:可执行文件内部自带库路径,新开终端、重启系统都不用额外输命令,直接 ./run;

相对路径 ../lib 跟随项目文件夹,整个项目文件夹复制到别的机器也能正常跑;

不修改系统全局配置,无权限污染,普通用户、root 都能用。

(2) 缺点

仅当前编译出的程序生效,别的程序不受影响。

(3) 适合:

.课堂练习、个人项目、小型交付程序

5. 动/静态库编译生成可执行程序的大小比较

只有不几个文件,就差了24字节的大小

项目不用交再交源程序,直接交编译生成的动态库/静态库发给上级即可

运行指令的具体含义

gcc main.cpp -L 库的路径 -l库名 -I 头文件的名字的具体含义

单纯说链接库:指 -L xxx -lxxx 这一段;剩下的是编译

整条完整命令:编译源代码 + 链接外部库 ,是完整的编译链接命令。

6 如何使用第三方库

使用数学库:#include<math.h>

l后面是库名

线程支持类库:#include<pthread.h>

如果man手册不能支持线程库:sudo yum install manpages-posix manpages-posix-dev

怎么知道咱们要用的头文件他对应的要链接 的名字?

查找这个头文件底下的的某个函数名

man 函数名

你可以看到SYNOPSIS里面的东西

比如线程库函数能看到:Compole with -pthread(相当于-lpthread)

相关推荐
c238561 小时前
下篇:伸缩魔法!进阶吃透可变滑动窗口篇
c++·算法
来一碗刘肉面1 小时前
顺序表的按值查找
数据结构·c++·算法
小肝一下3 小时前
2. 顺序表和链表
c语言·数据结构·c++·链表·dijkstra·依蕾娜·香香的依蕾娜
王老师青少年编程3 小时前
csp信奥赛C++高频考点专项训练:【二分答案】案例5:进击的奶牛
c++·二分答案·csp·高频考点·信奥赛·进击的奶牛
旖-旎15 小时前
《LeetCode647 回文子串 || LeetCode 5 最长回文子串》
c++·算法·leetcode·动态规划·哈希算法
Darkwanderor16 小时前
对Linux的进程控制的研究
linux·运维·c++
云泽80816 小时前
从零吃透 C++ 异常:抛出捕获、栈展开、异常重抛与编码规范详解
开发语言·c++·代码规范
REDcker16 小时前
libdatachannel 快速入门
c++·webrtc·datachannel
second6018 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++