1. 程式人生 > >Windows向Linux程式碼移植常見問題

Windows向Linux程式碼移植常見問題

前幾天完成了一次Windows向Linux的程式碼移植,由於在Windows上開發時沒有考慮到相容性,所以移植的時候還是碰到了不少的問題,今天專門抽時間把問題和解決方法整理出來,作為經驗,以備將來查閱。

1. 包含的標頭檔案名稱大小寫問題

例如

[plain]  view plain  copy
  1. decode_test_utils.cpp:1:20: fatal error: StdAfx.h: No such file or directory  
  2.  #include "StdAfx.h"  

Windows下VS編譯器對檔名稱的大小寫不敏感,但在Linux下使用gcc或g++編譯器則會報錯,這種錯誤解決方法很簡單,把#include包含的標頭檔案名稱改為與實際名稱字母大小寫一致即可。

2. Windows下的標頭檔案在Linux下不存在

例如,

[plain]  view plain  copy
  1. targetver.h:8:23: fatal error: SDKDDKVer.h: No such file or directory  
  2.  #include <SDKDDKVer.h>  

這裡的SDKDDKVer.h是支援一些Windows API的呼叫的,在VS生成的targetver.h中包含,在Linux下面基本用不到這些。因此,可加入系統判斷,只在Windows下才包含該標頭檔案。

再舉另一個例子:

[plain]  view plain  copy
  1. decode_test_utils.cpp:288:2: error: ‘BITMAPFILEHEADER’ was not declared in this scope  
  2.   BITMAPFILEHEADER bmpheader;    
  3.   ^  
  4. decode_test_utils.cpp:288:19: error: expected ‘;’ before ‘bmpheader’  
  5.   BITMAPFILEHEADER bmpheader;    
  6.                    ^  
  7. decode_test_utils.cpp:289:2: error: ‘BITMAPINFOHEADER’ was not declared in this scope  
  8.   BITMAPINFOHEADER bmpinfo;    
  9.   ^  
  10. decode_test_utils.cpp:289:19: error: expected ‘;’ before ‘bmpinfo’  
  11.   BITMAPINFOHEADER bmpinfo;    
  12.                    ^  
  13. decode_test_utils.cpp:290:10: error: ‘bmpheader’ was not declared in this scope  
  14.   memset(&bmpheader, 0, sizeof(BITMAPFILEHEADER));    
  15.           ^  
  16. decode_test_utils.cpp:291:10: error: ‘bmpinfo’ was not declared in this scope  
  17.   memset(&bmpinfo, 0, sizeof(BITMAPINFOHEADER));    
  18.           ^  
  19. decode_test_utils.cpp:312:26: error: ‘BI_RGB’ was not declared in this scope  
  20.   bmpinfo.biCompression = BI_RGB;    

BITMAPFILEHEADER、BITMAPINFOHEADER等定義在Windows系統下的WinGDI.h裡面,在Linux下則沒有該標頭檔案。我的解決方法是,將程式中用到的結構體、巨集定義從WindGDI中拷貝出來,放在自己新建的標頭檔案mytypedef.h裡面,並將自建的標頭檔案包含在程式碼中。

3.  Linux下同一功能函式的名稱、引數與Windows不一致

例如,

[plain]  view plain  copy
  1. decode_test_utils.cpp:125:24: error: ‘_access’ was not declared in this scope  
  2.  if(_access(sub_path, 0) < 0)  

解決方法是,加入對系統的判斷,win32下呼叫_access和_mkdir,Linux下呼叫access 和mkdir。 相似錯誤還有_stat。

除了函式名稱不一致,有可能函式傳入的引數也不一致,例如mkdir:

[plain]  view plain  copy
  1. decode_test_utils.cpp:136:30: error: too few arguments to function ‘int mkdir(const char*, __mode_t)’  
  2.    mkdir((const char*)sub_path);  

在Windows下,_mkdir形式為:int _mkdir( const char *dirname ),而在Linux下,mkdir不光要傳入需要建立的路徑,而且要傳入新建路徑的許可權,形式為int mkdir(const char *pathname, mode_t mode),mode可以是多個許可權的組合,例如如下語句是為新建的路徑賦予所有人讀、寫、可執行許可權。

mkdir(sub_path,S_IRWXU | S_IRWXG | S_IRWXO); 

4. Linux編譯void main()會報錯

[plain]  view plain  copy
  1. online_test.cpp:305:33: error: ‘::main’ must return ‘int’  
  2.  void main(int argc, char *argv[])  

在Windows VS下,編譯void main()可以通過,但在Linux下面則不支援void型別的main函式,必須要返回int值。

5. 連結錯誤

(1) 

[plain]  view plain  copy
  1. /usr/bin/ld: /tmp/ccH3cL83.o: undefined reference to symbol '[email protected]@GLIBC_2.2.5'  
  2. /usr/lib64/libpthread.so.0: error adding symbols: DSO missing from command line  
  3. collect2: error: ld returned 1 exit status  

解決方法:在Makefile中編譯選項中加入 -lpthread。

(2) 

[plain]  view plain  copy
  1. /usr/bin/ld: /tmp/ccWPCTf3.o: undefined reference to symbol '[email protected]@GLIBC_2.2.5'  
  2. /usr/lib64/libm.so.6: error adding symbols: DSO missing from command line  
  3. collect2: error: ld returned 1 exit status  

解決方法:在編譯選項中加入-lm。

暫時記錄了以上的幾個問題,實際在移植過程中,由於最開始Makefile寫的不好,也出現了不少編譯錯誤,後來完善了Makefile後,一些不必要的錯誤才消失。後面準備寫一篇如何編寫Makefile的文章。