目录
1. 找不到你描述fin_max.h那一个头文件""引起来的头文件先在当前目录查找,找不到就去标准路径找
2. 编译器找不到函数的实现(定义)函数find_max的实现在libfind_max.so这个库里面,但是编译器不知道
3. 上面仅仅是指定了库的名字,编译器在标准路径(/usr/lib:/lib)下面找不到名字叫做libfind_max.so的库文件
前言:库文件:动态库和静态库
二进制的仓库(一个已经实现好的,可以直接调用的功能模块)
库是一种二进制的封装形式,其他的源代码可以直接调用库中已经实现的函数模块或者其他功能模块,但是又看不到他的源代码
库这种方式有利于模块化,以及代码重用,而且只要接口设计合理,改变库的实现方式,不影响使用库的源代码的
如:
printf()/scanf()/strlen() 只需要使用即可,不需要知道它是如何实现的
库是如何来的呢?
源代码(一般没有主函数)------>编译------->二进制文件(01)
1.动态库(又叫做共享库)
动态库的使用步骤:
a.先制作一个动态库
1.先编写库函数的源代码
xxx.c 库文件的功能实现
xxx.h 函数以及数据类型的声明(接口文件)
2.把你写的库函数(模块)的源代码编译成为动态库
把功能源代码变成一种谁都可以调用的二进制形式
gcc -shared -fpic -o libxxx.so xxx.c xxx.c
编译器名称 共享库 与位置无关的 output 生成的库的名字 源文件列表
libxxx.so 你指定的生成的库的名字,必须以lib开头,以.so结尾
xxx.c xxx.c 你生成库文件的源文件列表,可以有多个,以空格隔开
如:
把find_max这个功能制作为一个动态库文件
gcc -shared -fpic -o libfind_max.so find_max.c
生成了一个库文件
file libfind_max.so 查看库文件的详细信息
就可以把库文件(libfind_max.so)和头文件(find_max.h)拷贝给其他人使用了
b.在写一个其他的源代码调用这个库文件
在其他源代码中直接包含接口文件,就可以直接使用库中的函数
如:当前源代码存在的结构如下
inc/ 存放一些外部引用的头文件
lib/ 存放一些外部引用的库文件
src/ 当前项目的源文件
change_log.txt 修改和更新的记录日志信息
readme.txt 注意事项和说明
编译自己源代码的时候,可能会遇到一些如下的错误:
1. 找不到你描述fin_max.h那一个头文件""引起来的头文件先在当前目录查找,找不到就去标准路径找
gcc main.c -o main
main.c:2:10: fatal error: find_max.h: 没有那个文件或目录
#include "find_max.h"
解决方法:
1.把自己的头文件放到当前目录下面或者放到标准路径下面(不建议)
2.手动指定头文件的查找路径
-I Include
-I后面接一个目录名,指定当前编译时,头文件的查找路径
可以是相对路径,也可以是绝对路径,可以有多个-I(以空格隔开)
如: 相对路径
gcc main.c -o main -I../inc
or
绝对路径
gcc main.c -o main -I /mnt/hgfs/CS2406F/2024-1-18交叉开发
/code/01动态库/project/inc/
2. 编译器找不到函数的实现(定义)函数find_max的实现在libfind_max.so这个库里面,但是编译器不知道
gcc main.c -o main -I../inc
/tmp/ccLjjHi0.o:在函数‘main’中:
main.c:(.text+0x6e):对‘find_max’未定义的引用
collect2: error: ld returned 1 exit status
对...未定义的引用
解决方法:
编译的时候指定函数find_max定义的位置
-l library的缩写
-l + 库的名字(需要去掉前面的lib和后面的.so)
-lfind_max
===================>
你的工程中使用了其他模块的函数的时候,你必须告诉编译器你的函数在哪里
printf/scanf这些函数,我并没有指定路径,为什么可以直接使用
因为这个是C语言标准库函数,编译器会自动的包含这个库文件
总之,你使用了不是你自己定义的函数的时候,就必须指定出处
如:工程中使用了数学函数的时候, -lm libm.so
3. 上面仅仅是指定了库的名字,编译器在标准路径(/usr/lib:/lib)下面找不到名字叫做libfind_max.so的库文件
gcc main.c -o main -I../inc -lfind_max
/usr/bin/ld: 找不到 -lfind_max
collect2: error: ld returned 1 exit status
解决方法:
1.把自己的库文件放到标准路径下面(不建议)
2.使用-L指定库文件的查找路径
-L 目录名
在指定的目录下面去搜索库文件(可以是相对路径,也可以是绝对路径,也可以接多个路径)
==============>
gcc main.c -o main -I../inc -lfind_max -L ../lib
4.编译成功之后,运行使用了库函数的程序
./main
./main: error while loading shared libraries: libfind_max.so:
cannot open shared object file: No such file or directory
在一个程序运行之前,必须把它依赖的所有的库文件加载到内存中去,程序才可以运行
动态库你必须知道的特点:
某一个工程编译的时候,用到了动态库的某一个函数,但是在编译完成之后,并不会把动态库的内容复制到可执行程序中去(可执行程序main中并没有关于find_max的实现指令),仅仅是在用到这个函数的位置做了一个标记,表示用到了某一个库的某一个函数!!!
ldd main
linux-vdso.so.1 (0x00007fff4ea76000)
libfind_max.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f18771b0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f18777a3000)
如:
上面的可执行程序main中,并没有包含find_max的实现指令,只是标记用到了这个库,就导致了一个问题,在运行main的时候,要先准备好libfind_max.so这个库文件
如果在标准路径下面没有这个库文件,就会报错
解决方法:
1.把你的库文件放到标准路径下面(/usr/lib)
2.在运行main前,可以通过环境变量指定库的加载路径
linux中有一个环境变量
LD_LIBRARY_PATH 加载库的路径
修改这个环境变量:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:你要添加的路径
几种修改环境变量的方式:参考shell编程
总结:
不仅仅在编译的时候需要用到动态库,在运行的时候也需要使用到动态库文件
动态库也叫做共享库
无论有多少个可执行程序用到了这个库文件,这个库文件在内存中都只有一份拷贝,是所有可执行程序共享的
c.练习
自己制作一个动态库文件,并且写一个程序调用库中的函数(放到开发板上面运行)
写一个模块,这个模块可以对数组进行排序
2.静态库
静态库也是库的一种形式,也是一种二进制指令的封装,在静态库做好了之后,需要使用静态库的工程在编译的时候,会直接把静态库中包含的指令复制到可执行文件中去(可执行文件中拥有静态库的内容,所以静态库编译的文件往往比动态库编译的文件大),这样这个可执行文件就包含了库函数的指令,在运行的时候就不需要使用库文件了,也不需要指定库的加载路径
和动态库最大的区别:
使用动态库的可执行文件中不包含库函数的指令,每一次都是动态加载
库函数在内存中仅仅只有一份拷贝,所有的可执行文件共享
使用静态库的可执行文件中包含了库函数的指令,运行的时候就不需要加载了
库函数在内存中有很多份拷贝(由多少个可执行文件,就有多少份拷贝)
例子:
a.先制作一个静态库
1.先编写库函数的源代码
xxx.c 库文件的功能实现
xxx.h 函数以及数据类型的声明(接口文件)
2.把你写的库函数(模块)的源代码编译成为静态库
把功能源代码变成一种谁都可以调用的二进制形式
先把库的源文件全部都编译为.o文件
xxx.c------->xxx.o
sort.c ----->sort.o
....
gcc -c sort.c -o sort.o
利用ar命令把所有的.o文件打包生成一个静态库
ar -rc 库的名字 .o文件的列表
ar -rc libsort.a sort.o
静态库的名字还是以lib开头,以.a结尾
.o文件的列表:可以有多个,使用空格隔开即可
只需要把头文件和库文件拷贝给其他人使用即可!
b.在写一个其他的源代码调用这个库文件
在其他源代码中直接包含接口文件,就可以直接使用库中的函数
但是编译的时候还是需要指定头文件/库文件的路径
ldd main
linux-vdso.so.1 (0x00007fffef0cd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8be06f2000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8be0ce5000)
没有包含对libsort.a的引用信息,使用的是静态库,直接把库中的指令复制到了可执行文件中
直接运行可执行文件即可
静态库只有在编译的时候需要使用库文件,在运行的时候就不需要使用库文件了
3.总结
假如你以后需要写一个库函数,你是做成静态库还是动态库呢?
动态库和静态库各有优缺点!!!
静态库:
优势:静态库只有在编译的时候需要使用库文件,在运行的时候就不需要使用库文件了
劣势:
1.静态库明显是冗余的
动态库在系统中,只有一份拷贝,不管你有多少个可执行文件,都只有一份
2.静态库的更新不方便
因为使用静态库的可执行文件把库的内容直接复制到可执行文件中去了
更新库文件的时候,需要重新编译可执行文件,但是动态库不需要
动态库:
劣势:不仅仅在编译的时候需要用到动态库,在运行的时候也需要使用到动态库文件
优势:动态库的更新很方便
只要函数的接口(库的名字,函数的三要素)不变,依赖动态库的程序就不需要重新编译
只需要把更新好的库文件替换掉原来的库文件即可,这一点静态库做不到
4142

被折叠的 条评论
为什么被折叠?



