从 Solaris 向 Linux 移植应用程序的技术指导

移植概述

移植过程本身非常简单:

  • 清理代码和头文件,并删除与体系结构相关的部分和非标准做法。
  • 编译代码,并修正在编译过程中发现的问题。
  • 如果需要,则修正段故障及未对齐的访问。
  • 重新编译代码,如果需要,则重复上面的过程。

移植指导

移植 Solaris 应用程序至少需要两个平台:一个源平台和一个(或多个)Linux 目标平台。在将应用程序移植到 Linux 目标平台上运行时,您应该考虑很多因素:

  • 要移植到哪个 Linux 目标平台?举例来说,有很多种硬件平台都支持 Linux,而字节顺序是以目标系统(如大尾数和小尾数)为基础来决定的。要使用哪个 Linux 分发版和内核版本?(Red Hat、TurboLinux、Caldera、SuSE,还是其它的?) 
  • Linux 目标平台必须支持所有硬件需求吗?举例来说,是否要依赖第三方网卡?您是否需要支持网络和存储需求? 
  • Linux 目标平台上是否具备所有所需的第三方包(如类库)、中间件软件、应用程序服务器工具以及应用程序开发工具?目标平台是否支持这些产品的相同(或兼容)版本? 
  • 在移植到目标平台的过程中是否要作出某些改变?举例来说,应用程序是否要改为使用其它数据库系统? 
  • 32 位的 Solaris 应用程序是否需要移植到 64 位的 Linux 平台上? 
  • Solaris 应用程序是否利用亲和处理器集?Solaris 有内核 hook(一种库)和用于将进程分配到特定处理器集的命令行工具。而 Linux 中没有与此相当的东西。 
  • 是否需要单独的公共源代码库?举例来说,您是否需要支持多个平台? 
  • 理解应用程序体系结构将使移植过程容易一些。举例来说,它是客户机/服务器模型还是 n 层应用程序组件?您需要决定先移植哪个软件组件。

如果只有硬件和操作系统被改变了,那么您进行的就是真正的移植。您可以使用不同的方法来实现目标。下面的选项描述了移植方法的两个步骤:

  • 选项 A:因为 Sparc 平台也支持 Linux,所以被修改的代码可以在移植到 Linux 目标平台上之前在 Sparc 平台上测试和执行。您可以从 Sun 免费获得一套全面的用于 Solaris 操作环境的软件,它们在 Linux 和 Solaris 环境中都能够提供互操作性和通用性。

    Sun 的开发工具使创建兼容的源代码更容易,并有助于迁移极为重要的实用程序代码以避免重写,还可以减少安装时间。这个选项可以帮助 Linux 经验有限的开发者将 Solaris 源代码移植到 Linux 目标平台上。下面的 Web 站点提供了 Solaris GNU 工具:

    http://www.sun.com/solaris/freeware.html

    http://www.sunfreeware.com

    在构建和测试了被移植的代码之后,您就可以遵循下一个选项来将代码移植到 Linux 目标平台了。

  • 选项 B:将代码移植到 Linux 目标平台。将测试结果与 Solaris 平台作比较,以验证操作是否正确。修改过的代码必须是与尾数无关的,或者必须使用条件编译以支持小尾数平台。

要开始移植,请仔细检查 Solaris 源代码,并测试这些代码以保证其运行无误。检查过程应该包括完整的编译、重构建以及测试周期。大多数情况下,代码在 Linux 目标系统上会出错,因为最初的源代码树中安装了有错误的软件更新。因此,除非您亲自测试过代码,否则不能轻信在移植时通常会听到的断言(“它在源系统上没有问题!”)。

下面的参考资料也有助于您进行 Linux 移植:

  • 由 Malcom Zung 和 Brian Thomas 撰写的 Solaris 移植指导文章,它位于: 
    ibm.com/developerworks/library/l-solar/ 
  • Red Hat 的 Solaris-to-Linux Porting Guide是一份对移植信息的很好的总结,它位于: 
    http://www.redhat.com/devnet/whitepapers/solaris_port/book1.html 
  • 关于 zSeries 平台的文章 Porting Unix applications to Linux,它位于: 
    ibm.com/servers/eserver/zseries/library/techpapers/gm130115.html

移植过程

下面的建议不是将 Solaris 应用程序移植到 Linux 环境的唯一方法。您可以运用自己的移植经验来建立自己的移植方法。

选择移植开发平台

Sparc 平台:这种方法能够让 Solaris 开发者轻松地实现迁移,将 Linux 应用程序移植到其它目标平台上。因为 Sun 提供了公共库和构建环境,从而将开发在 Linux 和 Solaris 操作环境上兼容的源代码的过程流水线化,所以第一步是修改 Solaris 平台上的移植代码。这些工具包括下面的使用指南:

  • 如何识别出 C/C++ 源代码中可能出现的库调用区别。 
  • 如何转换 shell 脚本。 
  • 如何在 Solaris 下重新创建 Linux 系统配置数据。要了解更多信息,请参阅: 
    http://www.sun.com/software/linux/compatibility/ultralinux/

在 Solaris 平台上测试和构建了 Linux 应用程序之后,您就可以移植到 Linux 目标平台上了。这种方法有下面几个优势:

  • 它使改变之处减到最少,从而让这些改变更容易理解,更容易管理,也更容易推广。 
  • 它使移植过程中产生的新问题的数目减到最少。 
  • 每一处改变都修正了某个已知的问题。

Linux 目标平台:经验丰富的 Linux 开发者可以在 Linux 目标平台上修改要移植的代码。您需要确保安装了正确版本的库和编译器,如 gcc、tcl/tk、glib、GNOME 和 KDE。

使用 grep 命令

在确定移植开发平台之后,您需要搜索下面内容,它们可能会导致源代码中出现移植问题:

  • 正则表达式 
  • printf、sprintf、scanf 和 sscanf 例程的宏 
  • 可能改变数据排列的结构和联合 
  • #else .... #endif 语句 
  • 系统头文件(如 limits.h、types.h 等等)

搜索了可能产生的问题之后,您需要决定是否希望保留单独的源代码库,以支持多平台(Solaris、Linux 及其它平台)。

找出潜在的问题

在使用 grep 命令之后,您还需要检查是否存在低效率或不可移植的代码。下面的列表可以帮助您找出移植问题:

  • 找出源代码和库中不兼容的地方。 
  • 实行比编译器所用的更严格的类型检查规则。 
  • 找出潜在的与变量有关的问题。 
  • 找出潜在的与函数有关的问题。 
  • 找出与流程控制有关的问题。 
  • 找出可能产生错误或降低效率的合法构造。 
  • 找出未使用的变量和函数声明。 
  • 找出有可能不可移植的代码。

使用移植工具

下面的工具已经可供使用,或者已在开发之中:

  • 移植管理器(Porting Manager)是一个 Perl 脚本,它接受源代码树作为输入。它扫描 C/C++ 代码以找出仅用于 Solaris 的 API,并将它们标记出来。它还提供了文档,描述如何将 Solaris API 移植为 Linux 上与其相当的 API。扫描过程是基于表的(工具提供了要检查的 API 的表以及标记)。它将生成工具要检查的 API 的列表。它还会检查头文件和某些编译指示(pragma)。移植管理器有一个 GUI 前端,而且因为它是用 Perl 编写的,所以能够同时在 Solaris 和 Linux 上运行,估计在 Perl 运行的任何平台上都能够运行。 
  • developerWorks Solaris-to-Linux 移植工具是一种 Web 应用程序,它检查 Solaris 应用程序使用的 API 在 Linux 上的兼容性如何。下面的 Web 站点提供对该 Web 应用程序工具的访问:

    ibm.com/developerworks/linux/tools/l-solar.html


  • MigraTEC 移植套装由 MigraTEC 开发,这家公司专门开发在平台之间迁移应用程序的工具。该移植套装包括 Migration WorkBench,它提供了一个完整的从 Solaris 到 Linux 的 API 映射:

    http://www.migratec.com/MigraTEC/migration_suite.htm

修正编译时找出的问题

通常,要重复好几次才能够编译出没有问题的代码。请确保使用了 -Wall 选项,以捕获所有警告消息。

测试和调试程序

您可以使用 gdb 工具来调试修改过的代码。要了解更多关于 gdb 的信息,请参阅 GNU gdb 调试程序。

比较 Linux 与 Solaris

这一部分将讨论目录、文件系统、信号、尾数问题、系统派生的数据类型以及绝对地址。

目录

Linux 目录的结构是标准化的。每个目录都有定义精确的任务。典型的 Solaris 和 Linux 安装将创建如下表所示的目录:

Solaris 目录 功能 Linux 目录 功能
/bin 用户命令。 /bin 包含普通用户启动时和启动后所需的二进制文件。
    /boot 包含开始启动过程的 LILO 引导程序所需的文件。内核文件驻留在 /boot 中。
/dev 包含 /devices 中的符号链接条目,大多数真正的设备条目都是在 /devices 中创建的。 /dev 包含真正的块、字符和其它指向设备的设备文件,如 fd0(第一个软盘驱动器)和 hda1(第一个硬盘驱动器上的第一个分区)。
/devices 对于系统中的每个真正的设备来说,都应该在该目录中为其创建一个条目。    
/etc 其它命令、网络配置文件和脚本等等。 /etc 预留给属于机器本身的配置文件。/etc 中没有二进制文件。X-Windows 配置文件 XF86Config 存储在 /etc/X11 中。
/home 通常用作用户主目录。 /home 通常用作用户主目录。
/kernel 包含内核模块。   对应的内核文件在 /boot 和 /lib 模块中。
/opt 应用程序包。    
/platform 特定于平台的 Unix 和用于启动的设备驱动程序。    
/proc 包含关于活动进程和线程的信息,还提供一个接口来控制这些进程和线程。每个进程目录都有一些文件条目,包含该进程的内核结构。 /proc 包含深入到内核的文件系统视图。对于每个进程,都有多个目录,另外,还有对应于系统计数器和限制的目录和文件。
    /lib 只包含那些需要执行 /bin 和 /sbin 中的二进制文件的库。/lib/modules 包含可装入的内核模块。
    /lost&found  
    /mnt 系统管理员进行临时安装所用的安装点。
    /root 这是 root 用户的主目录,除了 root 用户的概要文件信息之外,里面通常没有任何重要文件。
/sbin 系统控制命令,例如 mount 和 umount。 /sbin 只被 root 用户使用的可执行文件,而且只是那些需要安装 /usr 并执行系统恢复操作的可执行文件。
/tmp 它也是一个映射到系统内存的特殊文件系统。 /tmp 与 Solaris 系统相同
/usr 编译器,管理性质的。 /usr 多数应用程序软件安装所在的位置。
/var 包括 lpd 和 mail spool。也被各种需要记录日志文件的应用程序(如系统消息)所使用。 /var 包括 lpd 和 mail spool。也被各种需要记录日志文件的应用程序所使用。

文件系统

Linux 可以使用几种类型的文件系统。每种文件系统都有自己的格式和一组特征(如文件名长度、文件大小的最大值等等)。Linux 还支持几种第三方文件系统类型,如 MS-DOS 文件系统。下面的表列出了 Linux 可以使用的各种文件系统类型:

文件系统 类型名 注释
Second Extended Filesystem ext2fs 最常见的 Linux 文件系统
Third Extended Filesystem ext3fs ext2fs 的日志记录文件系统
Extended Filesystem ext 已被 ext2fs 取代
Minix Filesystem minix 最早的 Minix 文件系统
Xia Filesystem Xia 与 ext2 类似
UMSDOS Filesystem umsdos 用于在 DOS 分区上安装 Linux
MS-DOS Filesystem msdos 使用 tp 处理 MS-DOS 文件
/proc Filesystem proc 提供系统信息
System V Filesystem sysv 用于访问系统 V
HPFS Filesystem hpfs HPFS 分区的只读访问
Journal Filesystem jfs 有日志记录的文件系统
ReiserFS Filesystem reiserFs 使用经典的平衡树(balanced tree)算法上的变量

最常用的文件系统类型是 Second Extended Filesystem,或者说 ext2fs。ext2fs 是最有效、最灵活的一种文件系统;它允许文件名长达 256 个字符,文件系统大小最多可以达到四千兆字节。您还可以将 ext2fs 升级为 ext3fs。您可以在 /proc/filesystem 目录的文件中找到您的内核目前支持哪些文件系统。

字节顺序问题

SPARC 体系结构是big endian(BE)的,它具有向前的字节顺序。第 0 位是最不重要的位,而第 0 字节是最重要的字节。请注意,在从 Solaris 向 pSeries 或 IBM eServer zSeries 移植时,字节顺序问题并不会产生影响,因为它们都是 BE 平台。Intel x86 体系结构是little endian(LE),所以第 0 字节是最不重要的字节(LSB)。图 1 说明了 BE 和 LE 表达方式的字节顺序:


图 1. 大尾数和小尾数地址
从 Solaris 向 Linux 移植应用程序的技术指导_第1张图片 

数据类型不匹配

当把 4 字节的整数当作整数数据类型的数据元素对待时,LE 和 BE 则按相反方向查看整数中的各个位和字节。

int a=0x11121314;
char b, *ptr;
ptr= (char *) &a;	     // pointer 
        ptr points to 
        a
b= ptr[1];		     // 
        b is 0x13 in LE and 0x12 in BE
      

使用与尾数无关的解决方案可以解决 LE 和 BE 之间的字节顺序问题。

#define INTB16TO23(a) ((a>>16) & 0xff)
b= INTB16TO23(a);		// 
        b is 0x12 in BE and LE
      

网络通信

如果要在 BE 和 LE 系统之间转移多字节值的数据,那么我们要做的就只是提供交换字节的代码。对于网络通信来说,象 htons() 和 ntohs() 这样的函数也用来将端口号转换为网络字节顺序。

常用的尾数解决方案指南

  • 使用与尾数无关的解决方案来解决数据类型不匹配问题。 
  • 使用宏和指令。

    要使代码能够移植,您可以使用如下的宏和条件编译指令:

    #define BIG_ENDIAN         0
    #define LITTLE_ENDIAN      1
    #define BYTE_ORDER	BIG_ENDIAN
    


  • 使用编译时选项。

    另一种可以实现这一点的选项是在编译命令行定义 BYTE_ORDER 的值。您可以只改变 makefile 来构建应用程序,也可以使用 GCC 编译选项来选择合适的特定于尾数的代码片段。

信号

Linux 接受四种缺省操作作为信号:忽略、停止进程、终止进程或在终止进程之后生成核心转储。Linux 支持由 System V、BSD 和 POSIX 提供的几乎每种信号,除了下面的特殊情况:

  • 不支持 SIGEMT、SIGINFO 和 SIGSYS。 
  • SIGABRT 与 SIGIOT 相同。 
  • SIGIO、SIGPOLL 和 SIGURG 相同。 
  • SIGBUS 被定义为 SIGUNUSED。从技术角度上讲,Linux 环境中没有“总线错误”。

下面的 web 站点提供了关于 Linux 信号的更多详细信息:

http://www.linux-mag.com/2000-01/compile_01.html

http://www.linuxhq.com/guides/LPG/node138.html - SECTION001120000000000000000

注意:POSIX.1 只定义 SA_NOCLDSTOP。当移植使用信号操作的应用程序时,您可能必须修改 sa_flag 的值来获取合适的行为。

Solaris 中有 sig2str() 和 str2sig() API,它们用于在信号和字符串之间对信号名进行来回转换。因为 Linux 不支持这些 API,所以下面的代码对移植不起作用:

#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
int main(int argc, char **argv)
{
	char signame[SIG2STR_MAX];
	
        sig2str(atoll(argv[1]), signame);
	printf("Received signal = %s \n", signame);
	return 0;
}
      

下面是修正后的用于向 Linux 进行移植的代码:

#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
int main(int argc, char **argv)
{
	const char *str
	
        int signo_ = atoll(argv[1]);
	str = sys_siglist[signo_];
	printf ("Received signal = %s \n", str);
	return 0;
}
      

下面的表列出了 Solaris 和 Linux 操作系统中常用的信号。

Solaris Solaris 缺省操作 Linux Linux 缺省操作
SIGHUP 终止 SIGHUP 忽略
SIGINT 终止 SIGINT 忽略
SIGQUIT 终止,核心 SIGQUIT 终止,核心
SIGILL 终止,核心 SIGILL 终止,核心
SIGTRAP 终止,核心 SIGTRAP 忽略
SIGABRT 终止,核心 SIGABRT 终止,核心
SIGEMT 终止,核心 SIGEMT Linux 上不支持
SIGFPE 终止,核心 SIGFPE 终止,核心
SIGKILL 终止 SIGKILL 终止
SIGBUS 终止,核心 SIGBUS 终止,核心
SIGSEGV 终止,核心 SIGSEGV 终止,核心
SIGSYS 终止,核心 SIGSYS Linux 上不支持
SIGPIPE 终止 SIGPIPE 忽略
SIGALRM 终止 SIGALRM 忽略
SIGTERM 终止 SIGTERM 终止
SIGUSR1 终止 SIGUSR1 忽略
SIGUSR2 终止 SIGUSR2 忽略
SIGCHLD 忽略 SIGCHLD 忽略
SIGPWR 忽略 SIGPWR 忽略
SIGWINCH 忽略 SIGWINCH 进程停止
SIGURG 忽略 SIGURG 忽略
SIGPOLL 终止 SIGPOLL Linux 上不支持
SIGSTOP 进程停止 SIGSTOP 进程停止
SIGSTP 进程停止 SIGSTP 进程停止
SIGCONT 忽略 SIGCONT 忽略
SIGTTIN 进程停止 SIGTTIN 进程停止
SIGTTOU 进程停止 SIGTTOU 进程停止
SIGVTALRM 终止 SIGVTALRM 终止,核心
SIGPROF 终止 SIGPROF 忽略
SIGXCPU 终止,核心 SIGXCPU 终止,核心
SIGXFSZ 终止,核心 SIGXFSZ 终止,核心
SIGWAITING 忽略 SIGWAITING Linux 上不支持
SIGLWP 忽略 SIGLWP Linux 上不支持
SIGFREEZE 忽略 SIGFREEZE Linux 上不支持
SIGTHAW 忽略 SIGTHAW Linux 上不支持
SIGCANCEL 忽略 SIGCANCEL Linux 上不支持
SIGRTMIN 终止 SIGRTMIN Linux 上不支持
SIGRTMAX 终止 SIGRTMAX Linux 上不支持

系统派生的数据类型

系统派生的数据类型可以有不同的字节大小。派生的数据类型就是用 typedef 定义的派生类型,或者用已知基本类型的结构定义的类型。下面几部分将比较 Solaris 和 Linux 中最常见的系统派生的数据类型。

  • 数据类型 gid_t、mode_t、pid_t 和 uid_t

    数据类型 gid_t 用来代表用户的组 ID,而 uid_t 用来代表用户 ID。数据类型 mode_t 用来表示文件的模式,而 pid_t 用来以唯一的数字标识不同的进程。

    OS gid_t mode_t pid_t uid_t
    Solaris long unsigned long long long
    Linux unsigned int unsigned int int unsigned int

  • Size_t、ssize_t 和 wint_t

    数据类型 size_t 和 ssize_t 应该结合内存中对象的大小来使用,并返回字节计数或错误指示。当程序使用多字节和宽字符子例程时,就需要数据类型 wint_t 来表示宽字符代码值以及文件尾标记。

    OS size_t ssize_t wint_t
    Solaris unsigned int int long
    Linux unsigned long int unsigned int

绝对地址

每个平台都可能使用不同的内存位置来存储程序堆栈、系统库、堆等等。因此,使用硬编码地址已经很难保证到其它系统的可移植性了。某些寻址方式还忽略高阶位,所以硬编码地址 0x80000000(高阶位是 1)将被转换为 0x00000000,这很可能是非法的,而且绝对不是您想要的。在生成地址的时候,对地址的算术运算也能使高阶位变为 1。

如果应用程序使用了导致分段冲突或其它错误的绝对地址,那么就必须改变它。/proc/<pid>/map 将展示一个活动进程如何使用它内部地址空间的存储范围。如果代码必须使用绝对地址,那么这个 map 就可以用来查找还没有被保留的地址范围。

一些应用程序开发工具

C/C++ 应用程序基础架构

操作系统
  • Red Hat Linux V7.1
  • SuSE V 7.2(Intel)
运行时库
  • glibc V2.2

C/C++ 应用程序工具的使用

分析和设计
  • Rational Rose
IDE
  • 带有 C/C++ 插件的 IBM WebSphere Studio Application Developer
  • Metrowerks CodeWarrior
低级编辑/编译/调试
  • GNU Compiler Collection V3.0
  • GNU GDB Debugger V5.0
  • Insure++ V5.2
构建
  • GNU make V3.79
  • Automake
打包
  • RPM V4.02
测试
  • DejaGnu
  • TETWare Professional V1.3
性能调优及基准测试
  • GNU Profiler V2.9.1
  • LmBench
源代码管理
  • Rational ClearCase
  • AccuRev/CM V2.6
  • RCS 和 CVS
维护和故障检测
  • Rational ClearQuest Client
  • GNATS V3.113
  • Bugzilla

Java 应用程序工具的使用

  • 分析和设计
  • Rational Rose,ObjectDomain 2.5
IDE
  • Idera Jsync 1.50
  • AnyJ
  • NetBeans Developer 2.1
  • Source Navigator
JVM
  • SUN JVM
  • IBM JVM
编译器
  • Jikes
性能工具
  • Optimizeit
源代码管理
  • Rational ClearCase
维护和故障检测
  • Rational ClearQuest Client

Solaris make 对 GNU make

Solaris make 对 GNU make

Solaris make 和 GNU make 都定义了相同的基本后缀集和隐式规则。下面的目标、宏和变量都是相同的:

  • 目标:.DEFAULT、.IGNORE、.PRECIOUS、.SILENT 和 .SUFFIX 
  • 内部宏:$*、$%、$?、$<、$@、$$@、$(F) 和 $(D) 
  • 预定义的宏:ar、as、cc、ld、lex、lint、m2c、pc、rm -f 和 yacc 
  • 环境变量:MAKEFLAGS 
  • 变量:CC、CFLAGS、CPPFLAGS、FC、FFLAGS、LEX、LFLAGS、YACC、YFLAGS、LD 和 LDFLAGS

注意:GNU make 不完全支持 %。只有第一个 % 才会被替换。

下面是示例:

#Begin Makefile
FOO=abc def
BAR=$(FOO:%=dir1/%.o  dir1/%_cltn.o)
BAR2=$(FOO:%=dir1/%.o) $(FOO:%=dir1/%_cltn.o)
all:
@echo FOO is $(FOO)
@echo BAR is $(BAR)
@echo BAR2 is $(BAR2)
#end Makefile

在 Sun 上,make 命令将打印:

FOO is abc def
BAR is dir1/abc.o dir1/abc_cltn.o dir1/def.o dir1/def_cltn.o
BAR2 is dir1/abc.o dir1/def.o dir1/abc_cltn.o dir1/def_cltn.o

在使用 GNU 的 Linux 上,make 命令将打印:

FOO is abc def
        BAR is dir1/abc.o dir1/%_cltn.o dir1/def.o dir1/%_cltn.o
BAR2 is dir1/abc.o dir1/def.o dir1/abc_cltn.o dir1/def_cltn.o
      

为了解决这个差别带来的问题,您需要按下面所示修改代码:

					
        BAR = $(FOO:%=dir1/%.o)
BAR += $(FOO:%=dir/%_cltn.o)
BAR2 = $(FOO:%=dir/%.o)
BAR2 += ${FOO:%=dir1/%_cltn.o)
			
      

make 的后缀

make 自带的内置后缀规则让开发者可以极大地简化 makefile。下面的单后缀和双后缀的表包含 Solaris 和 GNU make 命令的缺省推理规则。

单后缀推理规则

后缀 Make 单后缀规则
.c Solaris $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBD)
  GNU $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) 
$(LDLIBS) -o $@
.C Solaris $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
  GNU $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ 
$(LOADLIBES) $(LDLIBS) 
-o $@
.cc Solaris $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
  GNU $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $(LOADLIBES) 
$(LDLIBS) -o $@
.f Solaris $(FC) $(FFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
  GNU $(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES)$(LDLIBS) -o $@
.F Solaris $(FC) $(FFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
  GNU $(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES)$(LDLIBS) -o $@
.mod Solaris $(M2C) $(M2FLAGS) $(MODFLAGS)-o $@ -e $@ $<
  GNU $(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH) -o $@ -e $@ $^
.p Solaris $(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
  GNU $(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ 
$(LOADLIBES) $(LDLIBS) -o $@
.r Solaris $(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
  GNU $(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ 
$(LOADLIBES) $(LDLIBS) -o $@
.sh Solaris $(RM) $@ 
cat $<>$@ 
chmod -x $@
  GNU cat $<>$@ 
chmod a+x $@

双后缀推理规则

后缀 Make 双后缀规则
.c.o Solaris $(CC) $(CFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTION) $<
  GNU $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c$(OUTPUT_OPTION) $<
.c.ln Solaris $(LINT) $(LINTFLAGS) $(CPPFLAGS) $(OUTPUT_OPTION) -c $<
  GNU $(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -C$* $<
.cc.o Solaris $(CCC) $(CCFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTION) $<
  GNU $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c$(OUTPUT_OPTION) $<
.C.o Solaris $(CC) $(CFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTION) $<
  GNU $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c$(OUTPUT_OPTION) $<
.def.sym Solaris $(M2C) $(M2FLAGS) $(DEFFLAGS) -o $@ $<
  GNU $(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH) -o $@ $<
.f.o Solaris $(FC) $(FFLAGS) -c $(OUTPUT_OPTION) $<
  GNU $(FC) $(FFLAGS) $(TARGET_ARCH) -c $(OUTPUT_OPTION) $<
.F.o Solaris $(FC) $(FFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTIONS) $<
  GNU $(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c$(OUTPUT_OPTION) $<
.l.c Solaris $(RM) $@ 
$(LEX) $(LFLAGS) -t $< > $@
  GNU @$(RM) $@ 
$(LEX) $(LFLAGS) -t $< > $@
.l.ln Solaris $(RM) $*.c 
$(LEX) $(LFLAGS) -t $< > $*.c 
$(LINT) $(LINTFLAGS) $(CPPFLAGS) -o $@ -i $*.c 
$(RM) $*.c
  GNU @$(RM) $*.c 
$(LEX) $(LFLAGS) -t $< > $*.c 
$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -i $*.c -o $@ 
$(RM) $*.c
.mod.o Solaris $(M2C) $(M2FLAGS) $(MODFLAGS) -o $@ $<
  GNU $(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH) -o $@ $<
.r.o Solaris $(COMPILE.r) $(OUTPUT_OPTION) $<
  GNU $(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c $(OUTPUT_OPTION)$<
.s.o Solaris $(AS) $(ASFLAGS) -o $@ $<
  GNU $(AS) $(ASFLAGS) $(TARGET_MACH) -o $@ $<
.S.o Solaris $(AS) $(ASFLAGS) -o $@ $<
  GNU $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c -o $@ $<
.y.c Solaris $(YACC) $(YFLAGS) $< 
mv y.tab.c $@
  GNU $(YACC) $(YFLAGS) $< 
mv -f y.tab.c $@
.y.ln Solaris $(YACC) $(YFLAGS) $< 
$(LINT) $(LINTFLAGS) $(CPPFLAGS) -o $@ -i y.tab.c$ 
(RM) y.tab.c
  GNU $(YACC) $(YFLAGS) $< 
$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -C$* y.tab.c 
$(RM) y.tab.c

C 编译器的选项

Sun Workshop(Forte)编译器和 GCC 都支持扩展 C 语言。Sun Workshop 编译器的扩展几乎等同于 GCC。扩展的编译指示的形式是独一无二的。GCC 通常不使用编译指示,但在使用了 -Wall 选项的时候会警告忽略了编译指示。

GCC 上的 -m486 选项用来编译 x486 机器的二进制文件,它只会改变某些特定的优化。有一种版本的 GCC 可以对 586 进行很好的优化,但它很不可靠,尤其是在高优化设置时。关于 Pentium GCC,请参阅:

ftp://tsx-11.mit.edu/pub/linux/ALPHA/pentium-gcc/。

对于 pSeries 和 RS/6000 来说,使用“-mcpu”选项将禁用“-mpower”或“-mpowerpc”选项。我们推荐的做法是使用缺省的“-mcpu=common”。

对于 SPARC 来说,使用“-mcpu”选项也会为机器类型选择体系结构。

GNU C 库也有线程意识。当您链接到线程处理库 libpthread(用 gcc 的命令行参数 pthread )时,libc.so 中的某些函数将被线程处理库中的函数覆盖。

下面的表包含 Solaris 和 GNU GCC 上的 C 编译器的常用选项。

Sun Workshop GCC 描述
-# -v 打开详细(verbose)模式,显示每个被调用的组件。
-Xa -ansi 指定与 ANSI/ISO 标准的兼容。GCC 支持所有 ISO C89 程序。您可以使用“-std”来指定特殊版本的 ISO C。
-xinline -finline-functions 只插入那些指定的函数。
-p -p 生成额外代码,用来写适用于分析程序简档的概要文件信息。
-xa -ax 生成额外代码,用来写基本块的概要文件信息,记录每个基本块被执行的次数。
-xspace -O0 不进行优化。
-xunroll= -finroll_loops 只对迭代次数可以在编译时或运行时决定的循环进行循环打开优化。
-xtarget = name -b=machine 参数机器指定进行编译的目标机器。另外,这里的每个目标机器类型都可以有自己特殊的选项,以“m”开头,在各种硬件模型或配置中进行选择。
-xo -O, -O1, -O2, -O3, -Os 控制各种优化。
-O 同上 控制各种优化。
-xmaxopt   保证 GCC 不使用编译指示。
-xnolib -nostdlib 缺省情况下不链接任何库。
-fsingle -fsingle-precision-constant 将浮点常量作为单精度常量对待,而不是隐式地将其转换为双精度。
-C -C 告诉预处理器不要废弃注释。与“-E”选项一起使用。
-xtrigraphs -trigraphs 支持 ISO C trigraph。
-E -E 预处理所有指定的 C 源文件,并将结果输出到标准输出或指定的输出文件。
-xM -M 只运行指定的 C 程序上的预处理器,要求生成 makefile 依赖性(dependencies)信息并将结果发送到标准输出。
-xpg -pg 生成额外代码,来写适用于分析程序 gprof 的概要文件信息。
-c -c 命令编译器不要用 ld 进行链接,并为每个源文件生成 .o 文件。
-o -o 命名输出文件。
-S -S 命令 cc 生成组装源文件但并不组装程序。
-xtemp TMPDIR 如果设置了 TMPDIR 环境,就指定临时文件要使用的目录。
-xhelp=f -help 显示联机帮助信息。
-xtime -time 报告编译序列中的每个子进程所使用的 CPU 时间。
-w -q 禁止编译器警告。
-erroff= %none -W 显示警告消息。
-errwarn -Werror 将所有警告消息转换为错误消息。

链接程序调用

Sun 和 GNU 链接程序都接受为数众多的选项。下面的表解释了 SPARCworks 链接程序最常用的选项与 GNU 链接程序的功能对比。

Solaris Workshop gld 选项 描述
-a -static 启用静态模式的缺省行为,防止与共享库进行链接。链接程序会创建可执行文件和导致错误消息的未定义符号。GNU ld 有 -static 选项,也能启用这种行为。
-b   不用 -fPIC/-fpic 选项编译源代码,从而实现 GNU 链接程序的同等功能。
-g -g 以操作系统的本机格式生成调试信息。
-G -shared 生成共享对象。与 GNU 链接程序等同的是 -shared。
-m (-M) 打印链接程序映射。-M 选项打印可以比较的某些东西,只是它们的格式不同,内容也稍有不同。
-s -S/-s 使用 GNU 链接程序的 -S(它只会删除调试信息),实现与 -s 选项同等的效果。
-h name -sonamename 将名称设置为共享对象的名称。如果使用 GNU 链接程序,就必须用 -soname 选项。
-o filename -o filename 将输出放在文件中。不管产生的输出是何种类型,它都适用。缺省情况是将可执行文件放在“a.out”中。
-Ldirectory -L dir 将目录 dir 添加到目录列表中。
-R path -rpathpath 指定运行时链接程序的搜索方向。GNU 链接程序使用 -rpath 选项。

每个 Linux 共享库都被分配了一个叫作 soname的特殊名称,它包括库的名称和版本号。除非您有特别的理由,否则请不要链接到特定版本之外的库上。通常请使用 C 编译器或链接程序的标准的 -l libname选项。链接程序将查找文件 lib libname.so,该文件是到正确版本的库的符号链接。

特定于 pSeries 和 RS/6000 的 GCC 选项

选项 描述
-fPIC 生成与位置无关的代码(position-independent code,PIC),以便在共享库中使用。
-mpower、-mno-power、-mpowerpc、-mno-powerpc、-mnpowerpc64、-mno-powerpc64 指定 GCC 将生成各种体系结构的指令。
-mcpu=cpu_type 设置体系结构类型、注册程序的使用、助记符的选择和特定机器类型的指令调度参数。
-mtune=cpu_type 设置特定机器类型的指令调度参数。
-mlittle 用小尾数模式编译 Power PC 处理器的代码。
-mbig 用大尾数模式编译 Power PC 处理器的代码。
-mcall-linux 编译 Power PC 基于 Linux 的 GNU 系统的代码。

Solaris 线程库(Solaris Thread Library,STL)

为 Solaris 编写的应用程序经常会使用非标准的专有函数,这会令向 Linux 进行移植的工作很困难。Linux( Intel 平台)上支持一种临时的 STL,这将减少迁移这些应用程序的麻烦。它提供了基于 POSIX 线程库的 Solaris 线程 API 的实现。STL 是 Solaris 兼容性库(Solaris Compatibility Libraries,SCL)的一个组件,您可以按开放源代码的形式免费获取 SCL 的这个部分。您可以从Compaq发起的 Sourceforge 项目获取它,这个项目位于:

http://sourceforge.net/projects/sctl

局限性

SCL STL 不支持下面的功能:

  • 对系统级同步对象的支持 
  • 出现 fork() 时对每个线程的复制

要让开发者使用 STL 库,您需要留意线程的局限性和问题。举例来说,POSIX 线程的暂挂和线程继续没有得到支持。一篇题为“Building an Open-Source Solaris-Compatible Threads Library”( Proceedings of the FREENIX,2001 年 6 月)的文章中包含更多详细信息和实现注释。您可以从下面的 Web 站点获取该文章的副本:

http://www.opensource.compaq.com/the_source/linux_papers/scl_solaris.htm

我们希望今后 Linux 版本的 STL 能够支持其它 Linux 目标平台(RS/6000、Power PC 等等)。

系统接口

下面这部分将讨论 Solaris 中使用了线程的应用程序、Solaris 中使用了 POSIX 线程的应用程序、Solaris 线程库和 POSIX 线程库的对比,以及对接口和定义的支持。

Solaris 中使用了线程的应用程序

使用 Solaris 线程编程接口(API)的应用程序基本上是不可移植的,例如 thr_create()、mutex_lock()、cond_signal() 等等。POSIX 线程中不支持的 Solaris 线程函数的主要方面有:

  • 守护线程(thr_create) 
  • 加入任何线程(Solaris 允许您用 tid 0 加入任何线程) 
  • 线程暂挂和线程继续

如果前面所述的任何一方面需要满足,那么将使用 Solaris 线程的应用程序移植到 Linux 就需要一定程度的工作了。否则,Solaris 线程 API 和 POSIX 线程 API 之间的映射就非常简单了。

我们不推荐您将 STL 与 POSIX 线程 API 调用混在一起。如果可能的话,您应该使用本机库,因为这将使您能够最大程度地控制线程。

下面的表将比较 Solaris 线程 API 与 POSIX 线程 API。

Solaris 线程 API Linux POSIX 线程 API 操作
thr_create() pthread_create() 创建一个新的控制线程。
thr_exit() pthread_exit() 终止调用线程的执行。
thr_getprio() pthread_getschedparam() 检索线程的优先级参数。
thr_getspecific() pthread_getspecific() 将新的特定于线程的值绑定到键。
thr_join() pthread_join() 暂挂调用线程,直到目标线程结束。
thr_keycreate() pthread_key_create() 创建一个定位特定于线程的数据的键。
thr_kill() pthread_kill() 向另一个线程发送信号。
thr_self() pthread_self() 返回进行调用的进程的线程 ID。
thr_setprio() pthread_setschedparam() 修改线程的优先级参数。
thr_setspecific() pthread_setspecific() 将新的特定于线程的值绑定到键。
thr_sigsetmask() pthread_sigmask() 改变或者检查发出调用的线程的信号掩码。
thr_yield() sched_yield() 使当前线程对另一个线程让步。
thr_setconcurrency() pthread_setconcurrency() 设置线程并发性级别。
thr_getconcurrency() pthread_getconcurrency() 获取线程并发性级别。
thr_setspecific() pthread_setspecific() 设置特定于线程的数据键。
thr_getspecific() pthread_getspecific() 获取特定于线程的数据键。
thr_suspend 不支持 暂挂指定线程的执行。
thr_continue 不支持 恢复被暂挂的线程的执行。

请注意:POSIX 标准不提供任何使得线程 A 在不与线程 B 合作的情况下暂挂线程 B 的执行的机制。实现暂挂或者重启机制的唯一方法就是让线程 B 周期性地检查某个全局变量,查找暂挂请求,然后找到条件变量时将自己暂挂(另一个线程可以在这之后对其发出信号,以重启 B)。

Solaris 中使用了 POSIX 线程的应用程序

Solaris 中使用了 POSIX 线程的应用程序很容易向 Linux 移植,只是在进程共享功能中会出现一些异常。

Solaris 线程库与 POSIX 线程库的对比

Linux 支持 POSIX 1003.1c。Solaris 既支持 POSIX 1003.1c,又支持专有信号 API。下面的表对专有的 Sun 例程和 Linux 中实现的 POSIX 1003.1c API 进行了对比。

Solaris 和 Linux 的接口之间的一个主要区别就是,Solaris 在 libthread 中定义这些函数,而 Linux 在 libpthread 中定义这些函数。

Solaris 库(lib 线程) Linux POSIX 库(libp 线程) 操作
sema_destroy() sem_destroy() 销毁信号状态。
sema_init() sem_init() 初始化信号。
sema_post() sem_post() 增加信号。
sema_wait() sem_wait() 阻止信号计数。
sema_trywait() sem_trywait() 减少信号计数。
mutex_destroy() pthread_mutex_destroy() 销毁或禁用与互斥对象相关的状态。
mutex_init() pthread_mutex_init() 初始化互斥变量。
mutex_lock() pthread_mutex_lock() 锁定互斥对象和块,直到互斥对象被释放。
mutex_unlock() pthread_mutex_unlock() 释放互斥对象。
cond_broadcast() pthread_cond_broadcast() 解除对等待条件变量的所有线程的阻塞。
cond_destroy() pthread_cond_destroy() 销毁与条件变量相关的任何状态。
cond_init() pthread_cond_init() 初始化条件变量。
cond_signal() pthread_cond_signal() 解除等待条件变量的下一个线程的阻塞。
cond_wait() pthread_cond_wait() 阻止条件变量,并在最后释放它。
rwlock_init() pthread_rwlock_init() 初始化读/写锁。
rwlock_destroy() pthread_rwlock_destroy() 锁定读/写锁。
rw_rdlock() pthread_rwlock_rdlock() 读取读/写锁上的锁。
rw_wrlock() pthread_rwlock_wrlock() 写读/写锁上的锁。
rw_unlock() pthread_rwlock_unlock() 解除读/写锁。
rw_tryrdlock() pthread_rwlock_tryrdlock() 读取非阻塞读/写锁上的锁。
rw_trywrlock() pthread_rwlock_trywrlock() 写非阻塞读/写锁上的锁。

要使用 POSIX 线程的 read/write lock 扩展,您必须在编译时定义:

_XOPEN_SOURCE=500

这要在加入 <pthread.h> 头文件之前完成,还要定义:

_POSIX_C_SOURCE=199506L

Linux 线程不实现共享进程的互斥、条件和信号。该扩展的目的是允许不同的进程(有不同地址空间的进程)在共享内存中(SVR4 共享内存片段或映射的 mmap() 文件)分配的互斥、条件或信号之间进行同步。举例来说,如果在 pthread_mutex_attr_setpshared、pthread_rwlockattr_setpshared 和 pthread_condattr_setpshared 各自的标志参数(它们可以被传送到这些函数)中设置了 PTHREAD_PROCESS_SHARED,那么对这些函数的调用就会失败。

在从支持与这些函数共享进程的平台进行移植时,如果设置了 PTHREAD_PROCESS_SHARED 标志,您就必须重写应用程序,因为如果在上述函数中使用该标志的话,Linux 内核将返回 -1。对于互斥和简单的锁/解锁类型的信号和条件变量来说,pthread* 调用可能必须由用户编写的代码来替换。在可以得到合适的 Linux 内核支持前,您应该使用传统的交互进程通讯来对不同进程进行同步:System V 信号、消息队列、管道或套接字。

对接口和定义的支持

Linux 是使用接口和定义的层次结构来编写的。使用缺省的接口 _GNU_SOURCE,应用程序就能够利用所有的编译器功能了。这提供了最方便的编程环境。在一致的环境中还需要下面的宏:

  • _POSIX_SOURCE
  • _XOPEN_SOURCE
  • _POSIX_C_SOURCE
  • _UNIX_STD

其它提示和技巧

下面是前面部分中没有谈到的一些有用的信息。

make 的句法

总是应该在命令开始处输入一个制表符,而不是几个空格。不要在其它任何行之前使用制表符。如果您在应该使用制表符的地方使用了空格,或者作了相反的事,那么 makefile 就不会起作用。

使用 gcc fPIC 标志,而不是 -fpic 标志。

-fPIC 标志将生成与位置无关的代码,这些代码可以在任何地址被链接和加载。

gcc ++ 用来生成 makefile 信息的依赖性工具

-M      生成 make 依赖性信息。
-MM     类似于 -M,但忽略系统头文件。
-MD     类似于 -M,但将输出放在 a.d 文件中。
-MMD    类似于 -MD,但忽略系统头文件
-MG     将丢失的头文件当作生成的文件一样对待。

不使用 lD 来进行链接的选项

只要使用编译器前端来进行链接:

gcc -o progname foo.o bar.o main.o

gcc 前端将插入所有正确的模块来进行适当的链接。添加 -v 参数还使您可以看到 gcc 操作的细节。

检查动态加载库

使用 ldd 来调用可执行文件;它会转储这些文件的库依赖性信息。

使用 LD_LIBRARY_PATH

Linux 系统在缺省情况下只搜索 /lib 和 /usr/lib。如果被链接到您的程序中共享的库安装在这些目录之外,那么就会找不到这些库,而系统会拒绝运行程序。

一种做法是在链接程序的时侯使用 -W1、-rpath 选项。另一种做法是在运行程序时设置 LD_LIBRARY_PATH 环境变量。

内存分配

总是应该使用 malloc() 来进行内存分配,而不是使用其它的系统调用来进行。

Linux 中丢失的 libsocket

对于 Solaris 来说,makefile 包含 -lsocket 库标志,然而 Linux 中看起来并没有出现 Solaris 中的 libsocket.*。没有必要链接任何特定的库,因为它们都是自动链接的。只要将 -lsocket 从 makefile 中取出来就可以了。

避免错误的引用符号

一个常见的错误就是使用撇号(')而不是回点号(`)来编译程序。您只要按“1”左面的那个键就可以输入(`)了。举例来说:

gcc -Wall -o intro intro.c `gtk-config -cflags -libs`

静态链接某些库,而动态链接其它库

请使用下面的:

gcc -o some-program some-program.c -Xlinker -Bstatic 
-llib1 -lib2 -Xlinker   -Bdynamic -llib3

硬编码的常量

避免对数据类型的大小进行硬编码;而是应该使用 sizeof()。请避免使用 malloc() 对常量进行硬编码。请使用 sizof(void *)来获取合适的指针大小。

数据对齐

多数处理器都需要每个内存中的数据项按 2 字节、4 字节或 8 字节边界进行数据对齐;否则处理器就必须执行多次读操作,从而导致性能降级,或者不得不引起硬件异常,让操作系统来处理,从而造成额外的性能降级。

为了解决这种不对齐带来的问题,GCC 编译器在每个没有对齐的项前面添加了填充字节(称为填充,padding),从而保证按照正确边界进行了对齐。虽然编译器添加的填充字节在应用程序代码中是不可见的,但它们的确存在,还能使内存中的数据结构布局与预期的不同。

移植 thr_suspend

请注意,thr_suspend() 一向非常危险,很容易引起争用情况。首先,我们无法控制目标线程真正在何处停止:即便有互斥存在,它也很可能在临界段的中间停住。由于这些原因,您最好不要使用互斥,而该用条件。

符合 ANSI

下面的示例是与不符合 ANSI 的代码,但示例可以在 Solaris Forte 编译器中运行:

const 引用

#include<iostream>
class test
{
public:
// Using a constant ref. to a variable whose value can be changed
        void test1 ( char & const newEvent) { cout << newEvent << endl;};
};
int main()
{
test t;
char * const ptr="A";
t.test1(*ptr);
return 0;
}
      

如果您用 g++ 编译,将得到下面的错误:

					
        Error "discarding "const" applied to a reference"
		
      

const char & 是对常量值的引用;char const & 引用是常量,但引用的值不是常量。

下面是纠正过的代码:

					
        void test1 ( char const & newEvent) { cout << newEvent << endl;};
			
      

未定义的引用

下面的代码样本包含一个未定义的引用:

					
        error" ANSI C++ forbids declaration 'ABC' with no type"
error" (S)  undefined reference to A::x"
#include<iostream>
class test
{
    public:
	     A(int q) { x=q;}
	     
        ABC(int y);
    private:
	     static int x;
};
        A::ABC(int z)
{
    cout << z << endl;
}
int main()
{
    A test(10);
    test.ABC(20);
    return 0;
}
	
      

下面是纠正过的代码:

#include<iostream>
class test
{
    public:
	     A(int q) { x=q;}
	     
        int ABC(int y);
    private:
	     static int x;
};
        int A;;x=1;
int A::ABC(int z)
{
    cout << z << endl;
}
int main()
{
    A test(10);
    test.ABC(20);
    return 0;
}
	
      

从 fstream 对象获取文件描述符

在 Solaris 上,您可以使用 fstream::rdbuf().fd() 方法来从 fstream 对象获取文件描述符。但是 Linux 上的 basic_filebuf 类就没有可用的 fd() 方法。这就是非标准的 C++ 代码。

对于标准的 C++ 代码来说,首先用 open (Posix) 打开文件,然后获取文件描述符 fd。然后用 fdopen(fd)(Posix)打开 FILE 对象,并将其命名为 myfile。接着用 mybuf(myfile)(一致的扩展)创建 filebuf 对象,并将其命名为 mybuf。之后,您就可以调用它的成员函数 str.rdbuf(mybuf)(标准 C++)将该缓冲与 ifstream 或 ofstream 对象 str 关联在一起。

目标硬件平台

Sparc

很多分发商都提供 Sun 的 Sparc 体系结构的 Linux。Sun 正在将 Solaris 作为 Linux 的软件伴侣和开放源代码的发展方向。Sun 有针对 Linux 的调整策略和将 Linux 应用程序迁移到 Solaris 的计划,但 Sun 并不支持或认可任何特定的 Linux 分发版。

pSeries

IBM 在 Linux PowerPC 社区中扮演了积极的角色。对最新一代处理器 POWER3 和 POWER4 的开发需要加入其它功能,这些功能都被添加到 Linux 2.4 内核中了。

使用 Linux 2.4 内核的 SuSE 版本 7.1 是第一个宣布支持 RS/6000 系统的,包括 B50、150、F50、170、260、270 和 p640 模型。

Yellow Dog Linux 也有支持 RS/6000 系统的 PowerPC 分发版。TurboLinux 和 Red Hat 也都发布了 PPC 版本。

据报告说,最新版本的 Linux 2.4 在 SMP 系统中的四到六处理器上伸缩性很好。该版本在 pSeries 和 RS/6000 系统(如 B50、150、260、270 和 p640)以及即将出现的 1 到 6 路的 p620 和 p660 系统上都能很好地工作。要了解 Linux for pSeries System Guide,请参阅:

ibm.com/servers/eserver/pseries/linux/guide.html

下面的软件中有 pSeries 上的 Linux 包:

  • Enhydra Java/XML 
  • Lutris 的 Application Server 
  • Myricom 的 Myrinet scalable cluster interconnect 
  • Absoft 的 Pro Fortran for PowerPC/Linux 
  • Metrowerks 的 CodeWarrior for Linux

任何应用程序都可以用 Linux 开发,然后部署到本机运行 Linux 的 pSeries 上,或者部署到使用 Linux 技术的 AIX Affinity 的 AIX 上。在开发和部署之后,基于 Linux 的应用程序是本机 AIX 应用程序,这意味着它们可以实现与其它任何 AIX 应用程序相同的可伸缩性和性能。然而,如果不为 pSeries 重新编译 Linux,您就不能在 pSeries 上运行 Linux。类似地,在 Linux 上为 pSeries 开发的应用程序也不能在 AIX 上以二进制的形式运行。pSeries 和 AIX 上的 Linux 有源代码兼容性。要了解关于 pSeries 上的 Linux 的更多信息,请参阅:

ibm.com/servers/eserver/pseries/linux/

zSeries

由于服务器结构的统一和服务器数量的减少,从大型服务器场到 zSeries 大型机的巩固使得客户的管理和能源花费更低了。IBM 在 zSeries 上对 Linux 提供了硬件上的支持,如 z900,还有支持 Linux for S/390 的 S/390 处理器,如 G5、G6 和 Multiprise 3000。目前,分发版可以从 SuSE、TurboLinux 和 and Red Hat 获得。

支持的应用程序和语言正在迅速增加,其数量如此众多,很难完整列出。它们包括 C/C++、perl、tcl、python、scheme、Regina(Rexx)和 Java JDK 1.3。数据库包括 MySQL、Postgres、DB2 UDB 和 DB2 Connect。中间件包括 Websphere 3.5、MQ Client、Tivoli 和 Apache。有一些分发版支持 Linux 内核 2.4、HiperSockets 支持、逻辑卷管理器(Logical Volume Manager)和日志记录文件系统 ReiserFS。您可以下载一个 64 位的内核进行 beta 测试。如果您需要一个详细描述可用的应用程序的 Web 页面,请参阅:

ibm.com/servers/eserver/zseries/solutions/s390da/linuxproduct.html

要了解特定于 S/390 和 zSeries 上的 Linux 的移植方面的其它信息,请参阅:

ibm.com/servers/esdd/articles/linux_s390/index.html

ibm.com/servers/eserver/zseries/os/linux

xSeries

几乎所有的 Linux 分发版(RedHat、Caldera、Mandrake、SuSE、Debian、TurboLinux 等等)在 Intel 平台上都在不断得到支持。然而,Linux 在 Intel 台式机方面还没有取得很大成功,但在服务器市场上却小有成果。

IBM e-Business Hosting 正在将 Red Hat Linux 6.2 加入到它的服务器硬件支持的一系列操作系统中。新提供的内容有:一项基本的服务、一组附加的增值服务,以及客户可以选择的价目表(从而能够启用、管理、监控和保护他们的 Linux 电子商务服务器)。服务器环境提供的如下所示:

  • 操作系统:Red Hat Linux 6.2 
  • 支持的服务器硬件:IBM Netfinity Models 3500、4500、5000、5100、5500、5600、6000R、7000、7100 
  • 可用性监控服务:Ping 和 URL 监控 
  • 管理服务:代码中深入的监控能力和增强的事件过滤将提供积极和主动的监控和智能警报通知。可选的控制台将在所有服务器上以实时模式提供客户的应用程序环境的图形表示,从而实现全面、整体的端对端浏览。可视警报通知将捕获“时间点(point in time)”数据,然后事件查看器将帮助最终用户迅速找出问题并加以解决。还有简短的历史报告以供趋势分析。您可以定制所有视图,并在会话之间保存它们。 
  • 安全性服务:每星期用 NSA 扫描程序对受管服务器目标 IP 地址上大约 2500 个最常用的服务和流行的后门端口(backdoor port)进行缺陷扫描。服务是在因特网上有因特网地址的设备之间进行的。扫描服务将根据由 IBM 定义的安全控件来配置(过滤),并标记缺陷。安全性评估小组将审查扫描结果,以确保工作被正确执行。报告将送交 IBM 站点管理者(或指定的支持人员)进行审查,这样他们就可以采取适当的举措。 
  • 备份和恢复服务:在受管的共享数据环境中实现提供客户数据备份和恢复的过程。根据客户需求,还会提供专门的备份和恢复资源。还有其它的 R 级(Band R)服务,包括离站存储(Offsite Storage)、存储协助(Storage Assist)、专门的 B 和 R 服务,以及库划分(Library Portioning)。

要了解关于 xSeries 上的 Linux 的其它信息,请参阅:

ibm.com/servers/eserver/linux/xseries/


你可能感兴趣的:(从 Solaris 向 Linux 移植应用程序的技术指导)