静态库的打包和使用
我们下面使用静态库打包和使用的例子让大家更加深入的理解静态库
我们使用下面的四个文件来演示
add.h
1 #pragma once 2 3 extern int myadd(int x , int y);
add.c
1 #include "add.h" 2 3 int myadd(int x , int y) 4 { 5 return x + y; 6 }
sub.h
1 #pragma once 2 3 extern int mysub(int x , int y);
sub.c
1 #include "sub.h" 2 3 int mysub(int x , int y) 4 { 5 return x-y; 6 }
打包
第一步 生成二进制文件
第二步 将所有目标文件打包为静态库
ar命令是gnu的归档工具 常用于将目标文件打包为静态库
下面是命令选项
- -r(replace):若静态库文件当中的目标文件有更新 则用新的目标文件替换旧的目标文件
- -c(create):建立静态库文件
- -t:列出静态库中的文件
- -v(verbose):显示详细的信息
我们可以使用下面的指令将一个或多个目标文件打包为静态库
ar -rc libst.a add.o sub.o
我们可以使用下面的指令查看一个静态库中的文件
ar -tv libst.a
第三步 将头文件和生成的动态库组织起来
与我们使用时一样
我们可以将所有的头文件放到 /include
文件夹中
将所有的静态库文件放到 /lib
文件夹中
接着将这两个目录放到 /mylib
中
这样子我们就可以将我们的mylib给别人使用了
使用
我们首先写出一个源文件 main.c
1 #include <stdio.h> E> 2 #include <add.h> E> 3 #include <sub.h> 4 5 6 7 int main() 8 { 9 int x = 10; 10 int y = 20; E> 11 int z1 = myadd(x , y); E> 12 int z2 = mysub(x , y); 13 printf ("myadd :: %d\n" , z1); 14 printf ("mysub :: %d\n" , z2); 15 return 0; 16
我们发现 这个源文件中其实报了四个错误 这是因为我们c语言程序在查到头文件的时候只会查找同级的头文件还有系统配置的头文件
而我们当前目录下只有两个文件 main.c 和 mylib
不过我们不必担心 编译之后的程序肯定是可以正常运行的
使用方式一: 使用选项
gcc编译时我们需要使用的三个选项如下
- -I:指定头文件搜索路径
- -L:指定库文件搜索路径
- -l:指明需要链接库文件路径下的哪一个库
所以说我们只需要敲出下面的指令他就可以
gcc -o main main.c -I ./mylib/include/ -L ./mylib/lib/ -l st
这段指令的意思是使用main.c源程序编译 指定某个头文件 指定某个库文件 指定st这个库
编译生成一个名为main的可执行文件
这个时候我们就可以运行我们的程序了
使用方式二: 把头文件和库文件拷贝到系统路径下
编译器之所以能够找到c的头文件和库文件是因为它们被放在默认的路径中
当我们开始编译的时候编译器就会默认去那里寻找
而头文件的默认路径在这里
/usr/include/
而库文件的默认路径在这里
/lib64/
所以说我们只需要将自己的头文件和库文件拷贝到这两个地方就可以了
我们使用下面两个指令来拷贝
cp ./mylib/include/* /usr/include/
cp ./mylib/lib/libst.a /lib64/
之后我们再看main文件代码
我们发现这次代码并没有报错
但是我们这里发现gcc编译的时候报错了 这是因为gcc编译的时候默认找的是c库 而我们添加的库并不是c库
所以说我们编译的时候还需要指定依赖的库文件
注意: 我十分不建议将自己写的库文件拷贝到系统路径中 这样子会污染原本的库文件
动态库的打包和使用
我们还是使用这四个库文件来演示动态库的打包和使用
打包
第一步 生成对应的目标文件
让所有源文件生成对应的目标文件
动态库与静态库汇编指令中不同的是 动态库的汇编指令中需要加上-fPIC
选项
-fPIC
选项的意义是生成和位置无关码
它是一个很复杂的概念 涉及到很多的专业知识 这里就不过多赘述 对于它我们只需要了解两点
- -fPIC作用于编译阶段 告诉编译器产生与位置无关的代码 之后代码被加载到内存的任何位置都可以运行
- -fPIC选项并不是必须要加的 如果不加动态库必须要在加载到用户程序的地址空间时重定向所有表目
第二步 打包动态库
与生成静态库时使用ar命令打包不同 我们只需要使用gcc的-shared选项即可
指令如下
gcc -shared -o libdy.so add.o sub.o
第三步 将头文件和生成的动态库组织起来
和生成的静态库一样
我们可以将所有的头文件放到 /include
文件夹中
将所有的静态库文件放到 /lib
文件夹中
接着将这两个目录放到 /mylib
中
这样子我们就可以将我们的mylib给别人使用了
使用
我们还是使用静态库的源文件main.c来演示动态库的使用
1 #include <stdio.h> E> 2 #include <add.h> E> 3 #include <sub.h> 4 5 6 7 int main() 8 { 9 int x = 10; 10 int y = 20; E> 11 int z1 = myadd(x , y); E> 12 int z2 = mysub(x , y); 13 printf ("myadd :: %d\n" , z1); 14 printf ("mysub :: %d\n" , z2); 15 return 0; 16 }
动态库的编译方法和静态库的编译方法一模一样
我们可以使用指令或者是将库文件和头文件放到系统目录中
我们这里使用指令为例
我们敲出下面的指令就可以编译
我们发现这样子就生成了我们的可执行程序了
但是和静态库的使用不一样 使用动态库的文件在成为可执行文件的时候还不能直接运行
我们再使用ldd指令 查看这个可执行文件所依赖的动态库
我们发现系统找不到这个动态库在哪里
这是因为 我们使用-I,-L,-l这三个选项都是在编译期间告诉编译器我们使用的头文件和库文件在哪里以及是谁 但是当生成的可执行程序生成后就与编译器没有关系了
所以说如果我们想要执行这个程序 还需要想办法告诉操作系统这个库文件的地址
这里有三种方式可以做到
方式一 拷贝到系统路径下
我们直接将该动态库拷贝到系统的库文件目录下 这样子操作系统就能够找到了
指令如下
cp ./mlib/dylib/libdy.so /lib64
这样子就可以顺利运行了
方式二 更改环境变量
LD_LIBRARY_PATH
是程序运行动态查找库时所要搜索的路径 我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH
环境变量当中即可
使用指令如下
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/shy/linux/lesson11~20/lesson13/code4/mlib/dylib/
之后我们再查询a.out的动态库 可以发现
我们可以发现动态库的路径变为了我们设置的路径
当然现在也可以继续运行了
方式三 配置/etc/ld.so.conf.d/
我们可以通过配置/etc/ld.so.conf.d/
的方式解决该问题
首先我们自己需要写一个以.conf
后缀的文件
将我们库文件所在的路径放到这个文件当中
之后将这个配置文件放到 /etc/ld.so.conf.d/
目录中
之后使用指令更新配置文件
ldconfig
这样子我们就可以运行我们的文件了