结束语及最佳实践总结

库、链接、初始化和 C++ 系列的第 8 部分

作者:Darryl Gove 和 Stephen Clamage,2011 年 7 月

第 1 部分 — 库和链接简介
第 2 部分 — 解析库中的符号


功能的分类

将应用程序作为可执行文件与一组库一起提供可能涉及一些复杂情况。有几个问题需要谨慎考虑。第一个要考虑的问题是设计适当的库层次结构,以便每个库既可以依赖自身实现其功能,又可以利用层次结构中下层库所提供的功能。依赖高层库实现功能的低层库不应存在任何循环依赖。

编译时,可使用 -z defs 标志实施层次结构,以便报告任何未解析的符号并显式列出每个新库依赖的现有库。-L 标志应与路径结合使用以确保链接程序可以找到现有库。
 

避免符号混乱

最小化库导出的符号数可确保只能使用这些符号。这将降低多个库定义了同一符号时发生冲突的风险,将避免调用库内部例程的可能性,还将减少运行时链接程序加载库时必须执行的工作量。所有这些都很重要。另一个要避免的问题是一个符号的多重定义。

符号作用域可用于避免导出库内部的符号。指定作用域的最佳方法是将所有未另行指定的内容设置为隐藏作用域。这可以使用编译器标志 -xldscope=hidden 实现。然后必须使用关键字前缀 __symbolic 声明需要导出的符号。符号作用域指示应优先使用本地符号,而非任何其他同名符号,并且还指示应导出符号以供其他库使用。需要由某库导入的所有符号应使用前缀 __global 进行声明。声明为全局的符号在定义后可供任何库使用。如果这些全局符号未定义,那么将被运行时链接程序解析为外部符号。本地定义可以满足全局符号,但实际上不必如此。

对于现有代码,使用作用域标志 -xldscope=symbolic 编译所有内容的变通办法可确保库优先绑定到符号的本地版本而非全局版本。这可以使有符号绑定问题的应用程序正常工作,但也会带来问题。依赖干预对库函数的调用的应用程序将无法看到库内发生的调用。依赖只有一个定义的特定符号的应用程序可能会发现同一符号在同一应用程序的不同部分的解析有所不同。

库可能积累不必要符号的另一区域是通过定义内联例程或模板。头文件中声明的成员函数可以出现在包含该头文件的任何库中。在这些情况下,对成员函数或变量设置适当的作用域是控制多重定义的最佳办法。对于模板代码,编译器标志 -instlib=<library> 将导致编译器在位于所识别库中的模板代码的当前编译单元中不发出定义。
 

在运行时找到库

在运行时,运行时链接程序需要找到应用程序所需的库。依赖于设置 LD_LIBRARY_PATH 来使运行时链接程序找到所需库从来就不是一种好的做法。最好的方法是使用编译时标志 -R <path> 将运行时路径嵌入可执行文件或库中。在运行时可使用此路径找到所需的库。

尽管为 -R 标志提供硬编码路径的方法很诱人,但建议使用令牌 $ORIGIN 提供相对于可执行文件位置的相对路径。这样做可确保应用程序及其库可以存储在相对路径所保留的任意位置,并且仍可以正常工作。

从链接程序获取指导

Oracle Solaris 11 Express 中的链接程序在 -zguidance 标志下提供了一个新特性。该选项对如何改进链接提供了一些指导。清单 1 显示了这样一个示例。

清单 1:Oracle Solaris 11 Express 链接程序提供的指导
$ CC -o main main.cpp -L. -R'$ORIGIN' -ldata -zguidance
ld: guidance: -z lazyload option recommended before first dependency
ld: guidance: -B direct or -z direct option recommended before first dependency
ld: guidance: removal of unused dependency recommended: libCstd.so.1
ld: guidance: removal of unused dependency recommended: libm.so.2
ld: guidance: see ld(1) -z guidance for more information

在本示例中,编译时链接程序建议使用库的直接绑定和延迟加载。它还报告未使用 libCstd.so.1libm.so.2。这些库被 C++ 编译器自动包含在链接中,但在此实例中,应用程序没有使用它们。
 

结束语

有充分的理由将应用程序作为可执行文件和库的组合进行分发。本系列文章中的所有规则可使结果应用程序正确、高效地工作。如果遇到符号作用域或库初始化问题,则使用调试工具(如 LD_DEBUG)或工具(如 nmlari)可促进快速诊断。

修订版 1,2011 年 7 月 11 日