Solaris 被認(rèn)為是風(fēng)格與 Linux™ 最為接近的一種 UNIX®,但是對(duì)于程序的遷移來(lái)說(shuō),它們?cè)谥T如內(nèi)存映射、線程以及對(duì)自然語(yǔ)言的支持等領(lǐng)域還是有很大區(qū)別的。這個(gè)移植指南可以為您在計(jì)劃將程序移植到 Linux/x86 上時(shí)提供一些建議,并且?guī)椭斫忾_(kāi)發(fā)環(huán)境和體系架構(gòu)之間的區(qū)別。
在各種風(fēng)格的 UNIX 中,Solaris 被認(rèn)為與 Linux 的風(fēng)格最為接近。因此在開(kāi)始將大型的基于 Unix 的應(yīng)用程序移植到 Linux 上之前,首先要從 Solaris 中挑選出那些依賴于操作系統(tǒng)的代碼。即便如此,在那些依賴于體系架構(gòu)的領(lǐng)域、內(nèi)存映射、線程或一些特殊的領(lǐng)域(例如系統(tǒng)管理和自然語(yǔ)言的支持),它們之間還是有差異的。
本文對(duì)這些差異進(jìn)行了討論,并加以對(duì)比,從而能夠?qū)δ鷱倪\(yùn)行在 32/64 位 SPARC 體系架構(gòu)上的 Solaris 遷移到運(yùn)行在 x86 體系架構(gòu)上的 Linux 提供一些幫助。對(duì)于 Solaris 來(lái)說(shuō),這種討論是基于版本 8 及更新的版本的。對(duì)于 Linux 來(lái)說(shuō),這種討論著重于那些在基于 x86 處理器的服務(wù)器上可用的發(fā)行版本:SUSE LINUX Enterprise Server 9 和 Red Hat Enterprise Linux AS V3 或 V4。
本文內(nèi)容包括:
- 移植規(guī)劃
- 開(kāi)發(fā)環(huán)境(編譯器,make 工具,等等)
- 依賴于體系架構(gòu)或系統(tǒng)的區(qū)別
移植規(guī)劃
下面 6 個(gè)步驟為從 SPARC 平臺(tái)上的 Solaris 成功遷移到 x86 平臺(tái)上的 Linux 提供了一個(gè)完整的路線圖。如果您曾經(jīng)將應(yīng)用程序從一個(gè)操作系統(tǒng)移植到另外一個(gè)操作系統(tǒng)上,那么這些步驟可能就會(huì)聽(tīng)起來(lái)非常熟悉:
- 準(zhǔn)備
- 環(huán)境和 makefile 的變化
- 編譯器修正
- 測(cè)試和調(diào)試
- 性能優(yōu)化
- 打包并分發(fā)
步驟 1. 準(zhǔn)備
正確準(zhǔn)備的關(guān)鍵是了解某些領(lǐng)域之間的差異,例如:
- 系統(tǒng)調(diào)用
- 文件系統(tǒng)的支持
- 依賴于機(jī)器的代碼
- 線程
- 內(nèi)存映射
- 系統(tǒng)調(diào)用
- Endianness
在移植程序時(shí),要確保有關(guān)的第三方包在目標(biāo)平臺(tái)上都是可用的。對(duì)于 32 位的應(yīng)用程序來(lái)說(shuō),要考慮是否有必要遷移到 64 位的版本。還要確定在目標(biāo)平臺(tái)上使用哪種編譯器。在基于 x86 的 Linux 平臺(tái)上,可以使用 gcc 作為編譯器。
步驟 2. 環(huán)境和 makefile 的變化
在這個(gè)步驟中,您將設(shè)置開(kāi)發(fā)環(huán)境,這包括確定環(huán)境變量,修改 makefile,并對(duì)環(huán)境進(jìn)行必要的修改。在這個(gè)步驟之后,您應(yīng)該準(zhǔn)備好開(kāi)始編譯自己的應(yīng)用程序了。
在準(zhǔn)備好進(jìn)入下一個(gè)步驟之前,這個(gè)步驟可能會(huì)需要幾次反復(fù)。
步驟 3. 編譯
在這個(gè)步驟中,您將修正一些編譯錯(cuò)誤,鏈接錯(cuò)誤,諸如此類。在能夠得到一個(gè)干凈的編譯產(chǎn)品之前,這個(gè)步驟可能需要多次反復(fù)。
步驟 4. 測(cè)試和調(diào)試
在應(yīng)用程序成功編譯之后,要對(duì)其進(jìn)行測(cè)試,看看是否存在運(yùn)行時(shí)錯(cuò)誤。在測(cè)試時(shí),有些領(lǐng)域可能會(huì)涉及客戶機(jī)/服務(wù)器的通信、數(shù)據(jù)交換格式、數(shù)據(jù)編碼的轉(zhuǎn)換(例如從單字節(jié)編碼轉(zhuǎn)換為多字節(jié)編碼)以及數(shù)據(jù)的永久保存。
步驟 5. 性能優(yōu)化
現(xiàn)在移植后的代碼可以在目標(biāo)平臺(tái)上運(yùn)行了。監(jiān)視其性能,確保所移植的代碼可以如我們所期望的一樣工作;如果不能,就需要對(duì)性能進(jìn)行優(yōu)化。
有兩個(gè)很好的性能分析工具:Performance Inspector 和 OProfile。Performance Inspector 提供了一組工具來(lái)判斷 Linux 上的應(yīng)用程序中的性能問(wèn)題。從 2.6 版本的內(nèi)核開(kāi)始,OProfile 已經(jīng)成為對(duì)代碼進(jìn)行優(yōu)化分析的推薦工具。OProfile 在 RHEL4 中也可以使用。(有關(guān)這些工具的更多信息,請(qǐng)參閱 參考資料。)
步驟 6. 打包和分發(fā)
您要將所生成的代碼分發(fā)給其他人嗎?如果需要,就要確定打包的方法。
Linux 提供了幾種方法對(duì)應(yīng)用程序進(jìn)行打包,例如 tarball、自行安裝的 shell 腳本或 RPM。RPM 是 Linux 上廣泛使用的包管理系統(tǒng)。Solaris使用 pkgadmin 作為自己的包管理器。
在 Solaris 中,pkgadmin 所使用的包規(guī)范模板文件與 RPM 所使用的規(guī)范文件不同 —— 將打包信息從模板文件轉(zhuǎn)換成規(guī)范文件需要很多的努力。使用諸如 InstallShield for Multiplatforms(ISMP)之類的軟件包可以在這兩種平臺(tái)上產(chǎn)生通用的打包軟件,從而減少移植的努力。通過(guò)使用 ISMP,應(yīng)用程序開(kāi)發(fā)就可以使用一個(gè)跨平臺(tái)的通用規(guī)范文件。
開(kāi)發(fā)環(huán)境
現(xiàn)在讓我們來(lái)看一下 Solaris 和 Linux 開(kāi)發(fā)環(huán)境的一些差異,包括以下內(nèi)容:
- Makefile
- 編譯器和鏈接選項(xiàng)
- 32 位到 64 位的移植考慮
GNU Make 和 Solaris Make 的比較
如果您在原有的平臺(tái)上使用的是 Solaris 的 Make,那么要在 Linux 上使用 GNU Make,就需要對(duì) makefile 進(jìn)行修改。AIX 5L Porting Guide (請(qǐng)參閱 參考資料 中的鏈接)的第 6 章詳細(xì)介紹了二者之間的區(qū)別。
編譯器和鏈接選項(xiàng)
正如前面介紹的一樣,對(duì) x86 上的 Linux 可用的編譯器是 GNU GCC。下表是 SUN Studio C/C++ 編譯器所廣泛使用的一些編譯選項(xiàng),以及 GNU GCC 中的等價(jià)選項(xiàng)。
表 1. Solaris 到 Linux 的等價(jià)編譯器選項(xiàng)
| SUN Studio | GNU GCC | 說(shuō)明 |
| -# | -v | 通知編譯器在編譯的過(guò)程中顯示信息。 |
| -### | -### | 跟蹤編譯過(guò)程,而不會(huì)真正調(diào)用任何操作。 |
| -Bstatic | -static | 讓鏈接編輯器只查找那些名為 libx.a 的文件。 |
| -Bdynamic | (缺省值) | 通知鏈接編輯器在給定 lx 選項(xiàng)時(shí),首先查找名為 libx.so 的文件,然后查找名為 libx.a 的文件。 |
| -G | -shared | 產(chǎn)生一個(gè)共享對(duì)象,而不是一個(gè)動(dòng)態(tài)鏈接的可執(zhí)行程序。 |
| -xmemalign | -malign-natural, | 指定假定內(nèi)存邊界對(duì)齊的最大值,以及訪問(wèn)不對(duì)齊的數(shù)據(jù)時(shí)的行為。 |
| -xO1, -xO2, -xO3, -xO4, -xO5 | -O, -O2, -O3 | 在編譯過(guò)程中選擇對(duì)代碼進(jìn)行優(yōu)化的級(jí)別。有點(diǎn)類似于 O2。 |
| -KPIC | -fPIC | 生成位置無(wú)關(guān)的代碼,用于大型共享庫(kù)。 |
| -Kpic | -fpic | 生成位置無(wú)關(guān)的代碼,用于小型共享庫(kù)。 |
| -mt | -pthread | 為多線程代碼進(jìn)行編譯和鏈接。 |
| -R dirlist | -Wl, -rpath, dirlist | 將動(dòng)態(tài)鏈接庫(kù)的搜索路徑編譯到可執(zhí)行文件中。 |
| -xarch | -mcpu, -march | 指定目標(biāo)體系架構(gòu)的指令集。 |
表 2 解釋了不同風(fēng)格的 Linux 上的不同級(jí)別的 C 編譯器之間的區(qū)別。
表 2. 不同級(jí)別的 C 編譯器之間的區(qū)別
| 操作系統(tǒng) | 內(nèi)核級(jí) | GCC 級(jí) | Glibc 級(jí) | Gnu binutils 級(jí) | JDK 級(jí) |
| SLES9 | 2.6 | 3.3.3 | 2.3.3 | 2.15.90 | 1.4.2* |
| RHEL3 | 2.4 | 3.2.3 | 2.3.2 | 2.14.90 | 1.4.2 |
| RHEL4 | 2.6 | 3.4.3 | 2.3.4-2 | 2.15.92.0.2-10.EL4 | 1.4.2* |
| Solaris 10 | Solaris 10 | 3.3.2 | 2.2.3 | | 1.4.2 |
注意: * 在 64 位的 IBM JDK 1.4.2 for Linux on x86 中并不支持 LinuxThreads。Java 支持 NPTL 64 位線程庫(kù)。
還有,如果您要在 SLES9 上編譯 C++ 程序,并將其部署到 RHEL4 上,那么就需要使用 compat 庫(kù),它在包 compat-libstdc++-33-3.2.3-47.3.i386.rpm 中。之所以需要這個(gè) compat 庫(kù),是因?yàn)樵?SLES9 和 RHEL4 之間需要不同級(jí)別的 ABI 兼容性。SLES9 遵循 LSB 1.3 標(biāo)準(zhǔn),而 RHEL4 遵循 LSB 2.0 標(biāo)準(zhǔn)。
32 位到 64 位移植的考慮
要將應(yīng)用程序從 32 位環(huán)境移植到 64 位環(huán)境中,您有兩種選擇:
- 讓?xiě)?yīng)用程序可以容許 64 位操作
- 開(kāi)拓目標(biāo)平臺(tái)上的 64 位操作能力
首先,將應(yīng)用程序在一個(gè) 64 位的環(huán)境中使用,然后試圖開(kāi)拓目標(biāo)平臺(tái)的 64 位能力。
盡管 32 位的應(yīng)用程序通常都可以在 64 位的目標(biāo)平臺(tái)上很好地運(yùn)行,但是在 64 位環(huán)境中啟用應(yīng)用程序也是非常重要的,因?yàn)橛行┑谌降漠a(chǎn)品會(huì)以 64 位模式啟動(dòng),而不提供 32 位版本的庫(kù)對(duì)象。
在遷移到 64 位的環(huán)境中時(shí),您需要決定是否繼續(xù)支持該產(chǎn)品的 32 位版本。如果需要支持這兩個(gè)版本,那么就需要適當(dāng)?shù)臅r(shí)間進(jìn)行打包和測(cè)試。
開(kāi)拓 64 位的能力應(yīng)該是在實(shí)現(xiàn)容許 64 位操作之后的下一個(gè)步驟。在開(kāi)始這種嘗試之前,應(yīng)該仔細(xì)衡量一下開(kāi)拓 64 位能力的優(yōu)點(diǎn)。
應(yīng)用程序從 32 位到 64 位的遷移這個(gè)主題在很多出版物中已經(jīng)進(jìn)行了介紹(例如 參考資料 中列出的 AIX 5L Porting Guide 的第 3 章)。
體系架構(gòu)和系統(tǒng)特有的區(qū)別
現(xiàn)在,讓我們來(lái)看一下 Solaris 和 x86 上的 Linux 之間一些特定于體系架構(gòu)和系統(tǒng)的區(qū)別,包括:基本的數(shù)據(jù)類型,內(nèi)核參數(shù)的設(shè)置,體系架構(gòu)特有的區(qū)別,endianness,系統(tǒng)調(diào)用,信號(hào),數(shù)據(jù)類型,以及線程庫(kù)。
參考資料 提供了在進(jìn)行大型的移植嘗試時(shí),需要考慮的一個(gè)可行的檢查清單。
基本的數(shù)據(jù)類型和對(duì)齊方式
在一個(gè)系統(tǒng)中有兩種不同類型的數(shù)據(jù)類型:基本數(shù)據(jù)類型(basic data type)和派生數(shù)據(jù)類型(derived data types)。
基本數(shù)據(jù)類型 是由 C 和 C++ 語(yǔ)言規(guī)范所定義的所有數(shù)據(jù)類型。表 3 對(duì) x86 上的 Linux 和 SPARC 上的 Solaris 這兩者的基本數(shù)據(jù)類型進(jìn)行了比較。
表 3. 比較 Linux 和 Solaris 的基本數(shù)據(jù)類型
| Linux(x86) | | Solaris(SPARC) |
| 基本類型 | ILP32 (大。 (單位為字節(jié)) | LP64 (用于基于 IA64 的系統(tǒng)) (大。 (單位為字節(jié)) | ILP32 (大。 (單位為字節(jié)) | LP64 (大小) (單位為字節(jié)) |
| char | 1 | 1 | 1 | 1 |
| short | 2 | 2 | 2 | 2 |
| Int | 4 | 4 | 4 | 4 |
| float | 4 | 4 | 4 | 4 |
| long | 4 | 8 | 4 | 8 |
| pointer | 4 | 8 | 4 | 8 |
| long long | 8 | 8 | 8 | 8 |
| double | 8 | 8 | 8 | 8 |
| long double | 12 | 16 | 16 | 16 |
在兩個(gè)平臺(tái)之間或 32 位與 64 位模式之間移植應(yīng)用程序時(shí),您需要考慮不同環(huán)境中對(duì)齊設(shè)置之間的區(qū)別,從而避免出現(xiàn)性能降低和數(shù)據(jù)崩潰的危險(xiǎn)。
表 4 介紹了 x86 上的 Linux 中以字節(jié)為單位的對(duì)齊值。
表 4. x86 上的 Linux 中的對(duì)齊值(以字節(jié)為單位)
| 數(shù)據(jù)類型 | Linux IA-32 (ILP32) | Linux IA-64 (LP64) |
| Bool | 1 | 1 |
| Char | 1 | 1 |
| wchar_t | 4 | 4 |
| int | 4 | 4 |
| Short | 2 | 2 |
| long | 4 | 8 |
| long long | 8 | 8 |
| Float | 4 | 4 |
| Double | 4 | 8 |
| long double | 4* | 16 |
注意: 對(duì)齊取決于所使用的編譯器開(kāi)關(guān)。這些開(kāi)關(guān)控制著“l(fā)ong double”類型的大小。i386 應(yīng)用程序的二進(jìn)制接口規(guī)定這個(gè)大小是 96 位,因此 -m96bit-long-double 在 32 位模式中是默認(rèn)值,F(xiàn)代的體系架構(gòu)(Pentium 及更新的體系架構(gòu))更喜歡將“l(fā)ong double”按照 8 字節(jié)或 16 字節(jié)進(jìn)行對(duì)齊。在符合 ABI 規(guī)范的數(shù)組或結(jié)果中,這是不可能的。因此指定一個(gè) -m128bit-long-double 會(huì)將“l(fā)ong double” 按照 16 字節(jié)邊界進(jìn)行對(duì)齊,它會(huì)為“l(fā)ong double”填充 32 位的 0。
系統(tǒng)派生的數(shù)據(jù)類型
派生數(shù)據(jù)類型是已有的基本類型或其他派生類型的一個(gè)派生物或結(jié)構(gòu)。系統(tǒng)派生數(shù)據(jù)類型 可以根據(jù)所采用的數(shù)據(jù)模型(32 位或 64 位)和硬件平臺(tái)而具有不同的字節(jié)大小。
表 5 給出了 Linux 上與 Solaris 上不同的一些派生數(shù)據(jù)類型。
表 5. Solaris 和 Linux 中的派生數(shù)據(jù)類型
| OS | gid_t | mode_t | pid_t | uid_t | wint_t |
| Solaris ILP32 l | long | unsigned long | long | long | long |
| Solaris LP64 | int | unsigned int | int | int | int |
| Linux ILP32 | unsigned int | unsigned int | int | unsigned int | unsigned int |
| Linux LP64 | unsigned int | unsigned int | int | unsigned int | unsigned int |
機(jī)器特有的代碼的例子
在下面這些情況中需要機(jī)器特有的代碼:
在 Linux-x86 平臺(tái)上的堆棧指針可以實(shí)現(xiàn)為:
清單 1. 在 Linux-x86 上獲取堆棧指針
int get_stack(void **StackPtr){ *StackPtr = 0; __asm__ __volatile__ ("movl %%esp, %0": "=m" (StackPtr) ); return(0);}
|
在 Solaris,下面這段示例代碼讓您可以獲取堆棧指針:
清單 2. 在 Solaris 上獲取堆棧指針
.section ".text" .align 8 .global my_stack .type my_stack,2my_stack: ! Save stack pointer through 1st parameter st %sp,[%o0] ! Compute size of frame in return result reg retl sub %fp,%sp,%o0 .size my_stack,(.-my_stack)
|
在 Linux x86 上,您可以使用一個(gè) compare 和 swap 操作來(lái)實(shí)現(xiàn)原子鎖。例如,下面是 Linux x86 上使用 compare 和 swap 操作的一個(gè)簡(jiǎn)單實(shí)現(xiàn):
清單 3. Linux x86 上的 Compare 和 swap 操作
bool_t My_CompareAndSwap(IN int *ptr, IN int old, IN int new){ unsigned char ret; /* Note that sete sets a 'byte' not the word */ __asm__ __volatile__ ( " lock\n" " cmpxchgl %2,%1\n" " sete %0\n" : "=q" (ret), "=m" (*ptr) : "r" (new), "m" (*ptr), "a" (old) : "memory"); return ret;}
|
在 Solaris SPARC 上,加鎖的原子操作可以如下實(shí)現(xiàn):
清單 4. Solaris 上的原子鎖
.section ".text" .align 8 .global My_Ldstub .type My_Ldstub,2My_Ldstub: ldstub [%o0],%o0 ! Atomic load + set sll %o0,24,%o0 ! Zero fill ... retl ! ... result register srl %o0,24,%o0 ! ... and retrn .size My_Ldstub,(.-My_Ldstub)
|
字節(jié)順序(endianness)
由于 SPARC 采用的是 big-endian,而 x86 采用的是 little-endian,因此您需要考慮 endianness 的問(wèn)題。
Endianness 的問(wèn)題在以下這些情況中都變得非常重要:移植客戶機(jī)要在異構(gòu)網(wǎng)絡(luò)環(huán)境中進(jìn)行通信的應(yīng)用程序,將數(shù)據(jù)永久地保存到磁盤(pán)上,產(chǎn)品跟蹤(在 SPARC 平臺(tái)上所生成的跟蹤信息必須能夠在 x86 平臺(tái)上正確地格式化),以及其他相關(guān)領(lǐng)域。IA-64 Linux 內(nèi)核默認(rèn)使用 little-endian,但是也可以使用 big-endian 的字節(jié)順序。
系統(tǒng)調(diào)用
Solaris 系統(tǒng)調(diào)用使用了一種在 Linux 上是不可用的不同的命名和簽名機(jī)制,這在“從 Solaris 向 Linux on POWER 遷移指南” 中已經(jīng)介紹過(guò)了。以下這些系統(tǒng)調(diào)用現(xiàn)在在 RHEL4 中可以使用:
WaitidPutmsgputpmsgGetmsggetpmsg
Curses 庫(kù)
Linux 用于 xurses 庫(kù)的那些庫(kù)函數(shù)比 Solaris 更加類似于 AIX。例如,諸如 addwch 之類的函數(shù)在 Linux 中不受支持。有些函數(shù),例如 mvchgat,在 Solaris 中不可用。當(dāng)您將與 curses 有關(guān)的代碼從 Solaris 移植到 Linux 上時(shí),很多代碼都需要重寫(xiě)。
Terminal IO
Solaris 中的 termio 結(jié)構(gòu)與 Linux 中的這個(gè)結(jié)構(gòu)是不同的。Linux 中的 termio 結(jié)構(gòu)多了幾個(gè)域,您可以使用它們來(lái)設(shè)置輸入和輸出速度。
Linux 中 termio 結(jié)構(gòu)的定義位于 /usr/include/bits/termios.h 文件中,而 Solaris 中 termio 的定義則位于 /usr/include/sys/termios.h 文件中。
IOCTL
執(zhí)行 ioctl 可以使用的選項(xiàng)在 Solaris 和 Linux 中是不同的。例如,要獲得資源的利用情況,您可以向 ioctl 系統(tǒng)調(diào)用傳遞 PIOCUSAGE:
Return_code = ioctl("/proc/<pid>", PIOCUSAGE, &buff) ;
在 Linux 中,您必須直接從 /proc/<pid> 目錄中讀取相關(guān)的文件來(lái)獲得相關(guān)信息,在 Linux 上不能使用 PIOCUSAGE 選項(xiàng)。在這兩種情況中,pid 是正在執(zhí)行命令的當(dāng)前進(jìn)程的進(jìn)程 id。
另外一個(gè)例子是當(dāng)您希望獲取該進(jìn)程的堆信息時(shí)。在 Solaris 中,要獲取堆信息,您可以使用下面的方法:
Return_code = Ioctl("/proc/<pid>",PIOCPSINFO,&psinfo)
在這段代碼中,psinfo 是一個(gè) struct prpsinfo 結(jié)構(gòu);Prpsinfo.pr_size 就給出了該進(jìn)程的堆大小。
在 Linux 中,正在使用的頁(yè)數(shù)可以從 /proc/<pid>/mem 和 /proc/<pid>/stat 中獲得。頁(yè)面大小可以使用系統(tǒng)調(diào)用 getpagesize 獲得。這兩個(gè)值(頁(yè)數(shù)和頁(yè)面大小)的乘積就是堆的當(dāng)前大小。
Getopt
在 Linux 中,只有在設(shè)置了 POSIXLY_CORRECT 環(huán)境變量之后,getopt 調(diào)用才遵循 POSIX 標(biāo)準(zhǔn)。
如果設(shè)置了環(huán)境變量 POSIXLY_CORRECT,那么對(duì)參數(shù)的分析一碰到非選項(xiàng)參數(shù)(以“-”開(kāi)始的參數(shù))就立即停止。 其余的參數(shù)全部被解釋為非選項(xiàng)參數(shù)。
調(diào)用 shell 腳本之間的區(qū)別
如果 shell 腳本使用了 su 命令,就會(huì)派生一個(gè)子 shell。這種行為與 Solaris 不同,在 Solaris 中, su 命令不會(huì)派生一個(gè)新 shell。
如果您在 Linux 上執(zhí)行命令 su - root,那么 ps 命令的輸出就會(huì)如下所示:
30931 pts/4 00:00:00 su31004 pts/4 00:00:00 ksh
|
在這段代碼中,30931 是進(jìn)程 31004 的祖先進(jìn)程。您可能要修改一些受到這種關(guān)系影響的腳本。
重啟動(dòng)時(shí)的設(shè)備處理
從 RHEL4 開(kāi)始,Linux 就采用了熱插拔子系統(tǒng) udev 的概念。它提供了可配置的動(dòng)態(tài)設(shè)備命名的支持。設(shè)備配置是在每次重新啟動(dòng)時(shí)動(dòng)態(tài)構(gòu)建的。
例如,如果您有一個(gè)新目錄 /dev/dsk,那么系統(tǒng)可能并不知道它的存在,這個(gè)目錄在重啟之后可能就會(huì)丟失。為了避免 /dev/dsk 目錄丟失的問(wèn)題,可以建立一個(gè) /etc/udev/devices/dsk 目錄,這樣系統(tǒng)在重新啟動(dòng)時(shí)就可以維護(hù)這種信息,因此即使系統(tǒng)重新啟動(dòng)之后,/dev/dsk 也依然會(huì)存在。
內(nèi)核參數(shù)
在 Solaris 中,內(nèi)核參數(shù)可以在 /etc/system 文件中進(jìn)行設(shè)置。在 Linux 中,內(nèi)核參數(shù)可以使用 sysctl 系統(tǒng)調(diào)用進(jìn)行修改?梢孕薷牡膮(shù)在 /proc/sys/kernel 中都可以看到,procfs 的支持對(duì)于 sysctl 正常工作來(lái)說(shuō)是必需的。
信號(hào)
信號(hào)之間的區(qū)別在“Technical guide for porting applications from Solaris to Linux”中已經(jīng)詳細(xì)介紹過(guò)了。其他值得注意的一些區(qū)別是 Solaris 有 38 個(gè)信號(hào),而 Linux 使用了 31 個(gè)信號(hào),而且 sigaction 結(jié)構(gòu)也不相同。例如,在 Linux 中,sigaction 接口如下所示:
清單 5. Linux 中的 sigaction 結(jié)構(gòu)
struct sigaction { /* Signal handler. */#ifdef __USE_POSIX199309 union { /* Used if SA_SIGINFO is not set. */ __sighandler_t sa_handler; /* Used if SA_SIGINFO is set. */ void (*sa_sigaction) (int, siginfo_t *, void *); } __sigaction_handler;# define sa_handler __sigaction_handler.sa_handler# define sa_sigaction __sigaction_handler.sa_sigaction#else __sighandler_t sa_handler;#endif /* Additional set of signals to be blocked. */ __sigset_t sa_mask; /* Special flags. */ int sa_flags; /* Restore handler. */ void (*sa_restorer) (void); };
|
在 Solaris 中,sigaction 結(jié)構(gòu)如下所示:
清單 6. Solaris 中的 sigaction 結(jié)構(gòu)
struct sigaction { int sa_flags; union {#ifdef __cplusplus void (*_handler)(int);#else void (*_handler)();#endif#if defined(__EXTENSIONS__) || ((__STDC__ - 0 == 0) && \ !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || \ (_POSIX_C_SOURCE > 2) || defined(_XPG4_2) void (*_sigaction)(int, siginfo_t *, void *);#endif } _funcptr; sigset_t sa_mask;#ifndef _LP64 int sa_resv[2];#endif};
|
由于所支持的信號(hào)個(gè)數(shù)不同,siginfo_t 結(jié)構(gòu)也不相同。對(duì)于 Linux,這可以在 /usr/include/bits/signal.h 文件中找到;對(duì)于 Solaris,這可以在 /usr/include/sys/siginfo.h 文件中找到。
線程支持和 IPC
有關(guān) Linux on POWER 與 Solaris 之間進(jìn)行移植的出版物已經(jīng)介紹了 Solaris 線程與 Linux 的 POSIX 線程(由 NPTL 庫(kù)提供)之間的區(qū)別。
我的經(jīng)驗(yàn)是,如果應(yīng)用程序早已在 Solaris 上就使用了 POSIX 線程,那么它們移植到使用基于 NPTL 線程的 Linux 上就非常簡(jiǎn)單。在 Linux 上還可以利用一些新特性,例如進(jìn)程共享互斥鎖,因此 Solaris 中使用 pthread 互斥鎖和條件變量的那些有關(guān) IPC 機(jī)制的代碼在 Linux 中都可以使用。
自然語(yǔ)言的支持
在 Solaris 中對(duì)于自然語(yǔ)言的支持的代碼也與 Linux 中可能會(huì)有所不同,或者它們只是名字有所不同而已。在 Solaris 中大部分的 locales 和代碼頁(yè)在 Linux 中都有對(duì)應(yīng)的內(nèi)容。
結(jié)束語(yǔ)
從 Solaris 到 x86 上的 Linux 的移植工作在大部分情況中只是一個(gè)重新編譯的過(guò)程,或者對(duì)編譯器/鏈接器開(kāi)關(guān)稍微進(jìn)行一些修改。有時(shí)可能需要對(duì)某些平臺(tái)特有的內(nèi)容進(jìn)行一些修改,例如加鎖、內(nèi)存映射、線程,等等。您應(yīng)該了解一下這些差異,并對(duì)移植好好進(jìn)行一下規(guī)劃,從而減少移植所需要的時(shí)間。