树莓派学习笔记(二):Linux库
Linux库概念引入
这一篇开始,进入树莓派开发阶段,即编程部分。之前Linux系统编程部分学习了文件编程、进程与进程通信、线程、网络编程等内容,但主要以单文件编程为主。在Linux中,库是一个比较重要的概念,常在面试中考察到,因此在开始之前,先来引入一下库的基本概念与使用
分文件编程实例
在之前阶段的上官一号单片机项目:智能小车开发案例中,我们将主函数放在main.c
中,负责整体应用的初始化、维护和信号处理,而外围的超声波测距、wifi
建立tcp server
、舵机等模块分别放到单独的C文件中,这些文件只有具体的封装好的函数实现,没有main函数。
这就是分文件编程的基本思想。功能性函数分文件实现,符合模块化编程思想,利于责任划分、方便调试,且主程序简洁。
下面就是一个简单的四则运算C程序:
1 |
|
我们按照功能与逻辑分离的原则将其拆分为三个文件:
控制程序主体运行逻辑的main.c
:
1 |
|
实现具体功能的calculator.c
:
1 |
|
以及用于函数声明的calculator.h
:
1 |
|
三个文件编写好后使用命令gcc calculator.h main.c
可编译成功。
动态库与静态库
前面一节了解了分文件编程的基本概念,但这种方式仅仅是将功能与逻辑分开,不同功能的代码写在不同的文件中,并没有实现“封装”。对于功能完善、经过测试可以使用的代码,一般而言我们既希望别人能够直接使用,但又不想使用者对其进行修改(即不开放源代码,比较鸡贼),以保护文件的完整性。这种情况下,就引入了“库”的概念。
一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。(参考自Linux共享库、静态库、动态库详解)
程序函数库又可分为3种类型:
- 静态库(static libraries),在程序执行前,编译阶段就加入到目标程序中去了 ;
- 共享库(shared libraries)与动态(加载)库(dynamically loaded libraries)是同一个概念,都是在执行过程中由目标程序调用,动态加载库。只是在Linux上叫共享对象库,文件名后缀.so;在Windows上叫动态加载函数库,文件名后缀dll。
相应地,它们具有的特点是:引用静态库的加载速度快,移植性强(发布时无需另外再提供静态库)但目标程序文件较大,更新、部署麻烦;动态库加载速度较慢,但目标程序文件比较轻量,更新升级的操作也比较简单,系统加载一次后多个程序之间可以共享。
静态库的制作与使用
这里依然以上面简单的四则运算为例学习静态库的基本用法。
静态库的制作,第一步是将所有的功能实现的源代码(.c/.cpp)转化为对象文件(.o),这一步一般一个源文件对应一个对象文件,这里只有一个功能模块就只写了一个文件:
1 |
|
第二步,将所有的对象文件打包,合成一个静态程序函数库:
1 |
|
注意静态库名最好以lib
开头,既便于标识也易于使用
**静态库的使用**,这里还是以gcc
编译C文件产生程序为例:
1 |
|
不过,此时由于gcc默认从/usr/include
、/usr/lib
、/usr/local/lib
等目录查找标准库,而我们的静态库此时并未放进去,因此会报错找不到。只需要在上面的命令加一选项-L./
,告诉gcc优先查找当前目录即可。
如果后面不想麻烦指定位置,可以在静态库制作的时候添加选项-I /usr/include
,指定生成的静态库存放目录
最后的效果:

动态库的制作与使用
第一步依然是编译,不过此时需要加一个参数fpc
,生成专用于动态库的对象文件,加了该选项后库与具体位置无关:
1 |
|
第二步,使用gcc
将对象文件打包为.so
文件,shared选项用于胜场动态链接:
1 |
|
(**编译与打包可以合为一个步骤**)
使用共享库编译目标程序:与静态库一致,gcc main.c calculator.h -lcalcf -L./ -o calculator2
但在执行生成的目标程序时,由于使用的是动态库,所以没有编译到目标程序中,因此会自动到/usr/lib
中寻找动态库,找不到就会报错。

此时的解决方法还是两种:
第一种将动态库拷贝一份到
/usr/lib
中;第二种是使用一个环境变量
LD_LIBRARY_PATH
,指定到生成的动态库所在目录,如下图中就该是在/etc/profile
中写入:export LD_LIBRARY_PATH ="/home/pi/libtest"
,然后source /etc/profile
。这种方式和第一种其实原理是一样的第三种,在目标程序的编译阶段使用
-WI, -rpath
选项:1
gcc main.c calculator.h -lcalcf -WI,-rpath=./ -L./ -o calculator2
补充,关于共享库命名规则(参考自Linux共享库、静态库、动态库详解):
