C专家编程 第5章 对链接的思考 5.3 函数库链接的5个特殊秘密

    函数库链接的五个特殊秘密:(UNIX链接的真实情况)
    1.动态库文件的扩展名“.so”,而静态库文件的扩展名是“.a”
    共享archive的文件名扩展名“.sa”,共享archive只是一种过渡形式,帮助人们从静态库转变成动态库。

    2.例如,通过-lthread选项,告诉编译链接到libthread.so
    实际上,编译器被告知根据选项-lname链接到相应的函数库,函数库的名字是libname.so---换句话说,"lib"部分和文件的扩展名被省略了,但在前面加了一个“-l”。

    3.编译器在确定的目录找到库
    它查看一些特殊的位置,在/usr/lib中查找库。例如,线程库位于/usr/lib/libthread.so.
    编译器选项-Lpathname告知链接器一些其他的目录,如果命令中加入了-l选项,链接器就往这些目录查找函数库。系统中的环境变量LD_LIBRARY_PATH和LD_RUN_PATH用于提供这类信息。处于安全,性能和创建运行独立性方面的考虑,使用环境变量的做法现在已经不提倡。一般还是在链接时使用-Lpathname和-Rpathname选项。

    4.观察头文件,确认所使用的函数库
    一个很好的建议就是可以观察程序所使用的#include指令。在程序中所包含的每个头文件都可能代表一个必须链接的库。但是头文件的名字通常并不与它所对应的函数库名相似。
                         Solaris 2x下的库约定
    #include文件名          库路径名                               所用的编译器选项
    <math.h>                   /usr/lib/libm.so                      -lm
    <math.h>                   /usr/lib/libm.a                        -dn -lm
    <stdio.h>                   /usr/lib/libc.so                        自动连接
    "/user/openwin/include/X11.h" /usr/openwin/lib/libX11.so  -L/usr/openwin/lib-1X11
    <thread.h>                 /usr/lib/libthread.h                 -lthread
    <curses.h>                 /usr/lib/libcurses.a                -lcurses
    <sys/socket.h>           /usr/lib/libsocket.so              -lsocket
    函数库链接所存在的另一个不一致就是函数库包含许多函数的定义,但这些函数的原型声明却散布于多个头文件中。

    nm命令在/usr/lib的每个函数库中浏览所有的符号,从中寻找所丢失的符号。在缺省情况下,链接器会在/usr/cc/lib和/usr/lib中查找,你也应该从这两个地方着手,如果找不到就进一步扩展查找范围。(如/usr/openwin/lib)
    %cd /usr/lib
    %foreach i (lib?*)
    ?echo $i
    ?nm $i | grep xdr_refrence | grep -v UNDEF
    ?end
    ...
    这会在该目录中的所有函数库上运行nm命令,它显示函数库中已知的符号列表。通过grep设定需要搜索的符号,并过滤标记为UNDEF符号(在该函数库中有引用,但不是在此处定义)。结果显示xdr_reference位于libnsl库。需要在编译器命令行的末尾加上-lnsl。

    5.与提取动态库中的符号相比,静态库中的符号提取的方法限制更严
    在动态链接中,所有的库符号进入输出文件的虚拟地址空间中,所有的符号对于链接在一起的所有文件都是可见的。相反,对于静态链接,在处理archive时,它只是在archive中查找载入器当时所知道的未定义符号。简而言之,在编译器命令行中各个静态链接库出现的顺序是非常重要的。符号是通过从左到右的顺序进行解析的。如果相同的符号在两个不同的函数库中有不同的定义,且静态库出现的顺序不同,其结果就有可能不同。

    如果在自己的代码之前引入了静态库,又会带来一个问题。因为此时尚未出现未定义的符号,所以它不会从函数库中提取任何符号。接着,当目标问题被链接器处理时,他所有的对函数库的引用都将是未实现的! 

    libm经常是以静态链接的archive形式存在。如果你的程序使用了一些数学函数如sin()等,若像下面这样进行静态链接:
    cc -lm main.c
    则会得到一条错误信息,如下:
    Undefined first referenced
    symbol    in file
    sin       main.o
    ld:fatal: Symbol referencing errors. No output written to a.out
    为了能从math库中提取所需的符号,首先需要让文件包含未解析的引用,如下所示:
    cc main.c -lm
    链接器采用<命令><文件><选项>这样的约定。

    函数库选项应置于何处
    始终将-l函数库选项放在编译命令行的最右边

    工作区可以在被载入链接器的模式里声明像下面这样的函数,从而向链接器提供更多的线索:在PC上,当Borland的编译器驱动器试图猜测需要链接的浮点数时,也会出现这样的问题。
    scanf: floating point formats not linked
    abnormal program termination(scanf:浮点格式未链接,程序异常中止)
    当程序在scanf()或者printf()中使用浮点数格式,但并不调用任何浮点数函数时,就有可能猜测错误 
    static void forcefloat(float *p) {
        float f = *p; forcefloat(&f);
    } 
    不需要实际调用这个函数,只要保证它被链接即可。这样就能给Borland PC的链接器提供一个足够可靠的线索,即该浮点数库确实是需要的。
    另外还有一条类似的信息,当软件需要数值协处理器而计算机却未安装它时,Microsoft C运行时系统会打印一条信息,表示“浮点数未载入”。可以使用浮点数仿真库重新链接程序来解决这个问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值