库提供了在多个应用程序间共享代码的方法,也提供了减小超大型应用程序复杂度的方法。C++ 编译器使您可以访问各种库。本章说明了如何使用这些库。
Solaris 操作系统附带了安装在 /usr/lib 中的几个库。这些库大多有 C 接口。缺省情况下,其中的 libc 和 libm 库通过 CC 驱动程序进行链接。如果使用 –mt 选项,则链接 libthread 库。如果要链接其他系统库,请在链接时使用适当的 –l 选项。例如,要链接 libdemangle 库,请在链接时在 CC 命令行上传递 –ldemangle:
example% CC text.c -ldemangle |
C++ 编译器具有自己的运行时支持库。所有 C++ 应用程序都由 CC 驱动程序链接到这些库。C++ 编译器还具有其他一些有用的库,如下节所述。
C++ 编译器附带了一些库。其中一些只能在兼容模式 (-compat=4) 下使用,有些只能在标准模式 (–compat=5) 下使用,有些可以在这两种模式下使用。libgc 和 libdemangle 库都有 C 接口,可以在任何模式下链接到应用程序。
下表列出了随 C++ 编译器提供的库,以及可以使用这些库的模式。
表 12–1 C++ 编译器附带的库
库 |
说明 |
可用模式 |
---|---|---|
libstlport |
标准库的 STLport 实现。 |
–compat=5 |
libstlport_dbg |
调试模式的 STLport 库 |
–compat=5 |
C++ 运行时 |
–compat=5 |
|
C++ 标准库 |
–compat=5 |
|
传统 iostream |
–compat=5 |
|
C++ 运行时,传统 iostream |
–compat=4 |
|
支持 -xia 选项 |
–compat=5 |
|
复数库 |
–compat=4 |
|
librwtool |
Tools.h++ 7 |
–compat=4、– compat=5 |
支持调试的 Tools.h++ 7 |
–compat=4、–compat=5 |
|
垃圾收集 |
C 接口 |
|
还原 |
C 接口 |
请勿重新定义或修改用于 STLport、Rogue Wave 或 Sun Microsystems C++ 库的任何配置宏。库是按照适用于 C++ 编译器的方式进行配置和生成的。libCstd 和 Tool.h++ 配置为可互操作,因此,修改配置宏会导致程序不能编译、不能链接或不能正常运行。
以下是这些库中每个库的简单描述。
libCrun: 该库包含了标准模式 (–compat=5) 下编译器所需的运行时支持,并提供了对 new/delete、异常及 RTTI 的支持。
libCstd: 这是 C++ 标准库。具体来说,该库包含了 iostream。如果有使用传统 iostream 的现有源代码,而且要使用标准 iostream,必须修改源代码以符合新接口。有关详细信息,请参见《C++ 标准库参考》联机手册。
如果您的编译器软件没有安装在 /opt 目录中,请向系统管理员询问该软件在系统中的安装路径。
libiostream: 这是使用 – compat=5 生成的传统 iostream 库。如果有使用传统 iostream 的源代码,且要在标准模式 (–compat=5) 下编译这些源代码,可以使用 libiostream 而不必修改源代码。可使用 – library=iostream 获取此库。
标准库的很大部分取决于使用的标准 iostream。在相同程序中使用传统的 iostream 可能会出现问题。
libC: 这是兼容模式 (–compat=4) 下所需的库。该库包含了 C++ 运行时支持和传统 iostream。
libcomplex: 该库提供了兼容模式 (-compat=4) 下的复数运算。在标准模式下,可使用 libCstd 中的复数运算功能。
libstlport:这是 C++ 标准库的 STLport 实现。可以通过指定选项 -library=stlport4,使用该库而非缺省的 libCstd。但不能在同一程序中同时使用 libstlport 和 libCstd。您必须使用其中之一编译和链接包括输入库在内的一切项目。
librwtool (Tools.h++):Tools.h++ 是来自 RogueWave 的 C++ 基础类库。提供了版本 7。该库已过时,不应在新代码中使用该库。提供它是为了支持针对使用 RW Tools.h++ 的 C++ 4.2 编写的程序。
libgc: 该库用于部署模式或垃圾收集模式。只是与 libgc 库链接就会自动且永久修复程序的内存泄漏。虽然能以其他方式正常编程,但如果将程序与 libgc 库链接,则无需调用 free 或 delete 就可完成编程。垃圾收集库对动态装入库具有依赖性,因此在链接程序时要指定 -lgc 和 -ldl。
有关其他信息,请参见 gcFixPrematureFrees(3) 和 gcInitialize(3) 手册页。
libdemangle: 该库用于还原 C++ 损坏名称。
与本节所述库关联的手册页位于第 1、3、3C++ 和 3cc4 节中。
要访问 C++ 库的手册页,请输入:
example% man library-name |
要访问 C++ 库版本 4.2 的手册页,请输入:
example% man -s 3CC4 library-name |
缺省情况下,CC 驱动程序会链接其中一些 C++ 库,而其他库需要显式链接。在标准模式下,CC 驱动程序缺省链接下列库:
-lC -lm -lc
有关更多信息,请参见A.2.50 -library=l[ ,l...]。
CC 驱动程序提供了一些选项来帮助用户使用库。
-mt 选项用于编译和链接多线程代码。
-xia 选项用于链接区间运算库。
-xlang 选项用于链接 Fortran 或 C99 运行时库。
–library 选项用于指定 Sun C++ 编译器附带的下列库:
libCrun
libCstd
libiostream
libC
libcomplex
libstlport、libstlport_dbg
librwtool、librwtool_dbg
libgc
要使用传统 iostream 形式的 librwtool,请使用 -library=rwtools7 选项。要使用标准 iostream 形式的 librwtool,请使用 -library=rwtools7_std 选项。
以下命令动态链接传统 iostream 形式的 Tools.h++ 版本 7 和 libiostream 库。
example% CC test.cc -library=rwtools7,iostream |
以下命令静态链接 libgc 库。
example% CC test.cc -library=gc -staticlib=gc |
以下命令在兼容模式下编译 test.cc 并静态链接 libC。因为在兼容模式下缺省链接 libC,所以不必使用 – library 选项指定该库。
example% CC test.cc -compat=4 -staticlib=libC |
以下命令排除了库 libCrun 和 libCstd,否则缺省情况下这两个库包括在内。
example% CC test.cc -library=no%Crun,no%Cstd |
缺省情况下,CC 根据命令行选项链接不同的系统库集合。如果指定 -xnolib(或 -nolib),CC 仅链接在命令行上使用 -l 选项显式指定的那些库。(如果使用 -xnolib 或 -nolib,会忽略 -library 选项(如果有)。)
使用 –R 选项可以在可执行文件中生成动态库搜索路径。执行期间,运行时链接程序使用这些路径搜索应用程序所需的共享库。缺省情况下,CC 驱动程序将 – R<install_directory>/lib 传递给 ld(如果编译器安装在标准位置中)。可以使用 -norunpath 禁止在可执行文件中生成共享库的缺省路径。
对于针对部署生成的程序,应该使用 -norunpath 或 -R 选项进行生成,这样可避免在编译器目录中查找库。(请参见12.6 使用共享库)。
在源码中包括适当的头文件。
将程序与目标库链接。
传统 iostream。该术语是指 C++ 4.0、4.0.1、4.1 和 4.2 编译器以及早期基于 cfront 的 3.0.1 编译器附带的 iostream 库。该库没有任何标准,只是很多现有代码使用它。在兼容模式下,该库是 libC 的一部分,在标准模式下,libiostream 中也有该库。
标准 iostream。这是 C++ 标准库 libCstd 的一部分,仅用于标准模式下。该库与传统 iostream 库的二进制和源码都不兼容。
如果已有 C++ 源,那么代码可能象以下示例一样使用传统 iostream。
// file prog1.cc #include <iostream.h> int main() { cout << "Hello, world!" << endl; return 0; } |
以下命令在兼容模式下编译 prog1.cc,并将其链接到名为 prog1 的可执行程序中。传统 iostream 库是 libC 的一部分,兼容模式下缺省链接该库。
example% CC -compat prog1.cc -o prog1 |
下一个示例使用标准 iostream。
// file prog2.cc #include <iostream> int main() { std::cout << "Hello, world!" << std::endl; return 0; } |
以下命令编译 prog2.cc 并将其链接到名为 prog2 的可执行程序中。该程序在标准模式下编译,且缺省链接包括标准 iostream 库的 libCstd。
example% CC prog2.cc -o prog2 |
有关 libCstd 的更多信息,请参见忠告:。有关 libiostream 的更多信息,请参见13.3.1 重新分发和支持的 STLport 库。
有关编译模式的完整讨论,请参见《C++ 迁移指南》。
标准库提供了模板化的 complex 库,该库与 C++ 4.2 编译器提供的 complex 库类似。如果在标准模式下编译,必须使用 <complex> 而非 <complex.h>。不能在兼容模式下使用 <complex>。
在兼容模式下,必须在链接时显式请求 complex 库。在标准模式下,complex 库包括在 libCstd 中,缺省情况下链接该库。
标准模式下,没有 complex.h 头文件。在 C++ 4.2 中,"complex" 是类名称,但在标准 C++ 中,"complex" 是模板名称。不可能提供可使旧的代码不加修改就可工作的 typedef。因此,为使用复数的 4.2 版编写的代码需要某些简单的编辑,以便使用标准库。例如,以下代码是为 4.2 版编写的,并将在兼容模式下编译。
// file ex1.cc (compatibility mode) #include <iostream.h> #include <complex.h> int main() { complex x(3,3), y(4,4); complex z = x * y; cout << "x=" << x << ", y=" << y << ", z=" << z << endl; } |
以下示例在兼容模式下编译并链接 ex1.cc,然后执行该程序。
example% CC -compat ex1.cc -library=complex example% a.out x=(3, 3), y=(4, 4), z=(0, 24) |
下面将 ex1.cc 重写为 ex2.cc 以在标准模式下编译:
// file ex2.cc (ex1.cc rewritten for standard mode) #include <iostream> #include <complex> using std::complex; int main() { complex<double> x(3,3), y(4,4); complex<double> z = x * y; std::cout << "x=" << x << ", y=" << y << ", z=" << z << std::endl; } |
以下示例在标准模式下编译并链接重写的 ex2.cc,然后执行该程序。
% CC ex2.cc % a.out x=(3,3), y=(4,4), z=(0,24) |
关于使用复数运算库的更多信息,请参见表 14–4。
下表列出了链接 C++ 库的编译器选项。有关更多信息,请参见A.2.50 -library=l[ ,l...]。
表 12–2 链接 C++ 库的编译器选项
库 |
编译模式 |
选项 |
---|---|---|
–compat=5 |
不需要 -library=iostream |
|
complex |
–compat=4 -compat=5 |
-library=complex 不需要 |
–compat=4 –compat=5 |
-library=rwtools7 -library=rwtools7_std |
|
Tools.h++ 版本 7 调试 |
–compat=4 –compat=5 |
-library=rwtools7_dbg -library=rwtools7_dbg,iostream -library=rwtools7_std_dbg |
–compat=4 –compat=5 |
-library=gc -library=gc |
|
STLport 版本 4 |
–compat=5 |
-library=stlport4 |
STLport 版本 4 调试 |
–compat=5 |
-library=stlport4_dbg |
CC 驱动程序在缺省情况下链接几个库的共享版本(包括 libc 和 libm),这通过为每个缺省库将 -llib 选项传递给链接程序来实现。(有关兼容模式和标准模式下的缺省库列表,请参见12.2.3 缺省 C++ 库。)
如果要静态链接其中任何缺省库,可以使用 -library 选项和 –staticlib 选项来静态链接 C++ 库。这种替换方法比上文所述的方法简单。例如:
example% CC test.c -staticlib=Crun |
在此示例中,没有在命令中显式包括 -library 选项。这种情况下,无需 -library 选项,因为在标准模式(缺省模式)下,-library 的缺省设置是 Cstd,Crun。
也可以使用 -xnolib 编译器选项。使用 -xnolib 选项时,驱动程序不会将任何 -l 选项传递给 ld,所以您必须自己传递这些选项。以下示例显示了在 Solaris 8 或 Solaris 9 操作系统中如何静态链接 libCrun 以及如何动态链接 libm 和 libc:
example% CC test.c– xnolib– lCstd– Bstatic– lCrun– Bdynamic– lm– lc |
-l 选项的顺序很重要。– lCstd、– lCrun 和 -lm 选项位于 -lc 之前。
建议不要静态链接 libCrun 和 libCstd。而是生成 /usr/lib 中的动态版本以与其所安装在的 Solaris 版本一起使用。
有些 CC 选项链接到其他库。也可以使用 -xnolib 抑制这些库链接。例如,使用 -mt 选项会导致 CC 驱动程序将 -lthread 传递给 ld。但如果同时使用 –mt 和 –xnolib,CC 驱动程序不会将 -lthread 传递给 ld。有关更多信息,请参见A.2.153 –xnolib。有关 ld 的更多信息,请参见《链接程序和库指南》。
/lib 和 /usr/lib 中静态版本的 Solaris 库不再可用。例如,试图静态链接 libc 的操作将失败:
CC hello.cc -xnolib -lCrun -lCstd -Bstatic -lc |
C++ 编译器附带下列 C++ 运行时共享库:
libCCexcept.so.1(仅限 SPARC Solaris)
libcomplex.so.5(仅限 Solaris)
librwtool.so.2
libstlport.so.1
在 Linux 上,C++ 编译器附带这些附加库:
libCrun.so.1
libCstd.so.1
libdemangle.so
libiostream.so.1
在 Solaris 上,这些附加库以及其他一些库作为 Solaris C++ 运行时库软件包 SUNWlibC 的一部分安装。
如果应用程序使用 C++ 编译器附带的任何共享库,则 CC 驱动程序会安排运行路径(请参阅 -R 选项),该运行路径指向将在可执行文件中生成库的位置。如果之后将可执行文件部署到另一台计算机上,而该计算机上并没有在同一位置安装同一编译器版本,将找不到所需的共享库。
在程序启动时,可能根本找不到此库,或可能使用错误版本的库,从而导致错误的程序行为。在这种情况下,应该将所需库与可执行文件一起提供,并使用指向这些库将要安装的位置的运行路径进行生成。
《Using and Redistributing Sun Studio Libraries in an Application》(《在应用程序中使用与重新分发 Sun Studio 库》一文中详细讨论了该主题并提供了示例,请参见 http://developers.sun.com/sunstudio/documentation/techart/stdlibdistr.html。
替换与编译器一起发布的标准库是有风险的,不能保证产生预期的结果。基本操作是禁用编译器提供的标准头文件和库,指定找到新的头文件和库(及库本身的名称)的目录。
编译器支持标准库的 STLport 实现。有关更多信息,请参见13.3 STLport。
可以替换大多数标准库及其关联头文件。替换的库是 libCstd,关联的头文件如下所示:
<algorithm> <bitset> <complex> <deque> <fstream <functional> <iomanip> <ios> <iosfwd> <iostream> <istream> <iterator> <limits> <list> <locale> <map> <memory> <numeric> <ostream> <queue> <set> <sstream> <stack> <stdexcept> <streambuf> <string> <strstream> <utility> <valarray> <vector>
库的可替换部分由一般称为 "STL" 的内容和字符串类、iostream 类及其帮助类组成。因为这些类和头文件是相互依赖的,所以不能仅替换其中的一部分。如果要替换任何一部分,就应该替换所有头文件和所有 libCstd。
标准头文件 <exception>、<new> 和 <typeinfo> 与编译器本身以及 libCrun 紧密相关,不能可靠替换。库 libCrun 包含了编译器依赖且不能替换的许多“帮助”函数。
从 C 继承的 17 个标准头文件(<stdlib.h>、<stdio.h>、<string.h> 等)与 Solaris 操作系统和 Solaris 基本运行时库 libc 紧密相关,不能可靠替换。这些头文件的 C++ 版本(<cstdlib>、<cstdio>、<cstring> 等)与基本 C 版本紧密相关,不能可靠替换。
要安装替换库,必须先确定替换头文件的位置和 libCstd 的替换库。为方便讨论,假定头文件放置在 /opt/mycstd/include 中,库放置在 /opt/mycstd/lib 中。假定库称为 libmyCstd.a。(库名最好以 "lib" 开头。)
每次编译时,都使用 -I 选项指向头文件的安装位置。此外,还使用 -library=no%Cstd 选项防止查找编译器自身版本的 libCstd 头文件。例如:
example% CC -I/opt/mycstd/include -library=no%Cstd... (compile) |
编译期间,-library=no%Cstd 选项防止搜索编译器自身版本的这些头文件所在的目录。
每次执行程序或库链接时,都使用 -library=no%Cstd 选项防止查找编译器自身的 libCstd,使用 -L 选项指向替换库所在的目录,以及使用 -l 选项指定替换库。示例:
example% CC -library=no%Cstd -L/opt/mycstd/lib -lmyCstd... (link) |
也可以直接使用库的完整路径名,而不使用 -L 和 -l 选项。例如:
example% CC -library=no%Cstd /opt/mycstd/lib/libmyCstd.a... (link) |
链接期间,-library=no%Cstd 选项防止链接编译器自身版本的 libCstd。
C 有 17 个标准头文件(<stdio.h>、<string.h>、<stdlib.h> 等)。这些头文件以 Solaris 操作系统的一部分提供,位于 /usr/include 目录中。C++ 也有这些头文件,但另外要求在全局名称空间和 std 名称空间中都有各种声明的名称。在 Solaris 操作系统版本 8 之前的版本中,C++ 编译器提供了自身版本的这些头文件而不是替换 /usr/include 目录中的头文件。
C++ 也有另一个版本的各个 C 标准头文件(<cstdio>、<cstring> 和 <cstdlib> 等),仅名称空间 std 中有各种声明的名称。最后,C++ 添加了 32 个自己的标准头文件(<string>、<utility>、<iostream> 等)。
标准头文件的明显实现将 C++ 源码中找到的名称用作包括的文本文件的名称。例如,标准头文件 <string>(或 <string.h>)可能指某目录中名为 string(或 string.h)的文件。这种明显实现有以下缺点:
如果具有名为 string 的目录或可执行程序,可能会错误地找到该目录或程序而不是标准头文件。
在 Solaris 8 操作系统之前的 Solaris 操作系统版本上,启用了 .KEEP_STATE 时,makefile 的缺省依赖性会导致尝试将标准头文件替换为可执行程序。(没有后缀的文件缺省假定为要生成的程序。)
为了解决这些问题,编译器 include 目录会包含一个与头文件同名的文件和一个指向它且具有唯一后缀 .SUNWCCh (SUNW 是所有编译器相关软件包的前缀,CC 指 C++ 编译器,h 是常用的头文件后缀)的符号链接。指定 <string> 后,编译器将其重写为 <string.SUNWCCh> 并搜索该名称。后缀名只能在编译器自己的 include 目录中找到。如果这样找到的文件是符号链接(正常情况下),编译器就对链接进行一次引用解除,并将结果(此例中是 string)用作错误消息和调试器引用的文件名。忽略文件的依赖性信息时,编译器使用带后缀的名称。
仅当出现在尖括号中且无需指定任何路径时,17 种标准 C 头文件和 32 种标准 C++ 头文件的两种格式才会发生名称重写。如果使用引号来代替尖括号指定任何路径组件或其他某些头文件,就不会有重写发生。
下表说明了通常的情况。
表 12–3 头文件搜索示例
源代码 |
编译器搜索 |
注释 |
---|---|---|
<string> |
string.SUNWCCh |
C++ 字符串模板 |
<cstring> |
cstring.SUNWCCh |
C string.h 的 C++ 版本 |
<string.h> |
string.h.SUNWCCh |
C string.h |
<fcntl.h> |
fcntl.h |
不是标准 C 或 C++ 头文件 |
"string" |
string |
双引号,不是尖括号 |
<../string> |
../string |
指定的路径 |
如果编译器未找到 header.SUNWCCh,则编译器将重新搜索 #include 指令中提供的名称。例如,如果使用指令 #include <string>,编译器就尝试查找名为 string.SUNWCCh 的文件。如果搜索失败,编译器就查找名为 string 的文件。
由于12.7.5 标准头文件实现中介绍的搜索算法,您无需提供12.7.3 安装替换库中介绍的 SUNWCCh 版本的替换头文件。但是会遇到某些上文所述的问题。如果这样,建议为每个无后缀的头文件添加后缀为 .SUNWCCh 的符号链接。也就是说,对于文件 utility,可以运行命令
example% ln -s utility utility.SUNWCCh |
编译器第一次查找 utility.SUNWCCh 时,会找到它,而不会和其他名为 utility 的文件或目录混淆。
不支持替换标准 C 头文件。如果仍然希望提供标准头文件的自己的版本,那么建议按以下步骤操作:
将所有替换头文件放置在一个目录中。
在该目录中创建指向每个替换头文件的 .SUNWCCh 符号链接。
在每次调用编译器时使用 -I 指令,搜索包含替换头文件的目录。
例如,假设有 <stdio.h> 和 <cstdio> 的替换。请将文件 stdio.h 和 cstdio 放在目录 /myproject/myhdr 中。在该目录中,运行如下命令:
example% ln -s stdio.h stdio.h.SUNWCCh example% ln -s cstdio cstdio.SUNWCCh |
每次编译时使用 -I/myproject/mydir 选项。
如果要替换任何 C 头文件,就必须成对替换。例如,如果替换 <time.h>,还应该替换 <ctime>。
替换头文件必须与被替换版本具有相同的效果。也就是说,各种运行时库(如 libCrun、libC、libCstd、libc 和 librwtool)是使用标准头文件中的定义生成的。如果替换文件不匹配,那么程序不能工作。