跳过导航链接 | |
退出打印视图 | |
手册页第 1 部分:用户命令 Oracle Solaris 11 Information Library (简体中文) |
- 用于检查应用程序级产品对 Solaris 接口的不稳定使用。
appcert [-h] [-n] [-f infile] [-w working_dir] [-B] [-L] [-S] {obj | dir}...
appcert 实用程序用于检查应用程序是否与 Solaris 应用程序二进制接口 (Application Binary Interface, ABI) 兼容。Solaris ABI 定义了 Solaris 中可以供应用程序安全稳定地使用的运行时库接口。更准确地说,appcert 实用程序能够识别依赖于不稳定运行时接口的依赖项以及可能导致产品在 Solaris 的未来发行版中运行失败的其他特定风险。
appcert 可检查:
Solaris 库中的专用符号的使用。专用符号是指不打算供开发者使用的函数或数据。它们是 Solaris 库之间用来互相调用的接口。这些符号可能会改变其语义行为或者甚至完全消失(也称为降级的符号)。因此,确保应用程序不依赖于任何专用接口是一个很好的做法。
静态链接。具体而言,就是检查是否存在归档文件 libc.a、libsocket.a 和 libnsl.a 的静态链接而没有动态链接到对应的共享对象 .so。Solaris 库之间的专用符号调用的语义在不同的发行版之间可能会发生更改。因此,将库代码硬连接到二进制对象的做法是不可取的。
未绑定的符号。未绑定的符号指在运行 appcert 时动态链接程序无法解析的库符号(即函数或数据)。未绑定的符号表明可能存在环境问题(如 LD_LIBRARY_PATH)或构建问题(如在编译时未指定 -llib 和/或 -z defs)。将未绑定的符号标记出来是为了指出这些问题,防止出现更严重的问题。
如果产品是很多程序和支持共享对象的集合,通过让 appcert 引用应用程序的安装目录,可以很容易地利用 appcert 检查整个应用程序。
为执行该任务,appcert 将为产品内的每个目标文件(不管是可执行对象还是共享对象)构建一个接口依赖项配置文件,以确定该产品依赖的所有 Solaris 系统接口。(注:appcert 使用 Solaris 运行时链接程序来执行该确定操作。)然后,这些依赖项配置文件将与 Solaris ABI 的定义进行比较以确定是否存在专用接口(这些专用接口在应用程序级使用时不安全且不稳定)。
appcert 会生成一个简单的汇总报告,其中指出产品的哪些组件有缺陷(如果有)以及它们的缺陷是什么。该报告对正在检查其产品的发行版间稳定性的开发人员很有帮助。
注意,appcert 生成的是完整的接口依赖项信息,包括公用的 Solaris 接口(安全稳定)和专用(非 ABI)接口。如有需要,还可以为每个产品组件检查该信息。
重要说明:appcert 必须与被检查的应用程序在同一环境中运行。请参见“注释”。
支持下列选项:
如果 appcert 在批处理模式下运行,则输出报告中将为每个二进制对象包含一行,以 PASS 开头表示没有检测到该二进制对象的问题,以 FAIL 开头表示发现问题,以 INC 开头表示无法完整检查该二进制对象。解析这些标签时不要太拘泥于字面意义。例如,PASS 只是意味着未触发任何 appcert 警告。这些字符串是左对齐的,因此可以使用 grep^FAIL ... 等进行选定。
指定包含要检查的文件(每个文件一行)的列表的 infile。该文件列表将附加到到由命令行操作数确定的列表中(请参见下面的“操作数”部分)。
输出 appcert 的用法信息。
appcert 检查产品中是否存在共享对象。如果找到一些共享对象,appcert 会将共享对象所驻留的目录附加到 LD_LIBRARY_PATH。使用 –L 标志可以阻止 appcert 的这一行为。
当在目录中搜索要检查的二进制对象时,该选项不跟踪符号链接。请参见 find(1)。
将 Solaris 库目录(即 /usr/openwin/lib:/usr/dt/lib)附加到 LD_LIBRARY_PATH。
指定要在其中运行库组件并创建临时文件的目录(缺省目录为 /tmp)。
支持下列操作数:
要检查的对象的完整列表和/或包含构成要检查的产品的对象的目录完整列表。appcert 以递归方式搜索目录来查找目标文件;非目标文件将被忽略。
将返回以下退出值:
appcert 运行成功,未发现潜在的二进制稳定性问题。
appcert 未能成功运行。
某些已检查的对象存在潜在的二进制稳定性问题。
未找到任何可检查的二进制对象。
如果要检查的目标文件依赖于库,必须在目标文件中记录这些依赖项(使用编译器的 -l 开关)。
如果要检查的目标文件依赖于其他共享库,则在运行 appcert 时必须能够通过 LD_LIBRARY_PATH 或 RUNPATH 访问这些库。
要检查 64 位应用程序,计算机必须运行 64 位 Solaris 内核。请参见 isalist(1)。另外,当前不能对 64 位应用程序执行静态链接检查。??
appcert 不能检查以下内容:
完全或部分静态链接的目标文件。
|
没有设置执行权限的可执行文件。
|
充当 setuid root 的目标文件。????
|
非 ELF 可执行文件,如 shell 脚本。
针对 Solaris,并非 C 语言接口,如 C++ 接口和 Java 接口。
|
appcert 会将结果记录到工作目录(缺省为 /tmp/appcert.?????)中的下列文件。
所检查的二进制对象与工作目录中此二进制对象的特定输出所在子目录之间的映射。
运行 appcert 时在 stdout 上显示的汇总报告的副本。
包含要求 appcert 检查但强制跳过的二进制对象的列表以及跳过每个二进制对象的简单原因。
此外,在 appcert.?????/objects/ 目录下的子目录中还包括针对每个对象的信息,这些信息在以下文件中:
包含怀疑为降级的 Solaris 符号的符号列表。
包含与对象直接绑定的专用 Solaris 符号的列表。
包含与对象直接绑定的公用 Solaris 符号的列表。
包含运行 ldd -r 时动态链接程序没有绑定的符号的列表。为方便起见,还包括 ldd 输出的包含 file not found 的行。
所检查对象的动态绑定的格式整齐的摘要,其中包括从每个 Solaris 库使用的公用符号和专用符号的表。
其他文件是 appcert 在内部使用的临时文件。
专用符号是 Solaris 库中的一些不打算供开发者或外部使用的函数或数据变量。这些符号是 Solaris 库之间进行互相调用和通信的接口。在 pvs(1) 输出中,这些符号的符号版本名称标记为 SUNWprivate。
专用符号可能会改变其语义行为或者甚至完全消失(降级的或者废弃的符号)。因此,您的应用程序不应依赖于任何专用符号。
降级符号是某个 Solaris 库中曾经专用于该库,但在后续 Solaris 发行版中已经删除(或其作用域被限制为该库本地)的函数或数据变量。如果应用程序直接调用了某个降级的符号,则该应用程序在删除了该符号的发行版中及后续发行版中将无法运行(重定位错误)。
在极少数情况下,在某个后续发行版中会恢复某个降级的符号。尽管如此,应用程序仍不能在某些发行版中运行。
Sun Microsystems Inc. 在从 Solaris 2.5.1 转变到 Solaris 2.6 时执行了大部分库的作用域确定。这一措施是为了增强二进制对象的稳定性。通过使这些完全内部的接口不可见(即它们无法被动态链接),开发者无法有意或无意地调用这些接口。有关更多信息,请参见《链接程序和库指南》,特别是介绍版本控制的章节。
未绑定的符号是指在应用程序引用的库符号中,在运行 appcert 时动态链接程序无法解析的那些库符号。注:appcert 并不真正运行应用程序,因此,影响动态链接的某个环境方面可能没有正确设置。
未绑定的符号不是一定表明存在潜在的二进制稳定性问题。它们唯一表明的是在运行 appcert 时,运行时动态链接程序无法解析这些符号。
存在未绑定的符号的原因可能是 LD_LIBRARY_PATH 设置得不正确。请确保正确设置该变量,这样您所有的二进制对象才能找到它们依赖的所有库(您的产品自己的库,Solaris 库,或者第三方的库)。然后,重新运行 appcert。
您可能会发现编写一个 shell 脚本,使用该脚本来正确设置环境并针对您要检查的二进制对象运行 appcert 比较方便。
存在未绑定的符号的另一个常见原因是测试中的共享对象未记录其动态依赖项,也就是说,在构建时没有将 -l 开关提供给编译器和 ld(1)。因此,共享对象要求基于它链接的可执行程序记录正确的依赖项。
注意,这样的共享对象可以通过标准形式进行链接(即在构建可执行程序时指定)或者动态打开(例如,可执行程序在运行时可能会针对共享对象调用 dlopen(3C)。在以上两种情况下,运行 appcert 时都会存在未绑定的符号。在第一种情况下,可通过在运行 appcert 之前正确设置 LD_LIBRARY_PATH 来解决未绑定的符号问题。在第二种情况 (dlopen) 下,很难解决未绑定的符号问题。在某些情况下,可以正确设置 LD_PRELOAD 来预装入所需的库,但该过程并不是总能奏效。
如何了解环境是否已经正确设置并可以避免出现未绑定的符号?如果运行 ldd -r 时未出现 "file not found" 或 "symbol not found" 错误,表明环境已经正确设置。有关动态链接的更多信息,请参见 ld.so.1(1) 和 ldd(1)。
在任何情况下,appcert 都会将未绑定的符号标记为警告,以防还暗藏着更严重的问题。未绑定的符号可能表明存在依赖于降级的符号(已从库中删除的符号或作用域调整为该库本地的符号)的依赖项。依赖于降级的符号的依赖项会导致严重的二进制稳定性问题。
不过,正确地设置环境应该能够消除大多数未绑定的符号。通常,比较好的做法是尽可能地在构建时记录库的依赖项,这样有助于更好地定义二进制对象并使其成为自包含的。另外,建议在构建共享对象时使用 -z defs 标志来强制在编译时解析所有符号。有关更多信息,请参见 ld(1)。
appcert 针对每个要测试的二进制对象运行 /bin/ldd -r。该命令对环境变量进行如下设置:LD_DEBUG="files,bindings"。(有关更多信息,请参见 ldd(1) 和 ld.so.1(1))。如果该命令由于某种原因而失败,appcert 将不能获得任何动态符号绑定信息并将找不到绑定。
存在以下任一情况时,appcert 可能会失败:
二进制对象没有读权限。
二进制对象是 SUID 或 SGID,并且用户没有足够的权限。
二进制对象是一个没有设置执行权限位的可执行程序。
二进制对象是完全静态链接的。
二进制对象没有记录库依赖项信息。
同样,还存在其他一些情况,如内存不足。通常,该标志意味着由于权限或环境问题,appcert 无法完整地检查对象。请尝试修改权限或环境以便能够记录动态绑定。
过时的库是指已不赞成使用并且可能会在将来的某个发行版中从 Solaris 中完全删除的库。appcert 将这些库标出是因为依赖于此类库的应用程序可能无法在将来的 Solaris 发行版中运行。过时的库中的所有接口(包括专用接口)都被冻结且不会更改。
直接使用 sys_errlist 或 sys_nerr 符号会存在风险,导致引用可能超出 sys_errlist 数组的结尾。这些符号在 32 位版本的 Solaris 中不赞成使用,而在 64 位版本中完全不存在。请改用 strerror(3C)。
与弱符号(如 socket)关联的强符号(如 _socket)保留为专用符号(其行为在将来可能会改变)。您的应用程序只应直接引用弱符号(强符号通常以 "_" 开头)。
注:在某些构建环境下,尽管源代码看起来没有引用专用符号,也会在您的二进制代码中记录强符号/专用符号依赖性而不是记录弱符号/公用符号依赖性。不过,应采取措施来弄清发生此情况的原因并纠正此依赖性。
appcert 应该与要检查的应用程序在相同的环境中运行。否则,它将无法将引用正确解析到 Solaris 库中的接口。请采取下列步骤:
确保将 LD_LIBRARY_PATH 及环境的任何其他方面设置为应用程序在运行时使用的设置。另外,请确保该设置包含产品中的任何非 Solaris 共享对象所在的目录,以确保在引用这些对象时可以找到它们。
确保要检查的所有二进制对象满足以下条件:
是动态链接的 ELF 对象
设置了对可执行程序的执行权限(共享对象不必满足此条件)。
不是 SUID 超级用户(否则,必须是超级用户才能检查;必要时,请创建非 SUID 副本并检查这些副本)。
您可能会发现编写一个 shell 脚本,使用该脚本来正确设置环境并运行 appcert 比较方便。
可能会遇到下面一些潜在的问题:
appcert 将看起来是 Solaris 库的一部分的符号报告为未绑定的符号。
当应用程序使用 dlopen(3C) 访问没有记录其 Solaris 依赖项的共享对象时,可能会发生这种情况。appcert 在这种情况下无法解析符号的使用,因为从不会针对共享对象调用动态链接程序,并且没有任何其他依赖项信息可用来解析 Solaris 符号绑定。对于非 Solaris 符号也会发生这种情况。
为避免该问题,请确保在构建共享对象时,在编译行上使用 -llib 选项来显式记录共享对象对 Solaris 库的依赖项信息(请参见 cc(1) 和 ld(1))。
appcert 报告指出应用程序使用了应用程序的源代码中没有引用的 Solaris 专用符号。
该问题很有可能是由引用该符号的 Solaris 库的静态链接造成的。由于 appcert 使用动态链接程序来解析符号,因此,在 appcert 看来,静态链接的库是应用程序代码的一部分(从某种意义上来说,它们确实是)。有时,Solaris 头文件中的宏替换也会导致该问题。
为避免该问题,请尽量不要将 Solaris 库归档文件静态链接到您的应用程序中。
appcert 不能识别作为 Solaris 的一部分的库。
有些过时的 Solaris 库太旧了,以致于还没能够对其符号进行版本化,这些库就已被废弃了。因此,appcert 无法将其识别为 Solaris 的一部分。
遗憾的是,将术语“公用”和“专用”分别等同于“稳定”和“不稳定”让人有点困惑。需要特别说明的是,实验性的或者正在改进的接口从某种意义上来说是公用的,因为它们是记录在案的并且鼓励使用它们。但这些接口是不稳定的,因为构建有这些接口的应用程序可能无法在后续发行版中运行。因此,为了方便 appcert 检查,这些接口被归类为专用接口,直到它们不再改进。与此相反,过时的接口最终将会消失,因此是不稳定的,即使它们在过去是公用且稳定的并且 appcert 当前仍将其视为公用接口。幸运的是,这两种情况极少见。
有关下列属性的描述,请参见 attributes(5):
|
cc(1)、find(1)、isalist(1)、ld(1)、ldd(1)、ld.so.1(1)、pvs(1)、dlopen(3C)、strerror(3C)、Intro(4)、attributes(5)