由于学完很容易忘记,还是需要有个记录,以便随时查阅一下。
主要记录Linux C的学习笔记。
1、静态库
文件目录结构如下
$ tree
.
|-- main.c
`-- stack
|-- is_empty.c
|-- pop.c
|-- push.c
|-- stack.c
`-- stack.h
1 directory, 6 files
(1)、把stack.c 、 push.c 、 pop.c 、 is_empty.c 编译成目标文件
$ gcc -c stack/stack.c stack/push.c stack/pop.c stack/is_empty.c
(2)、打包成一个静态库libstack.a
$ ar rs libstack.a stack.o push.o pop.o is_empty.o
ar: creating libstack.a
库文件名都是以 lib 开头的,静态库以 .a 作为后缀,表示Archive。
ar 命令起一个打包的作用
选项 r 表示将后面的文件列表添加到文件包,如果不存在就创建它,如果已有同名文件就替换成新的
选项s 是专用于生成静态库的,表示为静态库创建索引,这个索引被链接器使用
另外,ranlib 命令也可以为静态库创建索引,以上命令等价于
$ ar r libstack.a stack.o push.o pop.o is_empty.o
$ ranlib libstack.a
(3)、然后把libstack.a 和 main.c 编译链接在一起:
$ gcc main.c -L. -lstack -Istack -o main
-L 告诉编译器去哪里找库文件,-L.表示到当前目录查找(即使库文件就在当前目录,编译器默认也不会去找,必须指定)
-l 选项,是小写的l,告诉编译器要链接哪个库,这里是libstack库
-I 选项,是i的大写,告诉编译器去哪里找头文件
编译器默认会查找的目录,可以通过下面命令查看:
$ gcc -print-search-dirs
2、共享库
(1)、编译目标文件
组成共享库的目标文件和普通的目标文件有所不同,在编译时需要加上-fPIC选项
$ gcc -c -fPIC stack/stack.c stack/push.c stack/pop.c stack/is_empty.c
-f 后面跟一些编译选项, PIC 是其中一种,表示生成位置无关代码(Position Independent Code)
(2)、编译生成共享库文件
$ gcc -shared -o libstack.so stack.o push.o pop.o is_empty.o
(3)、然后把libstack.a 和 main.c 编译链接在一起:
$ gcc main.c -L. -lstack -Istack -o main
注意,编译通过没问题,但是运行时会提示找不到libstack.so
怎么解决呢?首先用ldd命令查看main文件依赖哪些共享库
$ ldd main
linux-gate.so.1 => (0xb7f5c000)
libstack.so => not found
libc.so.6 => /lib/tls/i686/cmov/
共享库的搜索路径由动态链接器决定,从 ld.so(8) 的Man Page可以查到共享库路径的搜索顺序:
1. 首先在环境变量 LD_LIBRARY_PATH 所记录的路径中查找。
2. 然后从缓存文件 /etc/ld.so.cache 中查找,这个缓存文件由 ldconfig 命令读取配置文件 /etc/ld.so.conf 之后生成。
3. 如果上述步骤都找不到,则到默认的系统路径中查找,先是/usr/lib,然后是/lib
解决上面问题最常用的方法,把 libstack.so 所在目录的绝对路径(比如/home/akaedu/somedir)添加到
/etc/ld.so.conf 中(该文件中每个路径占一行),然后运行 ldconfig 命令
现在再用ldd命令查看,libstack.so就能找到了
另外,还可以把libstack.so考到/usr/lib或/lib下面,也可以确保动态链接器能找到这个共享库
共享库的命名规则:
按照共享库的命名惯例,每个共享库有三个文件名:real name、soname和linker name。
real name:真正的库文件(而不是符号链接),包含完整的共享库版本号。例如上面的 libcap.so.1.10 、 libc-2.8.90.so 等
soname:是一个符号链接的名字,只包含共享库的主版本号,主版本号一致即可保证库函数的接口一致,例如上面的 libcap.so.1 和 libcap.so.2 是两个主版本号不同的 libcap
linker name:仅在编译链接时使用, gcc 的 -L 选项应该指定linker name所在的目录,例如 libc.so,它可能是一个链接符号,也可能时一段链接脚本
静态库和共享库的区别
静态库是在链接时就把目标文件和可执行文件main真正链接在一起了,而且只把用到的部分链接,没有用的的部分不做链接。
共享库在链接时只是指定了动态链接器和该程序所需要的库文件,在运行时才动态链接。