链接:动态库和静态库

链接

g++/gcc编译选项

cpp生成过程

img

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

-o不仅可以指定输出的可执行文件,还可以指定中间文件的输出

demo.cpp

#include <iostream>
using namespace std;
int main(){
 cout << "hello,world" << endl;
 return 0;
}
  • -E

    对源文件进行预处理,预处理后生成.i文件

  • -S

    只进行预处理和编译,结果就是将C++代码中转译为汇编代码,生成.s汇编文件

  • -c

    只进行 预处理, 编译,汇编操作,生成.o 文件,不进行链接

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

重要编译参数

-D参数用来指定一个宏,宏和-D加不加空格都可以

#include <iostream>
using namespace std;
int main(){
#ifdef AAA
 cout << "In AAA area" << endl;
#endif
#ifdef BBB
 cout << "In BBB area" << endl;
#endif
 cout << "hello,world" << endl;
 return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

-M参数可以输出#incude的文件依赖

#include <cmath>
int main(){
 return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

g++ -MD demo.cpp

-MD参数会将结果生成.d文件

g++ -MD demo.cpp -o mm.d—可以指定文件名

GDB简单使用

要想程序能够被gdb调试,必须在编译时加上调试信息,也即是加上-g选项

一般来说,不加-g也可以被调试

#include <iostream>
int main(){
 std::cout << "hello,world" << std::endl;
 return 0;
}

生成可调式的文件

g++ -g demo.cpp -o exec

调试可执行文件:exec

gdb exec

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回车后,即可输入入命令:

Reading symbols from exec...
(gdb)

  • l或者list可以查看源码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • b或者break可以打断点
b 函数名
b 行号
b 文件名:行号
b 行号 if条件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • info break查看断点信息,delete可以删除断点

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • run或者r启动程序调试
  • next或者n是单步调试

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

#include <iostream>
using namespace std;
int sum(int a, int b)
{
 return a + b;
}
int main(){
 int a = 100, b = 200;
 cout << sum(a,b) << endl;
 return 0;
}
  • p 变量名或者display 变量名可以查看变量值
  • step命令或其简写s来跳入函数内部调试;如果要从函数跳出则执行`finish

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

静态库

😄库的定义:

库是计算机的二进制文件,是一种代码仓库,可以给使用者提供一些变量、函数或类

  • 库是写好的现有的,成熟的,可以复用的代码。
  • 库没有main函数,库不能单独运行

😄在项目中使用库一般有两个目的:

  • 一个是为了使程序更加简洁不需要在项目中维护太多的源文件
  • 另一方面是为了源代码保密

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

汇编后得到的主程序的.o文件和库文件通过链接得到最后的可执行程序


静态库生成过程:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【静态库】:

在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中

一个静态库可以简单看成是一组目标文件(.o文件)的集合

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

静态库的制作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

要使用库一定是由三个部分组成:库文件、头文件、文档说明

  • 一般这个库本身就是函数的定义

  • 头文件就是函数声明

例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • include下面的head.h文件,函数声明
int add(int, int);
int sub(int, int);
  • src下面的文件,具体函数的定义
int add(int a,int b){
    return a + b;
}
int sub(int a,int b){
    return a - b;
}
  • main.cpp可执行程序
#include "head.h"
#include <iostream>
using namespace std;
int main(){
    cout << add(10, 20) << endl;
    cout << sub(30, 40) << endl;
}

首先将src的cpp文件,汇编成.o文件,然后打包成静态库

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将生成的静态库文件移动到:lib目录下

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

编译主程序需要指定头文件路径,使用的函数定义的库路径,还有具体的库文件名

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当然也可以写在一起

g++ main.cpp -Iinclude -Llib -lMylib -o app

但是一定不能把main.cpp指定在自己定义的库文件之后

g++ -I include/ main.cpp -o app -L lib/ -lMylib----对的

g++ -Iinclude -Llib main.cpp -lMylib -o app----对的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原因是因为main.cpp里面用到了静态库里的函数,所以静态库先指定

静态库特点总结

  1. 静态库对函数库的链接是放在编译时期完成的。
  2. 程序在运行时与函数库再无瓜葛,移植方便。
  3. 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

动态库

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时候才被载入。

动态库直接使用编译器即可创建动态库。

静态库需要打包工具(ar)

动态链接库是程序运行时加载的库,当动态链接库正确部署之后,运行的多个程序可以使用同一个加载到内存中的动态库,因此在Linux中动态链接库也可称之为共享库。

动态库的制作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用gcc命令并且添加-FPIC(-fpic) 以及-shared 参数就可以生成动态库


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


使用上面的程序:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

把生成的动态库.so移动到lib,然后想静态库那样,编译main.cpp

-I 头文件文件夹路径 -L 库文件文件夹路径 -l 自定义库名

g++ main.cpp -I include/ -L lib/ -lmylib -o app

但是运行时候会出错

在这里插入图片描述

虽然已经告诉了编译器库文件和头文件的路径所在位置,但是当编译器编译好后,就与编译器无关了;

执行可执行程序是由加载器来完成的。所以需要在运行告诉系统库文件在哪里

动态库原理

😄静态库工作原理:

  • 在程序编译的最后一个阶段也就是链接阶段,提供的静态库会被打包到可执行程序中

  • 当可执行程序被执行,静态库中的代码也会一并被加载到内存中

    因此不会出现静态库找不到无法被加载的问题。

😄动态库加载方式:

  • 在程序编译的最后一个阶段也就是链接阶段的gcc命令中:

库路径只是检查了这个路径下的库文件是否存在,对应的动态库文件也没有被打包到可执行程序中,只是在可执行程序中记录了库的名字。

  • 可执行程序被执行起来之后:

程序执行的时候会先检测需要的动态库是否可以被加载,加载不到就会提示上边的错误信息。当动态库中的函数在程序中被调用了, 这个时候动态库才加载到内存,如果不被调用就不加载。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在链接期,动态链接只在可执行程序中记录动态链接库中共享对象的映射信息。

在程序执行时,动态链接库的全部内容全部被映射到该进程的虚拟地址空间

本质就是把链接过程推迟到运行时处理

解决动态库的加载失败

可以通过ldd命令检查动态库的依赖关系

ldd : list dynamic depenfencies

在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

报错原因就是:

系统加载动态库代码,系统只知道动态库的名字,但是不知道动态库代码绝对路径。因为动态库编译过程不会把库代码链接到动态库.so中。要想知道绝对路径,需要系统的动态载入器获取绝对路径。

动态库在程序运行后才会被动态加载到内存中

对于 elf 格式的可执行程序,是由 ld-linux.so 来完成的。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • elf的字段是不可以认为改变的
  • /usr/lib涉及了系统,不要使用
使用环境变量指定动态库路径

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/Desktop/demo/lib

可以使用:echo查看是否导入成功

echo $LD_LIBRARY_PATH

ldd可执行程序,看库是否有路径

ldd app

本种方法只能在一个终端起作用,新终端运行还得继续使用命令添加环境变量

利用主目录下的.bashrc文件或/etc/profile
 sudo gedit .bashrc

在文件最底下引入上面的内容

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用source命令激活

source .bashrc

去/ect/profile文件中加上环境变量

 sudo gedit /etc/profile

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

激活环境后可以运行

source /etc/profile

在这里插入图片描述

source可以用.代替

使用ld.so.cache指定动态库路径

ld.so.cache是一个二进制代码,需要在ld.so.conf里面添加

sudo gedit /etc/ld.so.conf

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里用ldconfig来激活

sudo ldconfig

静态库和动态库对比

静态库优缺点

  1. 静态库优点:
  • 静态库被打包到应用程序中加载速度快
  • 发布程序无需提供静态库,移植方便
  1. 静态库缺点
  • 相同的库文件数据可能在内存中被加载多份, 消耗系统资源,浪费内存库
  • 文件更新需要重新编译项目文件, 生成新的可执行程序, 浪费时间

在这里插入图片描述

动态库优缺点

  1. 动态库优点:
  • 可实现不同进程间的资源共享

    动态库被加载到内存后,所有进程可以访问该动态库的函数

  • 动态库升级简单, 只需要替换库文件, 无需重新编译应用程序

    动态库只有库名称打包到可执行程序,不会打包代码到可执行程序

  • 程序员可以控制何时加载动态库, 不调用库函数动态库不会被加载

    因为是运行时才会链接

  1. 动态库缺点
  • 加载速度比静态库慢, 以现在计算机的性能可以忽略
  • 发布程序需要提供依赖的动态库

在这里插入图片描述

程序使用动态库函数,才会把动态库动态加载到内存,而且加载一次后,其他进程可以访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值