国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Windows下程序向Linux下移植細節(jié)

Windows下程序向Linux下移植實踐

 溫輝敏(wenhm@sina.com)

                                                                    20052 

【摘要】

根據(jù)zxms80項目的會議調(diào)度模塊移植的經(jīng)驗,本文提出了Windows平臺上程序向Linux下移植所碰到的一些典型問題,并舉例給出了相應(yīng)的解決方法,文中還描述了使用pwlib庫時makefile文件的編寫方法,該方法也適用于不使用pwlib庫開發(fā)時的一般情況,供要進行移植的同仁參考之用。

一、問題的提出

    在程序員中有這樣一個說法,若一個程序不能移植到Linux下,那這個程序?qū)⒖床坏轿磥怼?/span>

由于Linux操作系統(tǒng)源碼公開是的,開發(fā)庫等輔助工具都是源碼公開的,這樣就減少了程序的不可預(yù)知性,而且出現(xiàn)錯誤可以大家一起修正、完善,而Windows平臺下所有的操作系統(tǒng)Api就給了個接口,即使出現(xiàn)莫名奇妙的錯誤也只能望著接口興嘆了。再加上Linux操作系統(tǒng)本身和它上面的許多工具軟件是免費的,更是吸引了更多的公司和程序開發(fā)人員將程序開發(fā)轉(zhuǎn)向Linux。

在程序跨平臺的移植過程中,將存在操作系統(tǒng)API的不同、文件名大小寫識別不同、路徑分隔符不同、不同開發(fā)平臺數(shù)據(jù)類型的不一致等較一般性的問題。對于這些一般性的問題怎樣很好的來解決呢?Linux下的工程都是使用makefile文件來管理的,怎樣編寫出相應(yīng)的makefile文件呢?這些問題都是本文后面將要闡述的。

二、解決思路

   本文撰寫的目的是為了提供Windows平臺上程序向Linux下移植所碰到的一些典型問題及相應(yīng)的解決方法,供要進行程序平臺移植的同仁參考之用。

文中還描述了使用pwlib庫時makefile文件的編寫方法,對于使用了pwlib庫進行開發(fā)的程序能快捷的建立makefile工程文件,避免了自己手動書寫makefile的繁雜工作。

特別是<3.2.6可以移植的數(shù)據(jù)類型>一節(jié)中對于不同開發(fā)平臺數(shù)據(jù)類型的不一致提出了一個簡捷通用的解決方法,不用修改源程序中任何代碼即可在Linux下使用Windows開發(fā)平臺上的一些數(shù)據(jù)類型。

三、實踐情況

3.1.Makefile的編寫

       Linux下一般都是使用make工具來管理和編譯一個大的開發(fā)工程的所有源文件,make命令執(zhí)行時,需要一個 Makefile 文件,以告訴make命令需要怎么樣的去編譯和鏈接程序,makefile關(guān)系到了整個工程的編譯規(guī)則。一個工程中的源文件不計其數(shù),其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規(guī)則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進行更復(fù)雜的功能操作,因為makefile就像一個Shell腳本一樣,其中也可以執(zhí)行操作系統(tǒng)的命令。在Windows的一些IDEVC中將自動幫你生成相應(yīng)的makefile,所有這些都是透明的,但在Linux下你就不能不自己寫makefile了,會不會寫makefile,從一個側(cè)面說明了一個人是否具備完成大型工程的能力。

     make工具采用增量編譯的方式,每次只編譯被改動過確實需要編譯的源文件,每次編譯時make工具將自動判斷那些源文件需要重新編譯,當(dāng)一個工程很大而又只改動了很少的幾個源文件,這將節(jié)省很多時間。

具體makefile文件的編寫規(guī)則可以查看makeman info文檔(Linux命令行方式下輸入:man make info make)。makefile文件的編寫規(guī)則很多,重要的是怎樣使用最簡單的方式寫出我們自己需要的makefile文件。

    網(wǎng)上也有很多介紹資料,網(wǎng)上有一篇很好的介紹makefile文件編寫的文章:

下文將著重介紹使用pwlib開發(fā)庫的工程的makefile的編寫,但對于其它工程只需將common.mak文件中對pwlib庫進行編譯的腳本去掉也可適用。

3.1.1使用pwlib開發(fā)庫的工程的makefile的編寫

PWLibPortable Windows Library的縮寫,翻譯為輕便的Windows類庫.PWLib采用C++編寫,設(shè)計初衷是為了能讓Openh323WindowsUnixX-Windows下運行, 不過隨著一步步的完善PWLib已經(jīng)被跨平臺的程序所廣泛采用。

查看Pwlib的主目錄下/samples/hello_world/目錄下例子程序的makefile文件可以發(fā)現(xiàn)該Makefile文件內(nèi)容如下:

# Simple makefile for the hello world program

PROG    = hello

SOURCES = hello.cxx

ifndef PWLIBDIR

PWLIBDIR=$(HOME)/pwlib

endif

include $(PWLIBDIR)/make/ptlib.mak

# End of Makefile

實際上就是使用了Pwlib庫的ptlib.mak文件,編譯時需要的頭文件,相應(yīng)的編譯選項都在ptlib.mak文件中設(shè)置好了。

我們只需在該makefile文件所在目錄下,命令行輸入make all命令即可編譯出程序的Release版本和Debug版本,它們分別放在當(dāng)前目錄的obj_linux_x86_robj_linux_x86_d子目錄下。

下面對該makefile中的內(nèi)容進行解釋:

l         PROG變量為編譯出來的程序名稱。

l         SOURCES變量存儲的為本工程要進行編譯和鏈接的源文件,當(dāng)有多個源文件時可以用空格隔開,雖然文件名可以帶上路徑,但路徑在SOURCES變量中不起作用,實際編譯時對于每個文件它將截掉最后一個”/”字符前面的所有內(nèi)容只保留文件名。

l         PWLIBDIRpwlib的安裝目錄,需要設(shè)置該環(huán)境變量(若要系統(tǒng)每次重啟都自動設(shè)置好該環(huán)境變量則將該環(huán)境變量的設(shè)置放入/etc/profile文件中),若沒設(shè)置好則自動以用戶主目錄\pwlib”作為pwlib的安裝目錄。

3.1.2深入分析ptlib.mak文件

分析ptlib.mak文件,它的內(nèi)容如下;

ifndef PWLIBDIR

PWLIBDIR=$(HOME)/pwlib

endif

 

include $(PWLIBDIR)/make/unix.mak

include $(PWLIBDIR)/make/common.mak

也就是ptlib.mak包含了另兩個文件unix.makcommon.mak文件,其中unix.mak為定義編譯選項變量的文件,編譯規(guī)則放在common.mak文件中。

通過對這兩個文件的分析,歸納出一些我們寫makefile文件要用到的一些變量,列出如下:

l         STDCCFLAGS:所有頭文件的include目錄編譯選項、預(yù)編譯宏定義選項、警告選項、優(yōu)化選項都放在該變量中,各編譯選項之間用空格分開。

l         LDFLAGS:共享庫、靜態(tài)庫搜索目錄設(shè)置放入該變量中。

l         LDLIBS:鏈接時要用的庫的設(shè)置放入該變量中。

l         VPATH_CXX*.cxx源文件的搜索路徑放入該變量中,多個目錄以空格分開,編譯時將首先在makefile所在目錄查找相應(yīng)源文件,沒找到則按照VPATH_CXX中的路徑設(shè)置進行查找。

l         VPATH_C*.c源文件的搜索路徑放入該變量中,多個目錄以空格分開,文件查找順序和VPATH_CXX變量的類似。

3.1.3加入新的編譯規(guī)則

common.mak文件中只對*.c*.cxx的源文件定義了編譯規(guī)則,而一般windows下程序大多都使用了.cpp來作為C++源文件的后綴。

怎樣加入對于.cpp后綴的源文件的編譯規(guī)則呢,這需要修改pwlibcommon.mak文件,具體步驟如下:

       1.加入對于.cpp文件的搜索目錄設(shè)置

vpath %.cxx $(VPATH_CXX)語句后面加入如下語句:

              vpath %.cpp $(VPATH_CXX)

       2.加入對于.cpp文件的編譯規(guī)則

              $(OBJDIR)/%.o : %.cxx語句的前面加入如下語句:

$(OBJDIR)/%.o : %.cpp

       @if [ ! -d $(OBJDIR) ] ; then mkdir -p $(OBJDIR) ; fi

       $(CPLUS) $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) $(STDCXXFLAGS) -x c++ -c $< -o $@

       3.加入對于.cpp文件的.o文件(目標代碼文件)的命名規(guī)則

       SRC_OBJS := $(SRC_OBJS:.cxx=.o)語句后面加入如下語句

SRC_OBJS := $(SRC_OBJS:.cpp=.o)

       4.加入對于.cpp文件的.dep文件(依賴文件)的命名規(guī)則

       SRC_DEPS := $(SRC_DEPS:.cxx=.dep)語句后面加入如下語句

SRC_DEPS := $(SRC_DEPS:.cpp=.dep)

       5.加入對于.cpp文件生成.dep文件的生成規(guī)則,加入如下語句:

       $(DEPDIR)/%.dep : %.cxx語句前面加入如下語句

$(DEPDIR)/%.dep : %.cpp

       @if [ ! -d $(DEPDIR) ] ; then mkdir -p $(DEPDIR) ; fi

       @printf %s $(OBJDIR) > $@

       $(CPLUS) $(STDCCFLAGS:-g=) -M $< >> $@

3.1.4一個makefile范例

 

 


3.2.程序的移植

    進行程序移植的過程中碰到的問題較多,但大都主要集中在文件名大小寫、路徑分隔符、數(shù)據(jù)類型等方面。

3.2.1LinuxWindows操作系統(tǒng)API差異

Windows下基于MFCAPI、基于消息的API、基于注冊表的API等在Linux下都是沒有的,由于文件系統(tǒng)的差異,和文件系統(tǒng)相關(guān)的API也是不可以移植的。

解決方法:程序中不使用上面所列的不可移植的操作系統(tǒng)API,通過使用開源庫如PWLIBACE中的可移植的類來實現(xiàn)所需的功能。

如:

SYSTEMTIME pTime;

GetLocalTime(&pTime);       //windows獨有的API

sprintf(sTemp,"[%02.2d-%02.2d-%02.2d]%02.2d:%02.2d:%02.2d %s(%d)",

pTime.wYear,pTime.wMonth,pTime.wDay,

                  pTime.wHour,pTime.wMinute,pTime.wSecond,file,lineNum);

改為:

使用pwlibPTime來實現(xiàn)

PTime curTime;                   //pwlib中可以跨平臺使用的時間類

sprintf(sTemp,"[%02.2d-%02.2d-%02.2d]%02.2d:%02.2d:%02.2d %s(%d)",

                   curTime.GetYear(), curTime.GetMonth(), curTime.GetDay(),

                            curTime.GetHour(), curTime.GetMinute(), curTime.GetSecond(), file, lineNum);

 

3.2.2開發(fā)庫函數(shù)的差異

    一些函數(shù)在Windows操作系統(tǒng)的VC開發(fā)庫中有,但Linux下的GLIB C開發(fā)庫中沒有或是名字不一樣。

      Windows下有而Linux下開發(fā)庫沒有的函數(shù),例如: itoa(int, char *, int)、ltoa(long, char *, int)ultoa(unsigned long, char *, int)等。

解決方法1:通過編寫相應(yīng)的代碼來實現(xiàn)該函數(shù)。

解決方法2:使用Linux下含有類似功能的函數(shù)來替換,如itoa()、ltoa()等系列的函數(shù)都可以通過sprintf()snprintf()函數(shù)來替換

替換例子1

       ltoa( confHistb.conflong, caTemp, 10 );

可以替換為:

#ifdef WIN32    //windows

                            ltoa( confHistb.conflong, caTemp, 10 );

#else                             //linux

                   sprintf(caTemp, "%d", confHistb.conflong);

#endif    

或直接用sprintf(caTemp, "%d", confHistb.conflong);替換即可。

2WindowsSleep()函數(shù)對應(yīng)的Linux下函數(shù)為sleep()usleep(),要特別注意的是WindowsSleep()為休眠多少毫秒,而sleep()usleep()分別為休眠多少秒和微妙,所以替換的時候不僅要注意函數(shù)的名稱不同還要注意單位的不一致。

3Windowsstricmp()函數(shù)在Linux下對應(yīng)的為strcasecmp()函數(shù),可以通過宏定義來區(qū)分不同平臺的代碼,也可以在WINTYPES.H文件中加入如下語句:

#define stricmp strcasecmp

通過宏替換來實現(xiàn)。

3.2.3Linux下對文件名大小寫敏感

Windows下由于操作系統(tǒng)對文件名大小寫不明感,#include語句中文件名的大小寫均可以,而Linux操作系統(tǒng)是對文件名大小寫敏感的,#include語句中的文件名必須和原文件名大小寫一模一樣才能找到。

解決方法:#include語句中文件名和原文件名大小寫不一致的全部要修改為一致。

 

3.2.4Linux下路徑中各目錄的分隔符只能為”/”

Windows下路徑的分隔符使用”\”和“/“均可,而Linux下只能使用”\“來作為路徑中個目錄的分隔符。

解決方法:#include語句中路徑的分隔符全部使用“/”

 

數(shù)據(jù)類型

3.2.5程序里不能使用Windows特有的數(shù)據(jù)類型

例如:FAR PASCAL、HWND、HMENU、HFONT等,因為這些類型在Linux下無法找到替代它們的類型,必然導(dǎo)致程序的不可移植。

3.2.6可以移植的數(shù)據(jù)類型

有些數(shù)據(jù)類型是可以通過類型定義來實現(xiàn)的,如CHAR、LONG、INTINT32、FLOAT 、BOOL、VOID、UCHAR、CONST、WINAPI、CALLBACK等,這些類型在Windows下的VC開發(fā)庫中定義了,但在Linux下沒有。

解決方法:可以通過創(chuàng)建一個 WINTYPES.H的頭文件,將這些類型定義放在該文件里。

編譯時加上“-include  PATH/WTYPES.H”編譯選項即可不用在代碼中加入任何“#include”語句而使用WINTYPES.H中的類型,這里的PATHWINTYPES.H文件所在的路徑。示例代碼如下:

typedef float FLOAT;

typedef char CHAR;

#define VOID         void

#define WINAPI      __attribute__((stdcall))

#define CALLBACK  __attribute__((stdcall))

3.2.7一些宏定義Windows下有而Linux下沒有

有些宏定義如:

#define MAKEWORD(a, b)      ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))

#define MAKELONG(a, b)      ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))

#define LOWORD(l)           ((WORD)(l))

#define HIWORD(l)           ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))

#define LOBYTE(w)           ((BYTE)(w))

#define HIBYTE(w)           ((BYTE)(((WORD)(w) >> 8) & 0xFF))

等在Windows下有,而Linux下沒有。

解決方法:在使用到這類宏定義時將相應(yīng)的宏定義放入WINTYPES.H文件中即可。

 

3.2.8同名但結(jié)構(gòu)不同的數(shù)據(jù)類型

Winowsstruct in_addr結(jié)構(gòu)定義如下:

struct in_addr {

        union {

                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;

                struct { u_short s_w1,s_w2; } S_un_w;

                u_long S_addr;

        } S_un;

};

      Linuxstruct in_addr結(jié)構(gòu)定義為:

struct in_addr

{

__u32 s_addr;

};

解決方法:因在使用這種類型的時候不同操作系統(tǒng)下面的代碼不一樣,要使用宏定義將不同操作系統(tǒng)下的代碼分開。

例:

#ifdef WIN32

              ipAdd.S_un.S_addr = address_ip;

#else

              ipAdd.s_addr = address_ip;

#endif

宏定義WIN32WindowsVC編譯器自帶的一個宏定義,該宏定義在Linux下不存在所以在Windows下和Linux下使用的代碼是不同的。

3.2.9Windows下的頭文件Linux下名字不同

有些頭文件在Windows下和Linux下名字不一樣,如strstrea.hLinux下對應(yīng)的文件名為sstream strstream。

解決方法:當(dāng)發(fā)現(xiàn)以后寫頭文件在Linux下找不到時,查看下是否Linux相應(yīng)頭文件的名字不一樣,是否開發(fā)庫的不同版本頭文件不一樣,有些開發(fā)庫如STL開發(fā)庫由于不斷升級會淘汰一些頭文件而使用其它的頭文件來進行替代。

       所以

#include <strstrea.h>

修改為:

#ifdef WIN32 //windows

       #include <strstrea.h>

#else              //linux

       #include <sstream>

       #include <strstream>

#endif

 

3.2.10WindowsLinux下編譯器對語言理解的差異

由于編譯器的差異也導(dǎo)致要將不同平臺下的代碼要使用宏定義來區(qū)分開,如:

for(int i=0; i< iSize; i++)

語句定義的變量iWindows下該變量將在for語句執(zhí)行完后仍有效,而在Linux下變量i只在for語句內(nèi)部有效出了for語句的范圍后就失效了。

解決方法:這種情況是由于編譯器對語言語義上的理解不同導(dǎo)致的,只要看下編譯的錯誤信息就可以很快解決,要注意的時要使用宏定義來包含不同平臺之間的代碼。

 

3.2.11Linux下編譯器檢查比WindowsVC的編譯器檢查更嚴格

Linux下的編譯器檢查比Windows下更嚴格,特別是類型轉(zhuǎn)換檢查方面,如:

char strTime=2004/01/02 14:00:00;

PTime starttime = strTime;

windows下編譯可以通過,但由于PTime類只有PTime(const PString & str  )構(gòu)造函數(shù),而strTimechar[]類型,雖然在Windows下可以編譯通過但在Linux下編譯通不過

解決方法:增加強制類型轉(zhuǎn)換即可。

char strTime=2004/01/02 14:00:00

PTime starttime = Pstring(strTime);

這方面的代碼編譯錯誤只要看下編譯的錯誤信息也可以很快就解決。由于是Linux下編譯器檢查比Windows下嚴格,所以只要能保證在Linux下編譯通過Windows下肯定也能編譯通過不用使用宏定義來包含不同平臺之間的代碼。

 

四、效果評價

以上所列移植的問題是在進行zxms80項目 CSS(會議調(diào)度模塊)移植時碰到的,CSS模塊采用pwlibptlib,mak文件來創(chuàng)建makefile文件,采用了前面所列的解決方法來解決碰到的問題,整個移植過程花了一個月左右。(CSS代碼大概40000行左右,使用了Pwlib庫、ACE+TAO庫、Libodbc++)

通過借用pwlibptlib.mak文件可以快捷的創(chuàng)建自己的makefile文件,創(chuàng)建出來的makefile簡單易讀。

Windows下程序往Linux下移植主要就是會碰到上面列出來的一些問題,文中為每類問題都進行了舉例和提供了相應(yīng)的解決方案希望對要進行程序平臺移植的同仁會有所裨益。

五、推廣建議

并不是任何程序都可以輕松進行移植的,只有在設(shè)計、開發(fā)初期考慮到程序的可移植性,使用了可移植的開發(fā)庫來進行開發(fā),盡量避免使用和平臺相關(guān)的代碼,這樣的程序才能快速、方便的進行移植。

文中描述的移植中碰到的問題和解決方法對于Windows平臺下C/C++程序向Linux平臺移植均適用,特別是對于使用了pwlib庫來進行開發(fā)的程序提出了快捷的建立makefile工程文件的方法,并對makefile文件的關(guān)鍵部分進行了解釋,最后給出了一個makefile文件的完整范例。即使是沒有使用pwlib開發(fā)庫也可以使用pwlib的相應(yīng)make文件來構(gòu)建自己的makefile文件,只是需要將相應(yīng)編譯pwlib庫的那部分腳本(common.mak文件中)屏蔽掉就可用于創(chuàng)建任何工程的makefile文件。

只要使用了可移植的開發(fā)庫來開發(fā)大部分代碼,移植過程還是比較順利的,主要是一些如文件名大小寫、路徑分隔符使用不對等小問題的重復(fù)修正,若是使用了很多和Windows Api相關(guān)的代碼如訪問注冊表、文件操作的Api則要費些功夫來重寫這部分代碼了。

通過對程序進行移植操作,一定更能深刻體會寫代碼時為什么要注意可移植性了,不能一味的為了方便使用簡單而不可移植的方法來實現(xiàn)。


參考資料

1.       王華等Linux從入門到精通,中國水利水電出版社20009月第一版北京第一次印刷。

2.       Stephen Figgins, Ellen Siever, Aaron Weber,LPI Linux Certification in a Nutshell,Publisher : O'ReillyJune 2003。

http://www.us1.openh323.org/。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
如何在windows環(huán)境下配置libjpeg
在VS2010下編譯libjpeg及其應(yīng)用例子
MMIF在Linux下的下載安裝
VisualGDB安裝使用
“C語言” 讀書札記(六)之[Linux下C語言編程環(huán)境Make命令和Makefile]
LFS中幾個sed語句的作用探討
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服