链接详解

由于学完很容易忘记,还是需要有个记录,以便随时查阅一下。

主要记录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真正链接在一起了,而且只把用到的部分链接,没有用的的部分不做链接。

共享库在链接时只是指定了动态链接器和该程序所需要的库文件,在运行时才动态链接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值