從 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 移植:

移植過程

下面的建議不是將 Solaris 應用程序移植到 Linux 環境的唯一方法。您可以運用自己的移植經驗來建立自己的移植方法。

選擇移植開發平臺

Sparc 平臺:這種方法能夠讓 Solaris 開發者輕鬆地實現遷移,將 Linux 應用程序移植到其它目標平臺上。因爲 Sun 提供了公共庫和構建環境,從而將開發在 Linux 和 Solaris 操作環境上兼容的源代碼的過程流水線化,所以第一步是修改 Solaris 平臺上的移植代碼。這些工具包括下面的使用指南:

在 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. 大尾數和小尾數地址
 

數據類型不匹配

當把 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/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章