Linux C 库的生成与使用

库文件的存在极大的提升了 C/C++ 程序的复用性,本文简单介绍如何生成、使用它们。html

命名约定: 咱们通常对库文件约定以 lib 开头,动态库文件通常以 .so(*nix)或 .dll(Windows) 结尾,静态库文件通常以 .a(*nix)或 .lib(Windows) 结尾。linux

动态库还分为两种用法:架构

  1. 在编译期间声明动态库的存在,运行时由系统连接器自动连接
  2. 在运行期间动态加载和卸载,由用户程序决定什么时候连接

下面咱们以 Linux 为例,Windows 的用法与此有所不一样,但思路大同小异。函数

生成和使用静态连接库

将库源码编译成目标文件:工具

$ gcc -c struct.c [-o struct.o]

打包库文件:.net

$ ar cr libstruct.a struct.o # 注意参数顺序不能错

这里的 artar 相似,是一种打包工具。插件

可使用 $ ar -t libstruct.a 命令 检查包含哪些 .o 文件。设计

构建符号表:code

$ ranlib libstruct.a

这个命令不是必须的,是由于部分 ar 的实现集成了该功能,此时的 ranlib 就是一个空壳命令。htm

连接静态库,生成可执行文件:

$ gcc main.c -static -L . -lstruct -o main

由于咱们约定库文件以 lib 开头,因此这里能够省掉它。

设置库文件的环境路径:

  1. 定义 LD_LIBRARY_PATH 环境变量,添加动态库文件的路径。
  2. 把库路径添加到 ld.so.conf 文件中,而后用 ldconfig 加载。
  3. 使用 ldconfig <path-to-so-directory> 临时加载。

编译时,若是出现重名的动态库和静态库,优先使用动态库。

生成和使用动态连接库

编译动态连接库文件:

$ gcc -shared -fPIC struct.c -o libstruct.so

这其实融合了好几条命令,但咱们不作细述。

-fPIC 表示编译为“地址无关”的代码,用于编译共享库。若是不加 -fPIC 则加载 so 文件的代码段时,代码段引用的数据对象须要重定位,重定位会修改代码段的内容,这就形成每一个使用这个 so 文件代码段的进程在内核里都会生成这个 so 文件代码段的副本。

通常老是用 -fPIC 来生成 .so 文件,也历来不用fPIC来生成 .a 文件。

通常如下几种状况不须要:

  1. 该库可能须要常常更新
  2. 该库须要很是高的效率,尤为是有不少全局量的使用时
  3. 该库并不大
  4. 该库基本不须要被多个应用程序共享

连接动态库,生成可执行文件:

$ gcc main.c -L . lstruct -o main

通常咱们习惯将动态连接库放入系统库目录:

$ gcc -shared -Wl,-soname,libstruct.so.1 -o libstruct.so.1 *.o

其中 -Wl 前缀的命令会传递给 ld 命令。咱们以前说过,gcc 融合了多条命令。

也就是在连接 .o 文件时会执行:

$ ld -soname libstruct.so.1

libstruct.so 用于在编译期间使用 -lstruct 找到动态库,而 libstruct.so.1 则在运行期间真正被连接。

$ mv libstruct.so.1 /opt/lib
$ ln -sf /opt/lib/libstruct.so.1 /opt/lib/libstruct.so.1
$ ln -sf /opt/lib/libstruct.so.1 /opt/lib/libstruct.so

查看程序对动态库的依赖

$ ldd main

libstruct.so.1 => /opt/lib/libstruct.so.1 (0x00002aaaaaaac000)
libc.so.6 => /lib64/tls/libc.so.6 (0x0000003aa4e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003aa4c00000)

ldd 脚本中文详解

查看 obj 文件的符号表

obj 文件的格式和组成多是系统差别性的一大致现,好比 Windows 下的 PE、Linux 和部分 Unix 下的 elf、Mac OS 下的 mach-o、aix 下的 xcoff。

使用 nmobjdumpreadelf 等命令能够查看 .o .a .so 文件中的符号信息。

好比,下面这将打印出 hello.o 中未定义的符号:

$ nm -u hello.o

在运行时动态加载和卸载库

须要应用程序但愿设计成插件化的架构,这就须要能够动态加载和卸载库的机制。与动态连接不一样的是,动态加载的意思是,编译期间能够对动态库的存在一无所知,而是在运行期间经过用户程序尝试加载进来的。

经过 dlfcn.h 中的 dlopendlsymdlclose 等函数实现此种功能。

另外,使用 dlfcn机制须要在连接时使用 -rdynamic 选项,它将指示链接器把全部符号(而不只仅只是程序已使用到的外部符号,但不包括静态符号,好比被 static 修饰的函数)都添加到动态符号表(即 .dynsym 表)里。

GNU Libtool

现在许多软件的编译都采用 libtool 工具,libtool 是一个编译连接包装工具,实际只是一个脚本,用 libtool 编译和连接会产生相似 .la 的文件,这种文件实际上是个文本文件,指向 .a 文件,并声明一些版本信息。

更多

若是想更好地了解,须要多看 gcc / ar / ldd / nm 的参数。

相关文章
相关标签/搜索