Oracle Solaris Studio 12.2:C++ 用户指南

第 11 章 使用库

库提供了在多个应用程序间共享代码的方法,也提供了减小超大型应用程序复杂度的方法。C++ 编译器使您可以访问各种库。本章说明了如何使用这些库。

11.1 C 库

Oracle Solaris 操作系统附带了安装在 /usr/lib 中的几个库。这些库大多有 C 接口。缺省情况下,其中的 libclibm 库通过 CC 驱动程序进行链接。如果使用 –mt 选项,则链接 libthread 库。如果要链接其他系统库,请在链接时使用适当的 –l 选项。例如,要链接 libdemangle 库,请在链接时在 CC 命令行上传递 –ldemangle


example% CC text.c -ldemangle

C++ 编译器具有自己的运行时支持库。所有 C++ 应用程序都由 CC 驱动程序链接到这些库。C++ 编译器还具有其他一些有用的库,如下节所述。

11.2 随 C++ 编译器提供的库

C++ 编译器附带了一些库。其中一些只能在兼容模式 (-compat=4) 下使用,有些只能在标准模式 (–compat=5) 下使用,有些可以在这两种模式下使用。libgclibdemangle 库都有 C 接口,可以在任何模式下链接到应用程序。

下表列出了随 C++ 编译器提供的库,以及可以使用这些库的模式。

表 11–1 C++ 编译器附带的库

库 

说明 

可用模式 

libstlport

标准库的 STLport 实现。 

–compat=5

libstlport_dbg

调试模式的 STLport 库 

–compat=5

libCrun

C++ 运行时 

–compat=5

libCstd

C++ 标准库 

–compat=5

libiostream

传统 iostream

–compat=5

libC

C++ 运行时,传统 iostream

–compat=4

libcsunimath

支持 -xia 选项

–compat=5

libcomplex

复数库 

–compat=4

librwtool

Tools.h++ 7

–compat=4– compat=5

librwtool_dbg

支持调试的 Tools.h++ 7

–compat=4、–compat=5

libgc

垃圾收集 

C 接口 

libdemangle

还原 

C 接口 


注 –

请勿重新定义或修改用于 STLport、Rogue Wave 或 Solaris Studio C++ 库的任何配置宏。库是按照适用于 C++ 编译器的方式进行配置和生成的。libCstd 和 Tool.h++ 配置为可互操作,因此,修改配置宏会导致程序不能编译、不能链接或不能正常运行。


11.2.1 C++ 库描述

以下是这些库中每个库的简单描述。

11.2.2 访问 C++ 库的手册页

与本节所述库关联的手册页位于第 1、3、3C++ 和 3cc4 节中。

要访问 C++ 库的手册页,请输入:


example% man library-name

要访问 C++ 库版本 4.2 的手册页,请输入:


example% man -s 3CC4 library-name

11.2.3 缺省 C++ 库

缺省情况下,CC 驱动程序会链接其中一些 C++ 库,而其他库需要显式链接。在标准模式下,CC 驱动程序缺省链接下列库:

-lCstd -lCrun -lm -lc

在兼容模式 (-compat) 下,缺省链接下列库:

-lC -lm -lc

有关更多信息,请参见A.2.49 -library=l[ ,l...]

11.3 相关的库选项

CC 驱动程序提供了一些选项来帮助用户使用库。


example% CC test.cc -library=rwtools7,iostream

example% CC test.cc -library=gc -staticlib=gc

example% CC test.cc -compat=4 -staticlib=libC

example% CC test.cc -library=no%Crun,no%Cstd

缺省情况下,CC 根据命令行选项链接不同的系统库集合。如果指定 -xnolib(或 -nolibCC 仅链接在命令行上使用 -l 选项显式指定的那些库。(如果使用 -xnolib-nolib,会忽略 -library 选项(如果有)。)

使用 –R 选项可以在可执行文件中生成动态库搜索路径。执行期间,运行时链接程序使用这些路径搜索应用程序所需的共享库。缺省情况下,CC 驱动程序将 – R<install_directory>/lib 传递给 ld(如果编译器安装在标准位置中)。可以使用 -norunpath 禁止在可执行文件中生成共享库的缺省路径。

缺省情况下,链接程序会搜索 /lib/usr/lib。请勿在 -L 选项中指定这些目录或任何编译器安装目录。

对于针对部署生成的程序,应该使用 -norunpath-R 选项进行生成,这样可避免在编译器目录中查找库。(请参见11.6 使用共享库)。

11.4 使用类库

通常,使用类库分两个步骤:

  1. 在源码中包括适当的头文件。

  2. 将程序与目标库链接。

11.4.1 iostream

C++ 编译器提供两种 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

有关编译模式的完整讨论,请参见《C++ 迁移指南》。

11.4.2 complex

标准库提供了模板化的 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)

关于使用复数运算库的更多信息,请参见表 13–4

11.4.3 链接 C++ 库

下表列出了链接 C++ 库的编译器选项。有关更多信息,请参见A.2.49 -library=l[ ,l...]

表 11–2 链接 C++ 库的编译器选项

库 

编译模式 

选项  

传统 iostream

–compat=4

–compat=5

不需要 

-library=iostream

complex

–compat=4

-compat=5

-library=complex

不需要 

Tools.h++ 版本 7

–compat=4

–compat=5

-library=rwtools7

-library=rwtools7,iostream

-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

Apache stdcxx 版本 4

-compat=5

-library=stdcxx4

11.5 静态链接标准库

CC 驱动程序在缺省情况下链接几个库的共享版本(包括 libclibm),这通过为每个缺省库将 -llib 选项传递给链接程序来实现。(有关兼容模式和标准模式下的缺省库列表,请参见11.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 以及如何动态链接 libmlibc


example% CC test.c -xnolib -lCstd -Bstatic -lCrun– Bdynamic -lm -lc

-l 选项的顺序很重要。– lCstd– lCrun-lm 选项位于 -lc 之前。


注 –

建议不要静态链接 libCrunlibCstd。而是生成 /usr/lib 中的动态版本以与其所安装在的 Solaris 版本一起使用。


有些 CC 选项链接到其他库。也可以使用 -xnolib 抑制这些库链接。例如,使用 -mt 选项会导致 CC 驱动程序将 -lthread 传递给 ld。但如果同时使用 –mt–xnolibCC 驱动程序不会将 -lthread 传递给 ld。有关更多信息,请参见A.2.153 –xnolib。有关 ld 的更多信息,请参见《链接程序和库指南》。


注 –

/lib/usr/lib 中静态版本的 Solaris 库不再可用。例如,试图静态链接 libc 的操作将失败:


      CC hello.cc -xnolib -lCrun -lCstd -Bstatic -lc 

11.6 使用共享库

C++ 编译器附带下列 C++ 运行时共享库:

在 Linux 上,C++ 编译器附带这些附加库:

在 Solaris 10 上,这些附加库以及其他一些库作为 Solaris C++ 运行时库软件包 SUNWlibC 的一部分安装。

如果应用程序使用 C++ 编译器附带的任何共享库,则 CC 驱动程序会安排运行路径(请参阅 -R 选项),该运行路径指向将在可执行文件中生成库的位置。如果之后将可执行文件部署到另一台计算机上,而该计算机上并没有在同一位置安装同一编译器版本,将找不到所需的共享库。

在程序启动时,可能根本找不到此库,或可能使用错误版本的库,从而导致错误的程序行为。在这种情况下,应该将所需库与可执行文件一起提供,并使用指向这些库将要安装的位置的运行路径进行生成。

Using and Redistributing Solaris Studio Libraries in an Application》(《在应用程序中使用与重新分发 Solaris Studio 库》一文中详细讨论了该主题并提供了示例,请参见 http://developers.sun.com/sunstudio/documentation/techart/stdlibdistr.html

11.7 替换 C++ 标准库

替换与编译器一起发布的标准库是有风险的,不能保证产生预期的结果。基本操作是禁用编译器提供的标准头文件和库,指定找到新的头文件和库(及库本身的名称)的目录。

编译器支持标准库的 STLport 和 Apache stdcxx 实现。有关更多信息,请参见12.3 STLport12.4 Apache stdcxx 标准库

11.7.1 可以替换的内容

可以替换大多数标准库及其关联头文件。替换的库是 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

11.7.2 不可替换的内容

标准头文件 <exception><new><typeinfo> 与编译器本身以及 libCrun 紧密相关,不能可靠替换。库 libCrun 包含了编译器依赖且不能替换的许多“帮助”函数。

从 C 继承的 17 个标准头文件(<stdlib.h><stdio.h><string.h> 等)与 Solaris 操作系统和 Solaris 基本运行时库 libc 紧密相关,不能可靠替换。这些头文件的 C++ 版本(<cstdlib><cstdio><cstring> 等)与基本 C 版本紧密相关,不能可靠替换。

11.7.3 安装替换库

要安装替换库,必须先确定替换头文件的位置和 libCstd 的替换库。为方便讨论,假定头文件放置在 /opt/mycstd/include 中,库放置在 /opt/mycstd/lib 中。假定库称为 libmyCstd.a。(库名最好以 "lib" 开头。)

11.7.4 使用替换库

每次编译时,都使用 -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

11.7.5 标准头文件实现

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)的文件。这种明显实现有以下缺点:

为了解决这些问题,编译器 include 目录会包含一个与头文件同名的文件和一个指向它且具有唯一后缀 .SUNWCCh SUNW 是所有编译器相关软件包的前缀,CC 指 C++ 编译器,h 是常用的头文件后缀)的符号链接。指定 <string> 后,编译器将其重写为 <string.SUNWCCh> 并搜索该名称。后缀名只能在编译器自己的 include 目录中找到。如果这样找到的文件是符号链接(正常情况下),编译器就对链接进行一次引用解除,并将结果(此例中是 string)用作错误消息和调试器引用的文件名。忽略文件的依赖性信息时,编译器使用带后缀的名称。

仅当出现在尖括号中且无需指定任何路径时,17 种标准 C 头文件和 32 种标准 C++ 头文件的两种格式才会发生名称重写。如果使用引号来代替尖括号指定任何路径组件或其他某些头文件,就不会有重写发生。

下表说明了通常的情况。

表 11–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 的文件。

11.7.5.1 替换标准 C++ 头文件

由于11.7.5 标准头文件实现中介绍的搜索算法,您无需提供11.7.3 安装替换库中介绍的 SUNWCCh 版本的替换头文件。但是会遇到某些上文所述的问题。如果这样,建议为每个无后缀的头文件添加后缀为 .SUNWCCh 的符号链接。也就是说,对于文件 utility,可以运行命令


example% ln -s utility utility.SUNWCCh

编译器第一次查找 utility.SUNWCCh 时,会找到它,而不会和其他名为 utility 的文件或目录混淆。

11.7.5.2 替换标准 C 头文件

不支持替换标准 C 头文件。如果仍然希望提供标准头文件的自己的版本,那么建议按以下步骤操作:

例如,假设有 <stdio.h><cstdio> 的替换。请将文件 stdio.hcstdio 放在目录 /myproject/myhdr 中。在该目录中,运行如下命令:


example% ln -s stdio.h stdio.h.SUNWCCh
example% ln -s cstdio cstdio.SUNWCCh

每次编译时使用 -I/myproject/mydir 选项。

忠告: