文章目录
一、用gcc生成静态库和动态库
函数库分为静态库和动态库两种。 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程 序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
1、编辑生成例子程序 hello.h、hello.c 和 main.c
打开Linux终端,使用命令创建目录
然后用 vim、nano 或 gedit 等文本编辑器编辑生成所需要的 3 个文件。
hello.h:
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif//HELLO_H
hello.c:
#include<stdio.h>
void hello(const char *name)
{
printf("Hello %s\n",name);
}
main.c:
#include"hello.h"
int main()
{
hello("everyone");
return 0;
}
2、将 hello.c 编译成.o 文件
运行ls命令查看是否生成hello.o文件
结果中有.o文件
3.由.o文件创建静态库。
静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为 myhello,则静态库文件名就是 libmyhello.a。在创建和使用静态库时, 需要注意这点。创建静态库用 ar 命令
ls命令中有libmyhello.a
4、在程序中使用静态库
在删掉静态库的情况下,运行可执行文件,发现程序仍旧正常运行,表明静态库跟程序执行没有联系。同时,也表明静态库是在程序编译的时候被连接到代码中的。
5、由.o 文件创建动态库文件
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其 文件扩展名为.so。例如:我们将创建的动态库名为 myhello,则动态库文件名就是 libmyhello.so
6.在程序中使用动态库
在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明动态库名进行编译。
先运行 gcc 命令生成目标文件,再运行它看看结果:
(或 gcc main.c libmyhello.so -o hello不会出错(没有 libmyhello.so 的话,会出错),但是接下来./hello 会提示出错,因为虽然连接时用的是当前目录的动态库,但是运行时,是到 /usr/lib 中找库文件的,将文件 libmyhello.so 复制到目录/usr/lib 中就 OK 了)
出错了。看错误提示,原来是找不到动态库文件 libmyhello.so。程序在运行时, 会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提 示类似上述错误而终止程序运行。我们将文件 libmyhello.so 复制到目录/usr/lib 中,再试试:
表示权限不够,用sudo命令解决
成功了。这也进一步说明了动态库在程序运行时是需要的。 我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的 gcc 命令完全一样, 那当静态库和动态库同名时,gcc 命令会使用哪个库文件呢?抱着对问题必究到底的心情, 来试试看。 先删除除.c 和.h 外的所有文件,恢复成我们刚刚编辑完举例程序状态。
再来创建静态库文件 libmyhello.a 和动态库文件 libmyhello.so:
通过上述最后一条 ls 命令,可以发现静态库文件 libmyhello.a 和动态库文件 libmyhello.s o 都已经生成,并都在当前目录中。然后,我们运行 gcc 命令来使用函数库 myhello 生成目 标文件 hello,并运行程序 hello。
从程序 hello 运行的结果中很容易知道,当静态库和动态库同名时,gcc 命令将优先使用动 态库,默认去连/usr/lib 和/lib 等目录中的动态库,将文件 libmyhello.so 复制到目录/usr/lib 中即可。
补充
1:编译参数解析
最主要的是 GCC 命令行的一个选项:
-shared该选项指定生成动态连接库(让连接器生成 T 类型的导出符号表,有时候也生成弱连接 W 类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。
-fPIC 表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-L. 表示要连接的库在当前目录中;(多个库:在编译命令行中,将使用的静态库文件放在源文件后面就可以了。比如:gcc -L/usr/lib myprop.c libtest.a libX11.a libpthread.a -o myprop 其中-L/usr/lib 指定库文件的查找路径。编译器默认在当前目录下先查找指定的库文件,如前面的“法二 #gcc main.c libmyhello.a -o hello”)
-lmyhello 编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上 lib,后面 加上.so 或.a 来确定库的名称 libmyhello.so 或 libmyhello.a。
LD_LIBRARY_PATH 这个环境变量指示动态连接器可以装载动态库的路径。 当然如果有 root 权限的话,可以修改/etc/ld.so.conf 文件,然后调用 /sbin/ldconfig 来达到 同样的目的,不过如果没有 root 权限,那么只能采用输出 LD_LIBRARY_PATH 的方法了。
调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include 进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过 ldd 命令察看 时,就是死活找不到你指定链接的 so 文件,这时你要作的就是通过修改 LD_LIBRARY_PATH 或者/etc/ld.so.conf 文件来指定动态库的目录。通常这样做就可以解决 库无法链接的问题了。
2:找到生成的动态库的 3 种方式:
(1)把库拷贝到/usr/lib 和/lib 目录下。
(2)在 LD_LIBRARY_PATH 环境变量中加上库所在路径。 例如动态库 libhello.so 在/home/example/lib 目录下: $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/example/lib
(3) 修改/etc/ld.so.conf 文件,把库所在的路径加到文件末尾,并执行 ldconfig 刷新。 这样, 加入的目录下的所有库文件都可见。
附:像下面这样指定路径去连接系统的静态库,会报错说要连接的库找不到:
g++ -o main main.cpp -L/usr/lib libpthread.a
必须这样:
g++ -o main main.cpp -L/usr/lib -lpthread 才正确 。
自定义的库考到/usr/lib 下时, g++ -o main main.cpp -L/usr/lib libpthread.a libthread.a libclass.a 会出错,但是 g++ -o main main.cpp -L/usr/lib -lpthread -lthread -lclass 就正确了
二.Linux下静态库和动态库的生成和使用
创建作业目录并打开:
使用gedit命令编辑文件
A1.c:
#include <stdio.h>
void print1(int arg){
printf("A1 print arg:%d\n",arg);
}
A2.c:
#include <stdio.h>
void print2(char *arg){
printf("A2 printf arg:%s\n", arg);
}
A.h:
#ifndef A_H
#define A_H
void print1(int);
void print2(char *);
#endif
test.c:
#include <stdlib.h>
#include "A.h"
int main(){
print1(1);
print2("test");
exit(0);
}
1.静态库.a文件的生成和使用
使用.a库文件,创建可执行程序(若采用此种方式,需保证生成的.a文件与.c文件保存在同一目录下,即都在当前目录下):
2、共享库.so文件的生成与使用
出现错误,运行ldd test查看链接情况
找不到对应的.so文件,移动.so文件位置
成功
三、共享库.so文件的生成与使用
创建目录test3并打开,使用gedit编辑文件
sub1.c:
float x2x(int a,int b)
{
float c=0;
c=a+b;
return c;
}
sub2.c
float x2y(int a,int b)
{
float c=0;
c=a/b;
return c;
}
sub.h
#ifndef SUB_H
#define SUB_H
float x2x(int a,int b);
float x2y(int a,int b);
#endif
main.c
#include<stdio.h>
#include"sub.h"
void main()
{
int a,b;
printf("Please input the value of a:");
scanf("%d",&a);
printf("Please input the value of b:");
scanf("%d",&b);
printf("a+b=%.2f\n",x2x(a,b));
printf("a/b=%.2f\n",x2y(a,b));
}
1、静态库的使用
2、动态库的使用
3.静动态库生成文件的比较
比较发现静态库文件大小和动态库相比要小得多。
四、总结
通过三个程序用gcc生成静态库和动态库的练习过程,掌握了GCC生成静态库和动态库的命令,了解了静动态库调用时的规则以及静态库和动态库的优缺点,对比了两者的差别,虽然过程中遇到了一些小问题,也可以参考资料进行了解决。
五、参考文献
https://blog.csdn.net/qq_43279579/article/details/109026927