aix中使用xlc编译生成动态链接库(shared object)(.so)文件的方法

时间:2022-04-17 06:53:54
今天写一个ppt的时候,忽然发现不会用xlc编译成出.so文件,于是baidu,未果。
后cc看了一些命令的选项后,查到了编译的选项 。
假设我有hellofirst.c和hellosecond.c两个.c文件
使用命令
cc-qmkshrobj -o libhello.so hellofirst.c hellosecond.c

即可生成动态链接库libhello.so


aix下编译动态库的例子:
cc -bnoentry -G -o libwel.so wel.c -lc
调用动态库的程序:
cc -bdynamic -brtl -o open open.c -L. -lwel -ldl

用nm看看能不能看到so里面的符号。如果有,说明有可能是环境变量的问题。


cc-qmkshrobj -o libhello.so hellofirst.c hellosecond.c


部分内容转自[http://www.360doc.com/content/10/1213/22/4947005_77867631.shtml]
函数说明:
1.  打开动态链接库:
    #include <dlfcn.h>
    void *dlopen(const char *filename, int flag);
    该函数返回操作句柄,如:
    void *pHandle = dlopen(strSoFilePath, RTLD_LAZY);
flag:
   RTLD_LAZY: 暂缓决定,等有需要时再解出符号  
   RTLD_NOW :立即决定,返回前解出所有未决定的符号。  
   RTLD_LOCAL :默认的,如果既没有标志指定 。在这个库中定义的符号不是可用来解决在随  后加载的 库的引用。 
   RTLD_GLOBAL :允许导出符号,这个库中定义的符号将用于随后加载的库符号解析。

2.  取动态对象地址:
    #include <dlfcn.h>
    void *dlsym(void *pHandle, char *symbol);
    dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。
    使用这个函数不但可以获取函数地址,也可以获取变量地址。比如,假设在so中
    定义了一个void mytest()函数,那在使用so时先声明一个函数指针:
    void (*pMytest)(),然后使用dlsym函数将函数指针pMytest指向mytest函数,
    pMytest = (void (*)())dlsym(pHandle, "mytest");

3.  关闭动态链接库:
    #include <dlfcn.h>
    int dlclose(void *handle);
    该函数将该.so的引用计数减一,当引用计数为0时,将它从系统中卸载。

4.  动态库错误函数:
    #include <dlfcn.h>
    const char *dlerror(void);
    当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时
    表示没有错误信息。

示例:
1.动态库代码 myFunc.cpp

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. extern "C"  
  4. int myAdd(int a, int b)  
  5. {  
  6.     printf("func called.\n");  
  7.   
  8.     return a+b;  
  9. }  
xlc编译命令:

xlc -q64 -o libmyFunc.o -c myFunc.cpp

xlc -q64 -qmkshrobj -o libmyFunc.so libmyFunc.o

2.源程序代码 myTest.cpp

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <dlfcn.h>  
  3.   
  4. int main()  
  5. {  
  6.     printf("main begin.\n");  
  7.       
  8.     void *handle;  
  9.     int (*myAdd)(intint);  
  10.     char *error;  
  11.   
  12.   
  13.     handle = dlopen ("./libmyFunc.so", RTLD_LAZY);  
  14.   
  15.     if (!handle)   
  16.     {  
  17.         printf ("dlopen fail :%s\n", dlerror());  
  18.   
  19.         return 1;  
  20.     }  
  21.   
  22.   
  23.     myAdd = (int (*)(intint))dlsym(handle, "myAdd");  
  24.   
  25.     if ((error = dlerror()) != NULL)   
  26.     {  
  27.         printf ("dlsym fail :%s\n", error);  
  28.   
  29.         return 1;  
  30.     }  
  31.   
  32.     int temp = myAdd(3,4);  
  33.       
  34.     printf("temp = [%d]\n", temp);  
  35.   
  36.     dlclose(handle);  
  37.   
  38.     return 0;  
  39.   
  40. }  

xlc编译命令:

xlc -q64 -brtl -o myTest myTest.cpp

3.执行
./myTest

4.输出
main begin.
func called.
temp = [7]

总结:

1.动态库名最好为libxxx.so
2.动态库中函数需要声明为extern "C"
3.编译主应用程序时需要加-brtl



http://www.ibm.com/developerworks/cn/linux/l-pow-gnu-vacpp.html


简介

XL C/C++ Advanced Edition for Linux 是基于标准的命令行编译器,用于在基于 POWER 处理器的系统上运行的 Linux。它是 VisualAge® C++ V6.0 for Linux 的后续版本。XL C/C++ 不仅使用 IBM POWER、POWER3™ 和 POWER4™ 的功能,而且还添加了对新的 POWER5™ 和 POWER 970 处理器的支持。本文介绍了 XL C/C++ V7.0 for Linux 编译器中添加的新功能并着重讲述了 GCC 和 XL C/C++ 之间的各种区别。

在本文中,我们用 XL C/C++ 表示 IBM XL C/C++ V7.0 for Linux。术语 Linux on POWER 是指在基于 IBM POWER 处理器的系统上运行的 Linux 操作系统。

本文要说明的主题包括:

  1. 版本 7.0 中的新功能。
  2. 如何设置 XL C/C++ 的编译环境。
  3. 优化选项。
  4. 检查对 GNU gcc 和 gcc-c++ 扩展的依赖。
  5. 32/64 位编译器模式。
  6. 模板实例化。
  7. 运行时链接。
  8. XL C/C++ 支持的 GCC 功能。
  9. 可重新分布的库。
  10. 链接顺序。
  11. 对运行时错误的诊断。

XL C/C++ 提供了大量为 POWER Architecture 量身定做的优化选项,其中包括POWER5 和 POWER 970 处理器。在许多情况下,对于 POWER 基于处理器的系统,使用 XL C/C++ 构建的应用程序显示了比使用 GCC on Linux 构建的那些应用程序更显著的性能提高。如果您想充分利用 POWER Architecture 的潜能,我们建议您使用 XL C/C++。

XL C/C++ for Linux 现在可以在 SUSE Linux Enterprise Server 9 for POWER (SLES 9) 和 Red Hat Enterprise Linux AS V3 (RHEL 3) Update 3 上使用。在 IBM XL C/C++ Advanced Edition for Linux 站点中,可以发现更多信息。

XL C/C++ 概述

XL C/C++ 是 Linux on POWER 的优化的、基于标准的命令行编译器。可以将 XL C/C++ 用作后缀为 .c(小写 c)的文件的 C 编译器,或用作后缀为 .C(大写 C)、.cc、.cpp 或 .cxx 的文件的 C++ 编译器。XL C/C++ 支持 C 的两种 ISO 编程语言规范:C89 和 C99。该编译器还支持两种 C++ 标准:Standard C++ 和 C++98。另外,编译器还支持许多语言扩展,包括 GNU gcc 和 gcc-c++ 语言扩展的子集。

XL C/C++ 创建二进制或对象文件,这些文件与由 GCC 生成的文件相兼容。为了获得这种兼容性,在同一系统上,使用 XL C/C++ 编译的程序与 GCC 使用的那些程序包含相同的头文件。XL C/C++ 使用 GNU gcc 和 gcc-c++ 头文件,生成的应用程序与通过 GCC 提供的 C 和 C++ 运行时库链接。因此,应用程序的一部分可以使用 XL C/C++ 构建获得优化,然后将其与使用 GCC 构建的那部分组合来生成应用程序,该应用程序运行性能就好像是由 GCC 或 XL C/C++ 单独构建的。Linux on POWER 的 XL C/C++ 和 GCC 之间的关系可以概括如下:

  1. 编译使用 Linux 分布的 GNU gcc 和 gcc-c++ 头文件。
  2. 编译使用 GUN 汇编程序。
  3. 链接使用 GUN 链接程序。
  4. 编译的程序使用 GNU gcc 和 gcc-c++ 运行时库。
  5. 调试使用 GNU 编译器,gdb。
  6. POWER 处理器的 IBM 内置功能与 GNU gcc/gcc-c++ 内置功能共存。

版本 7 中的新功能

这一节将重点介绍 XL C/C++ for Linux 新增功能中的一小部分。有关新功能的完整列表,请参阅安装 XL C/C++ 时提供的 Getting Started with XL C/C++

性能与优化

  1. 对选项 -qarch 和 -qtune 的优化。把对 POWER5 和 POWER 970 架构的支持添加到选项 -qarch 和 -qtune 中。 

    例如: 

    -qarch=pwr5, -qarch=ppc970, -qtune=pwr5, -qtune=ppc970
  2. 通过 –qaltivec(仅 POWER 970)和 –qenablevmx 支持 Vector Multimedia Extensions (VMX)。
  3. 随编译器提供了 IBM Mathematics Acceleration Subsystem (MASS) 向量库。向量库是线程安全的,通过相应的 libm 例程提供改善的性能。

符合行业标准

  1. 对于 C、C++ 和 Fortran,XL C/C++ 支持 OpenMP API V2.0。
  2. 在版本 7 中,用 XL C/C++ 实现了更多的 GNU gcc 和 gcc++ 扩展。(有关的完整列表,请参见 Getting Started with XL C/C++ 中的表。)
  3. 增强的 Unicode 和 NLS 支持。添加了新数据类型以支持 UTF-16 和 UTF-32。

新功能

  1. gxlc 和 gxlc++ Utilities。它们是一些调用方法,将 GNU gcc 或 gcc-c++ 调用命令转换为相应 xlc 或 xlc++ 命令以调用 XL C/C++ 编译器。

    要使用 gcc –ansi 选项来编译 Hello World 程序的 C 版本,可以使用:

    gxlc -ansi hello.c


    其转换为:

    xlc –F:c89 hello.c

    然后使用此命令来调用 XL C 编译器。

    gxlc 和 gxlc++ 有助于最大程度地减少对使用 GNU 编译器构建的现有应用程序的 makefile 的更改。它们支持 GCC 选项的主要部分,配置文件 gxlc.cfg 控制它们的操作。对于未转换的输入选项,gxlc 和 gxlc++ 将返回警告。虽然 gxlc 和 gxlc++ 方便了到 XL C/C++ 的转换,从而可以充分使用 XL C/C++ 的功能,但我们建议您使用 XL C/C++ 调用方法及其相关选项。

  2. XL C/C++ 将版本信息添加到创建的模板注册文件中。编译器在内部使用这条信息来跟踪应该使用的模板注册文件格式的版本。
  3. 为编译器调用命令和每个命令行实用程序都提供了手册页。

编译器模式

XL C/C++ 的默认位置是 /opt/ibmcmp。XL C/C++ 包含各种调用命令。每个命令都有相应的线程安全版本。构建多线程应用程序时,要使用线程安全版本(除了 gxlc 和 gxlc++)。下表显示了可用调用命令。

表 1. 可用调用命令
调用命令 线程安全变量 描述
xlC 或 xlc++ xlC_r 或 xlc++_r 源文件作为 C++ 代码进行编译
xlc xlc_r 源文件作为 C 代码进行编译。该模式包含下列编译器选项: -qlanglvl=extc89、 -qalias=ansi、 -qcpluscmt、 -qkeyword=inline
c89 c89_r 编译器执行 ISO C89 标准。此调用包含下列编译器选项: -qlanglvl=stdc89-qalias=ansi、 -qstrict_induction、 -qnolonglong、 -D_ANSI_C_SOURCE、 -D__STRICT_ANSI__
c99 c99_r 编译器执行 ISO C99 标准。此调用包含下列编译器选项: -qlanglvl=stdc99、 -qalias=ansi、 -qstrict_induction、 -D_ANSI_C_SOURCE、 -D_ISOC99_SOURCE、 -D__STRICT_ANSI__
cc cc_r 用于不需要遵守 C89 和 C99 的遗留 C 代码。此调用包含下列编译器选项: -qlanglvl=extended、 -qnoro、 -qnoroconst
xlCcore 或 xlc++core XlCcore_r 或 xlc++core_r 与 xlC 和 xlc++ 相同,但是编译器将仅链接到运行时库的内核。如果想将应用程序链接到其他运行时库,而不是链接到随 XL C/C++ 一起提供的运行时库,那么可以使用这个调用
gxlc 或 gxlc++   转换方法,该方法将 GNU gcc 或 gcc-c++ 调用命令转换为相应 xlC 或 xlc++ 命令并调用 XL C/C++ 编译器

在大多数情况下,应该使用 xlC 命令来编译 C++ 源文件,使用 xlc 命令来编译 C 源文件。如果既拥有 C 文件又拥有 C++ 对象文件,那么可以使用 xlC 进行链接。注意,在 VisualAge V6.0 中,调用 xlc 意味着使用的是选项 -qlanglvl=stdc89,而不是在 XL C/C++ V7.0 中的 -qlanglvl=extc89

XL C/C++ 文档

安装 XL C/C++ 时提供下列 PDF 文档:

  1. XL C/C++ for Linux Getting Started (getstart.pdf)。
  2. XL C/C++ for Linux Installation Guide (install.pdf) 包含有关安装编译器和启用手册页的说明。
  3. XL C/C++ for Linux C/C++ Language Reference (language.pdf) 包含关于 IBM 支持的 C 和 C++ 语言的信息。
  4. XL C/C++ for Linux Compiler Reference (compiler.pdf) 包含关于各种编译器选项、编译指令、宏和内置函数信息,这些信息包括那些用于并行处理的信息。
  5. XL C/C++ for Linux Programming Guide (proguide.pdf) 包含其他出版物中尚未涉及的关于使用 XL C/C++ 编程的信息。

在下列位置可以找到这些文档:

  1. 安装 CD 的 /docs/LANG/pdf 目录,其中 LANG 表示语言和位置代码。
  2. 安装编译器后的 /opt/ibmcmp/vacpp/7.0/doc/LANG/pdf 目录。

产品文档的 HTML 版本安装在 /opt/ibmcmp/vacpp/7.0/doc/LANG/html 目录。在这个目录中打开 index.html 文件可以查看 HTML 文件。

安装和配置 XL C/C++

为了获得与 GNU gcc 和 gcc-c++ 编译器的二进制兼容,必须首先安装下列包:

表 2. RHEL3
GCC 先决条件 版本要求
gcc 3.2.3
gcc-c++ 3.2.3
glibc-devel(32 和 64 位) 2.3.2
libstdc++-devel(32 和 64 位) 3.2.3
表 3. SLES 9
GCC 先决条件 版本要求
gcc 3.3.3
gcc-c++ 3.3.3
gcc-64bit 9
glibc-devel-64 bit 9
libstdc++-devel-64 bit) 9

SLES 9 还需要 java2 和 java2-jre 包版本 1.3.1。

有关安装编译器的详细信息,请参阅 XL C/C++ for Linux Installation Guide

安装 XL C/C++ 后,我们建议您在开始使用编译器之前,先运行名为 new_install 的工具(默认情况下,这个工具位于 /opt/ibmcmp/vac/7.0/bin)。然后,这个工具会执行 vac_configure 脚本并创建适当的配置文件。

配置文件保存 XL C/C++ 应该使用的 32 位和 64 位 GCC 编译器的位置。该文件是必需的,因为系统中可能会安装多个 GCC,XL C/C++ 需要知道应该使用哪个 GCC。XL C/C++ 提供名为 vac_configure 的实用程序(默认情况下,该程序位于 /opt/ibmcmp/vac/7.0/bin),帮助创建和更新配置文件。默认配置文件是 /etc/opt/ibmcmp/vac/7.0/vac.cfg。 XL C/C++ Compiler Reference 文档中有 vac_configure 的语法。

还可以使用下列编译器选项指定标准包含路径:

表 4. 编译器选项
选项名称 描述
-qgcc_c_stdinc=<paths> 指定 GNU gcc 头文件的新目录搜索路径
-qgcc_cpp_stdinc=<paths> 指定 GNU gcc-c++ 头文件的新目录搜索路径
-qc_stdinc= 指定 IBM C 头文件的新目录搜索路径
-qcpp_stdinc=<paths> 指定 IBM C++ 头文件的新目录搜索路径

XL C/C++ 中的优化选项

XL C/C++ 提供了适合 IBM 硬件的优化选项组合。在许多情况下,对于 Linux on POWER,使用 XL C/C++ 编译的应用程序显示了比那些使用 GCC 编译的应用程序更显著的性能提高。应该注意的是,对于所有应用程序,并不是所有优化都是有利的。通常必须在编译器进行的优化与编译时间增加(伴随着调试能力减低)的程度之间进行平衡。

优化级别

优化级别由编译器选项指定。下表汇总了每一优化级别上的编译器行为。

表 5. 编译器行为
选项 行为
-qnoopt 快速编译,完全调试支持
-O2(与 -O 相同) 执行编译器开发人员认为是编译速度和运行时性能最佳组合的优化。如果没有使用 -qnostrict_induction 或 -qnostrict 明确否定,那么这个设置中将包含 -qstrict 和 –qstrict_induction
-O3 执行内存占用大、编译时间长或两者都有的其他优化。当运行时改善比最大程度地减少编译资源使用重要时,建议使用这些优化
-O4 和 -O5 执行过程间优化、循环优化和自动计算机调整

特定处理器架构的优化

目标计算机选项是指示编译器为给定微处理器或架构系列上的最佳执行生成代码的那些选项。您可以通过优化,来满足目标处理器、给定处理器架构系列内的一系列处理器或特定处理器的最大范围的可能选择。下列选项将控制影响目标计算机的单独某些方面的优化。

表 6. 优化选项
选项 行为
-qarch 选择应该为其生成指令代码的处理器架构系列。默认值是 -qarch=ppc64grsq。还可以使用以下子选项: autopwr3、 pwr4、 pwr5、 ppc970、 ppc64、 ppcgr、 rs64b、 rs64c
-qtune 偏向于对给定微处理器上的执行操作进行优化,但这并不意味着将与指令集合架构有关的任何操作作为目标。Linux 上的默认值是 -qtune=pwr3。可用的子选项包括: auto、 pwr3、 pwr4、 pwr5、 ppc970、 rs64b、 rs64c
-qcache 定义特定缓存或内存几何。如果使用了 –qcache,则将 -qhot 或 -qsmp 与其一起使用
-qhot High-Order Transformations:该优化可以通过诸如交换、合并及展开等方法特别地提高循环性能。指定 -qhot 时,默认值为选项 -qhot=vector。尝试将 -qhot 与 -O2 和 -O3 一起使用。如果不可能存在转换,该选项的影响是中性的。
-qsmp 生成共享内存并行处理所需的线程代码。指定 -qsmp 时,默认值为选项 -qsmp=auto。如果在 OpenMP 程序中编译且不想进行自动并行化,则使用 -qsmp=omp:noauto。使用 -qsmp 时,总是使用 _r 编译器调用

为了最有效地使用目标计算机选项,应该尝试使用 –qarch 指定可能的最小计算机系列,它将很好地运行代码。尝试使用 –qtune 为实际上指定性能最好的地方。例如,如果仅 POWER5 系统中支持应用程序,则使用 -O3
-qarch=pwr5 -qtune=pwr5
。当系统具有可配置的 L2 或 L3 缓存选项时,或者当执行模式减少了缓存的共享级别的有效大小时(例如,POWER5 中的单片双核的 SMP 执行),修改缓存配置可能会有用。

POWER 平台支持其他平台上无法使用的机器指令。XL C/C++ 提供了一组内置函数,直接映射到特定 POWER 指令。通过使用这些函数,可以消除函数调用返回成本、参数传递、堆栈调整及所有与函数调用相关的其他成本。有关支持的内置函数的完整列表,请参阅 XL C/C++ C++ for Linux on pSeries Compiler Reference 文档。

检查对 GNU gcc 和 gcc-c++ 语言扩展的依赖

严格遵从 ISO 语言规范的应用程序将具有最大程度的可移植性。IBM XL C/C++ 支持一部分 GNU gcc 和 gcc-c++ 到 C 和 C++ 的扩展。可能需要重新看一下依赖不受支持的扩展的代码。如果使用了任何扩展,GCC 选项 –pedantic 会将引导它打印警告消息。 http://gcc.gnu.org 中有 GNU gcc/gcc-c++ 扩展的完整列表。

在 32 位和 64 位编译器模式之间切换

通过指定编译器选项 -q32 或 -q64,或通过设置环境变量 OBJECT_MODE,可以设置 XL C/C++ 生成 32 位或 64 位对象。 -q32 和 -q64 选项会覆盖 OBJECT_MODE 变量设置的值。如果没有指定 -q32 和 -q64,并且没有设置 OBJECT_MODE,那么编译器的默认模式为 32 位输出模式。在 64 位模式中,定义了 __64BIT__ 预处理器宏。

32 位和 64 位对象不能绑定在一起,所以需要确保全部在同一模式中编译所有对象。链接选项还必须反映要链接到的对象类型。如果具有 64 位对象,必须使用 64 位模式链接这些对象。

模板实例化

模板实例化是到 C++ 语言的扩展之一,GCC 和 XL C/C++ 对其进行不同处理。编译器和链接程序需要确保每个模板实例在可执行程序中确实仅出现一次。这一节先讨论 GCC 如何处理模板实例化,然后讨论 XL C/C++ 中的可用选项。

GCC 3.2 不支持模板储存库的概念,模板储存库是存储模板实例的自动维护的位置。然而,GCC 3.2 提供了下列选项:

-frepo
如果使用此选项,那么对于将模板实例化了的每个 .cc 文件,编译器将生成扩展名为 .rpo 的文件。这个 .rpo 文件包含相应对象文件中使用的模板实例化的清单。链接时,一些对象文件可能会重新编译和重新链接,以避免符号重复。
-fno-implicit-templates
使用这个选项,开发人员可以确定必须对哪些实例进行实例化。还有其他几个选项,如  -fexternal-templates 和  -falt-external-templates,但是 GCC 3.2 中不支持这些选项。

XL C/C++ 中可以使用下列编译器选项:

-qtempinc
使用这个选项,XL C/C++ 可以确定要实例化的模板代码,作为编译和链接过程的最后一步。这样做可以防止在最终的可执行程序或库中有重复的模板实例。

该选项要求以特定方式组织源代码。也就是说,模板的声明和定义必须在单独的文件中。模板定义需要位于与头文件相同的目录中,并且拥有相同名称,但是具有 .cc(小写字母 c)后缀。否则,头文件必须使用 #pragma
implementation("...")
 语句来标识相应的定义文件。例如,模板类 List 的声明和定义文件分别为 List.h 和 List.cc。在 List.h 文件中,必须包含语句 #pragma
implementation("List.cc")

如果没有使用 -qtempinc 指定目录,那么编译器将在当前目录中创建名为 tempinc 的目录,用它来保存将在模板中生成的信息。可以为这个目录选择自己的名称和位置,这样,当创建包含在不同目录中编译的对象文件的可执行程序时,可以使用相同目录。

例如:

xlC -c foo.cc -qtempinc=../mytemplates
cd ..
xlC -o app app.cc src/foo.o qtempinc=mytemplates

因为模板代码实际由编译器在链接时创建,所以当使用具有共享库的模板时(其中没有链接发生),就会出现问题。在 XL C/C++ Version 5 中,引入了选项 -qmkshrobj,当创建使用模板的共享对象时,该选项应该与 -qtempinc 一起使用。不使用 makeC++SharedLib 而使用这些选项的优点是:编译器将自动包含并编译 tempinc 目录中的模板实例化。

如果 XL C/C++ 检测到上述代码布局结构,那么它会自动启用 -qtempinc 选项。如果想阻止这项操作,自己手工对模板进行实例化,那么可以使用选项 -qnotempinc。还可以使用 #pragma define 指令强制执行实例化。例如, #pragma
define(List<long>);

-qtemplateregistry
如果不想更改代码布局或不想在头文件中添加 #pragma implementation 指令,那么可以使用此选项。它依赖于算法的先到先得类型。在编译单元对新的实例第一次进行实例化时,编译器将创建在个实例,并将记录保存在注册表文件中。可以在该选项中指定这个注册表文件的名称。默认情况下,在当前目录中创建名为 templreg 的文件。当另一编译单元引用上一编译单元中相同的实例化或使用相同的注册表文件时,不再需要对该实例进行实例化。因此,只需为整个程序生成一个副本即可。

-qtemplateregistry 和 -qtempinc 选项是互斥的。指定 -qtempinc 则意味着 -qnotemplateregistry。然而,指定 -qnotempinc 并不意味着 -qtemplateregistry

如果更改源代码,并且仅重新编译受影响的部分,那么 -qtemplaterecompile 选项将参考模板注册表,来确定是否对源文件进行更改需要重新编译其他编译单元。当将源文件更改为不再引用给定实例化及以前包含该实例化的相应对象文件时,需要执行这项操作。如果是这样,那么受影响的编译单元将自动重新编译。

如果需要的话,可以使用选项 -qnotemplaterecompile 禁用依赖单元的自动重新编译。从原始子目录移动对象文件的自动化构建过程就是这样的例子。

示例代码

下列示例代码说明了在 XL C/C++ 中如何处理 C++ 模板。

清单 1. 文件布局
-app/
| main.cc
|--- bar/
|--- bar.cc
|--- foo/
|--- foo.cc
|--- stack/
|--- stack.cc
|--- stack.h
清单 2. stack.h
stack.h
--------
#ifndef STACK_H
#define STACK_H
#ifdef TEMPINC
//This is needed when building with -qtempinc
#pragma implementation("stack.cc")
#endif
template <class T> class stack
{
private:
T* array ;
int top ;
int sz ;
public:
stack( int ) ;
~stack() ;
void push( T ) ;
T pop( );
};
#endif
清单 3. stack.cc
#include "stack.h"
#include<stdio.h>
template <class T> stack<T>::stack(int s)
{
array = new T[sz = s];
top = 0;
}
template <class T> stack<T>::~stack()
{
delete [] array;
}
template <class T> void stack<T>::push( T a )
{
if ( top >= sz )
{
printf( "Out of stack range, push failed\n");
}
else
{
array[top++] = a ;
}
}
template <class T> T stack<T>::pop()
{
if ( top <= 0 )
{
printf( "out of stack range, pop failed\n");
return 0;
}
else
{
T ret = array[--top];
return ret;
}
}
清单 4. bar.cc
#include "../stack/stack.h"
#include<stdio.h>
#ifdef REGISTRY
#include "../stack/stack.cc"
#endif
stack<int> barstack( 2 ) ;
void bar ()
{
barstack.push( 5 );
barstack.push( 6 );
int p = barstack.pop();
printf("Pop from barstack is %d\n", p);
}
清单 5. foo.cc
#include "../stack/stack.h"
#include<stdio.h>
#ifdef REGISTRY
#include "../stack/stack.cc"
#endif
stack<int> foostack( 2 );
void foo ()
{
foostack.push ( 11 );
foostack.push ( 12 );
int p = foostack.pop();
printf("Pop from foostack is %d\n", p);
}
清单 6. main.cc
extern void foo(void);
extern void bar(void);
main(){
foo();
bar();
}

下面是使用选项 -qtempinc 构建 main 的过程:

  1. cd stack/
  2. xlC -c stack.cc
  3. cd ../bar
  4. xlC -c bar.cc -DTEMPINC
    -qtempinc=../mytemp
  5. cd ../foo
  6. xlC -c foo.cc -DTEMPINC
    -qtempinc=../mytemp
  7. cd ..
  8. xlC -o main main.cc
    -qtempinc=mytemp stack/stack.o bar/bar.o foo/foo.o

注意, bar.cc、 foo.cc 和 main.cc 共享了名为 mytemp 的相同 "tempinc" 目录。因此,只需创建一个 stack<int> 实例即可。在 mytemp 目录下,有两个文件:stack.C 和 stack.o。stack.C 的内容如下所示:

清单 7. stack.c
/*1053113184*/#include "/home/chakarat/Template_va/foo/../stack/stack.h"
/*0000000000*/#include "/home/chakarat/Template_va/stack/stack.cc"
/*1053113184*/#include "/home/chakarat/Template_va/bar/../stack/stack.h"
template stack<int>::stack(int);
template stack<int>::~stack();
template void stack<int>::push(int);
template int stack<int>::pop();

如果不想在 stack.h 中添加 #pragma
implementation("stack.cc")
,那么可以使用选项 -qtemplateregistry。下面说明了如何使用这个选项:

  1. cd stack/
  2. xlC -c stack.cc
  3. cd ../bar
  4. xlC -c bar.cc -DREGISTRY
    -qtemplateregistry=../registry
  5. cd ../foo
  6. xlC -c foo.cc -DREGISTRY
    -qtemplateregistry=../registry
  7. cd ..
  8. xlC -o main main.cc
    -qtemplateregistry=registry stack/stack.o bar/bar.o foo/foo.o

有关 XL C/C++ 中的 C++ 模板的详细信息,请参阅 XL C/C++ for Linux Programming Guide

运行时链接

运行时链接是在已经开始执行程序之后分析尚未定义并且还没有延时的符号的能力。下面是用来构建名为 test 的可执行程序的 GCC 命令的顺序示例,这个可执行程序拥有共享库 libfoo.so 和 libbar.so。所有这些命令都能够用于运行时链接。

gcc -c foo.c
gcc -c bar.c
gcc -o libfoo.so foo.o -shared
gcc -o libbar.so bar.o -shared
gcc -o test test.c -L. -lfoo -lbar

要执行 test,那么环境变量 LD_LIBRARY_PATH 必须包含 libfoo.so 和 libbar.so 所在的目录。也可以使用选项 -Wl,-rpath,而不用向LD_LIBRARY_PATH 添加搜索位置。

在本例中,使用

gcc -o test test.c -L. -lfoo -lbar -Wl,-rpath=/home/app


其中 /home/app 是 libfoo.so 和 libbar.so 的位置。

对于 XL C/C++,必须用选项 -qmkshrobj 替代选项 -shared,如下所示:

xlc -c foo.c
xlc -c bar.c
xlc -o libfoo.so foo.o -qmkshrobj
xlc -o libbar.so bar.o -qmkshrobj
xlc -o test test.c -L. -lfoo -lbar

与 XL C/C++ on AIX 不同,使用 XL C/C++ on Linux 构建启用了运行时链接的可执行程序时,不需要选项 -brtl。这是因为 XL C/C++ on Linux 使用 GNU 链接程序,因此,还可以在 XL C/C++ on Linux 中使用选项 -Wl,-rpath。与 GCC 相似,要执行应用程序,必须设置环境变量LD_LIBRARY_PATH

XL C/C++ 支持的 GCC 功能

对于 Linux on POWER,从 GCC 移至 XL C/C++ 通常很简单。为了帮助执行此任务,XL C/C++ 提供了选项 -qinfo=por,帮助筛选发出的诊断消息,从而只显示与可移植问题有关的那些消息。另外,XL C/C++ 还支持 GNU 到 gcc 和 gcc-c++ 的一部分扩展。有关受支持的功能以及被接受的但忽略语义的那些功能的完整列表,请参阅 XL C/C++ C++ for Linux on pSeries Compiler Reference

要与 C 代码一起使用受支持的功能,则需要指定 -qlanglvl=extended 或 -qlanglvl=extc89。默认情况下,C++ 中所有受支持的 GNU gcc/gcc-c++ 功能都能被接受。

如本文“ 版本 7 中的新功能”一节所述, gxlc 和 gxlc++ 有助于最大程度地减少对使用 GNU 编译器构建的现有应用程序的 makefile 的更改。

可重新发布的库

XL C/C++ 提供下列可重新发布的库。根据应用程序,可能需要随应用程序一起提供这些库中的一个或多个。

libibmc++.so
仅由 C++ 程序使用。
libxlsmp.so、 libxlsmp_ser.so、 libxlsmpdebug.so
当  -qsmp 或  -qsmp=omp 选项有效时,需要使用这个库。

链接顺序

XL C/C++ 按下列顺序链接库:

  1. User .o 文件和库
  2. XL C/C++ C++ for Linux 库
  3. C++ 标准库
  4. C 标准库

在 XL C/C++ 的手册中,有关于链接顺序的详细信息。

运行时错误诊断

也许能够成功地编译和链接程序,但在执行过程中却生成意想不到的结果。这一节将描述了一些普遍错误、如何检测和更正这些错误。

未初始化变量

对象未隐式初始化,因此其初始值不确定。如果未设置就使用 auto 变量,那么它可能每次都产生不同的结果。 -qinfo=gen 指示编译器将所有自动变量初始化为指定的值。

运行时检查

–qcheck 的子选项指定检查空指针、超出数组范围的下标以及与零相除。建议只使用 –qcheck 选项进行调试,因为它会降低应用程序的运行时性能。

ANSI 别名

ANSI 别名规则表明指针只能解除对相同类型或可兼容类型的对象的引用。将指针转换为不兼容的类型,然后解除对该类型的引用的这种通用编码习惯违反了这条规则。设置 –qalias=noansi 可以更正程序行为。但是这样做会减少编译器优化应用程序的机会。建议更改程序,使之符合 ANSI 别名规则。

#pragma option_override

有时只在进行优化时才出现错误。这时可以关闭对已知会有特定编程错误的函数的优化,同时允许优化程序的其余部分。这条指令允许为特定函数指定备用优化选项。通过有选择地关闭复杂程序中每个函数的优化,它还可以用于确定引起问题的函数。

编译器选项

下表对 GCC 和 XL C/C++ 中常常用到的编译器选项进行了比较:

表 7. 常常用到的编译器选项
GCC XL C/C++ C/C++ 描述
-v -v、-V、-# 开启详细模式
-p/-profile -p 设置编译器生成的对象文件进行概要分析
n/a -q32、-q64 或设置 OBJECT_MODE 环境变量 创建 32 位或 64 位对象。GCC 64 位编译器位于 /opt/cross/bin 中
-fsyntax-only -qsyntaxonly 执行语法检查,不生成对象文件
-fpic -qpic=small 生成共享库中使用的 Position-Independent Code。在 XL C/C++ 中,Global Offset Table 的大小不超过 64 Kb。如果指定 –qpic,而无任何子选项,则假设 -qpic=small。如果指定了 -qmkshrobj 编译器选项,则启用 –qpic 选项
-fPIC -qpic=large 允许 Global Offset Table 大于 64 Kb
-pthread -qthreaded 或 _r 调用模式 创建在多线程环境中运行的程序
-fno-rtti -qnortti 对于异常处理和 typeid 和 dynamic_cast 操作符的使用,禁止生成运行时类型 –qrtti 识别(RTTI)。在 XL C/C++ 中,默认值为 -qnortti
-static -qstaticlink 使用这个选项生成的对象将无法与共享库进行链接
-static-libgcc -qstaticlink=libgcc 指示编译器与 libgcc 的静态版本链接
-shared -mkshrobj Instruct 编译器生成共享对象
-shared-libgcc -qnostaticlink=libgcc 指示编译器与 libgcc 的共享版本链接
-Wl、-rpath -Wl、-rpath 或 –R 传递用冒号分隔的目录列表,用它来指定运行时链接程序搜索的目录
-fno-implicit-templates、-frepo -qtempinc、-qtemplateregistry、-qtemplaterecompile 模板实例化
-w -w 取消警告消息
  -warn64 允许对长型到整型的截断舍位(long-to-integer truncation)进行检查
  -qinfo=<…> 生成信息消息
-fpack-struct -qalign=bit_packed 使用 bit_packed 排列规则
  -qalign=linuxppc 使用默认 GCC 排列规则来维护与 GCC 对象的兼容性。这个值是默认值
     
-O、-O2、-O3 -O、-O2、-O3、-O4、-O5 优化级别
  -qarch、-qtune、-qcache 特定处理器的优化选项

结束语

为了编译使用 XL C/C++ 为 GCC 编写的应用程序,有多种帮助促进迁移的方法。在编译阶段出现错误时,可以检查应用程序使用的任何 GCC 扩展,并使用前面介绍的运行时诊断技术解决运行时错误。另外,使用 XL C/C++ 提供的优化功能时,会提高应用程序的性能。

词汇

GNU Compiler Collection (GCC)
开源 GNU Compiler Set,其中包括 gcc、GNU C Compiler、gcc-c++、GNU C++ 编译器和 g77、GNU Fortran77 编译器。
i5 或 iSeries
运行 OS/400 和 Linux 的 IBM 集成服务器。
Linux on POWER
在 POWER 系统上运行的 Linux 操作系统。在本文中可以假设这个操作系统是指 IBM eServer pSeries(包括 eServer p5);eServer iSeries(包括 eServer i5);eServer OpenPower 和 eServer BladeCenter JS20 服务器。
OpenMP
OpenMP 是一种行业标准,它描述了包括 UNIX 和 Windows NT 平台在内的所有架构中,C、C++ 和 Fortran 中的对称多处理 (SMP) 编程的 API 的通用集合。有关 XL C/C++ 如何支持 OpenMP 规范的详细信息,请参阅  XL C/C++ for Linux Compiler Reference
POWER
由 IBM、Motorola 和 Apple 合作生成的基于 RISC 的芯片技术。基于 POWER 架构的 IBM 处理器示例包括 RS64 IV、POWER3、POWER4、POWER 970 和 POWER5。
p5 或 pSeries
运行 AIX 和/或 Linux 的 IBM 基于 UNIX 的服务器。
Red Hat Enterprise Linux AS 3 (RHEL 3)
Red Hat Enterprise Linux AS version 3。这是 Red Hat 最新的企业 Linux 产品。在本文中,RHEL 3 是指 RHEL 3 for POWER 架构。
SUSE LINUX Enterprise Server 9(SLES 9)
SUSE LINUX Enterprise Server version 9。这是 SUSE LINUX 最新的企业 Linux 产品。在本文中,SLES 9 是指 SLES 9 for POWER 架构。

感谢

作者对 Steve Dibbell、Linda Kinnunen 和 Linux Solutions Enablement 团队的帮助不胜感谢。