Linux 静态库动态库的制作命令及示例

静态库和动态库

在Linux中静态库以lib作为前缀, 以.a作为后缀, 中间是库的名字自己指定即可, 即: libxxx.a
在Windows中静态库一般以lib作为前缀, 以lib作为后缀, 中间是库的名字需要自己指定, 即: libxxx.lib

生成静态链接库

1将源文件进行汇编, 得到 .o 文件, 需要使用参数 -c
$ gcc *.c -c    

2将得到的 .o 进行打包, 得到静态库
$ ar rcs 静态库的名字(libxxx.a) 原材料(*.o)
3发布静态库 1. 提供头文件 **.h 2. 提供制作出来的静态库 libxxx.a

 

静态库制作示例

#一创建文件
#main.c
#include <stdio.h>
#include "head.h"
int main()
{
    add();
    div();
}
#add.c
#include "head.h"
void add()
{
    printf("a+b = c\n");
}
#div.c
#include "head.h"
void div()
{
    printf("a-b = c\n");
}
#head.h
#ifndef _HEAD_H_
#define _HEAD_H_
#include <stdio.h>

void add();
void div();
#endif
#二 创建静态库
#1 生成.o文件
gcc add.c div.c -c
#2制作静态库
ar rcs libcalu.a add.o div.o
#3 使用静态库
gcc main.c -o cal -L./ -lcalu
  • -L: 指定库所在的目录(相对或者绝对路径)
  • -l: 指定库的名字, 静态库的名字指去掉头部的(lib)和尾部的(.a) 剩下部分

 

生成动态链接库

生成动态链接库直接使用gcc命令并且需要添加-fPIC(-fpic) 以及-shared 参数。

  • -fPIC 或 -fpic 参数的作用是使得 gcc 生成的代码是与位置无关的,也就是使用相对位置。
  • -shared参数的作用是告诉编译器生成一个动态链接库。

动态库制作示例

# 1. 将.c汇编得到.o, 需要额外的参数 -fpic或-fPIC
$ gcc add.c div.c mult.c sub.c -c -fpic -I ./include/   #-I指出头文件相对位置

# 2. 将得到 .o 打包成动态库, 使用gcc , 参数 -shared
$ gcc -shared add.o div.o mult.o sub.o -o libcalc.so  

# 3. 发布库文件和头文件
    1. head.h
    2. libcalc.so

动态库的使用

# 1. 拿到发布的动态库
    `head.h   libcalc.so
# 示例目录:
.
├── head.h          ==> 函数声明
├── libcalc.so      ==> 函数定义
└── main.c          ==> 函数测试
#2 在编译的时候指定动态库相关的信息: 库的路径 -L, 库的名字 -l
$ gcc main.c -o app -L./ -lcalc

#直接执行 ./app 会报错, 提示找不到动态库,还要进行下面操作

问题分析:可执行程序被执行起来之后:

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

动态连接器搜索顺序

  1. 可执行文件内部的 DT_RPATH 段

  2. 系统的环境变量 LD_LIBRARY_PATH

  3. 系统动态库的缓存文件 /etc/ld.so.cache

  4. 存储动态库/静态库的系统目录 /lib//usr/lib

解决方案

方案1: 将库路径添加到环境变量 LD_LIBRARY_PATH 中

找到相关的配置文件
用户级别: ~/.bashrc —> 设置对当前用户有效
或者系统级别: /etc/profile —> 设置对所有用户有效
使用 vim 打开配置文件, 在文件最后添加这样一句话
export LD_LIBRARY_PATH=动态库的相对路径/绝对路径
让修改的配置文件生效 1修改了用户级别的配置文件, 关闭当前终端, 打开一个新的终端配置就生效了 2修改了系统级别的配置文件, 注销或关闭系统, 再开机配置就生效了 如果不想执行上边的操作, 可以执行一个命令让配置重新被加载 # 修改的是哪一个就执行对应的那个命令 # 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

验证

$ ldd 可执行程序名
# 举例:
$ ldd app
    linux-vdso.so.1 =>  (0x00007ffe8fbd6000)
    libcalc.so => /home/robin/Linux/3Day/calc/test/libcalc.so (0x00007f5d85dd4000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5d85a0a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f5d85fd6000)  ==> 动态链接器, 操作系统提供

优缺点比较

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


3.2 动态库
优点:
可实现不同进程间的资源共享
动态库升级简单, 只需要替换库文件, 无需重新编译应用程序
程序猿可以控制何时加载动态库, 不调用库函数动态库不会被加载
缺点:
加载速度比静态库慢, 以现在计算机的性能可以忽略
发布程序需要提供依赖的动态库

 

posted @ 2023-08-26 13:34  ddup123  阅读(394)  评论(0)    收藏  举报