Windows向Linux程式碼移植常見問題
前幾天完成了一次Windows向Linux的程式碼移植,由於在Windows上開發時沒有考慮到相容性,所以移植的時候還是碰到了不少的問題,今天專門抽時間把問題和解決方法整理出來,作為經驗,以備將來查閱。
1. 包含的標頭檔案名稱大小寫問題
例如
[plain] view plain copy- decode_test_utils.cpp:1:20: fatal error: StdAfx.h: No such file or directory
- #include "StdAfx.h"
Windows下VS編譯器對檔名稱的大小寫不敏感,但在Linux下使用gcc或g++編譯器則會報錯,這種錯誤解決方法很簡單,把#include包含的標頭檔案名稱改為與實際名稱字母大小寫一致即可。
2. Windows下的標頭檔案在Linux下不存在
例如,
[plain] view plain copy- targetver.h:8:23: fatal error: SDKDDKVer.h: No such file or directory
- #include <SDKDDKVer.h>
這裡的SDKDDKVer.h是支援一些Windows API的呼叫的,在VS生成的targetver.h中包含,在Linux下面基本用不到這些。因此,可加入系統判斷,只在Windows下才包含該標頭檔案。
再舉另一個例子:
[plain] view plain copy- decode_test_utils.cpp:288:2: error: ‘BITMAPFILEHEADER’ was not declared in this scope
- BITMAPFILEHEADER bmpheader;
- ^
- decode_test_utils.cpp:288:19: error: expected ‘;’ before ‘bmpheader’
- BITMAPFILEHEADER bmpheader;
- ^
- decode_test_utils.cpp:289:2: error: ‘BITMAPINFOHEADER’ was not declared in this scope
- BITMAPINFOHEADER bmpinfo;
- ^
- decode_test_utils.cpp:289:19: error: expected ‘;’ before ‘bmpinfo’
- BITMAPINFOHEADER bmpinfo;
- ^
- decode_test_utils.cpp:290:10: error: ‘bmpheader’ was not declared in this scope
- memset(&bmpheader, 0, sizeof(BITMAPFILEHEADER));
- ^
- decode_test_utils.cpp:291:10: error: ‘bmpinfo’ was not declared in this scope
- memset(&bmpinfo, 0, sizeof(BITMAPINFOHEADER));
- ^
- decode_test_utils.cpp:312:26: error: ‘BI_RGB’ was not declared in this scope
- bmpinfo.biCompression = BI_RGB;
BITMAPFILEHEADER、BITMAPINFOHEADER等定義在Windows系統下的WinGDI.h裡面,在Linux下則沒有該標頭檔案。我的解決方法是,將程式中用到的結構體、巨集定義從WindGDI中拷貝出來,放在自己新建的標頭檔案mytypedef.h裡面,並將自建的標頭檔案包含在程式碼中。
3. Linux下同一功能函式的名稱、引數與Windows不一致
例如,
[plain] view plain copy- decode_test_utils.cpp:125:24: error: ‘_access’ was not declared in this scope
- if(_access(sub_path, 0) < 0)
解決方法是,加入對系統的判斷,win32下呼叫_access和_mkdir,Linux下呼叫access 和mkdir。 相似錯誤還有_stat。
除了函式名稱不一致,有可能函式傳入的引數也不一致,例如mkdir:
[plain] view plain copy- decode_test_utils.cpp:136:30: error: too few arguments to function ‘int mkdir(const char*, __mode_t)’
- 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- online_test.cpp:305:33: error: ‘::main’ must return ‘int’
- void main(int argc, char *argv[])
在Windows VS下,編譯void main()可以通過,但在Linux下面則不支援void型別的main函式,必須要返回int值。
5. 連結錯誤
(1)
[plain] view plain copy- /usr/bin/ld: /tmp/ccH3cL83.o: undefined reference to symbol '[email protected]@GLIBC_2.2.5'
- /usr/lib64/libpthread.so.0: error adding symbols: DSO missing from command line
- collect2: error: ld returned 1 exit status
解決方法:在Makefile中編譯選項中加入 -lpthread。
(2)
[plain] view plain copy- /usr/bin/ld: /tmp/ccWPCTf3.o: undefined reference to symbol '[email protected]@GLIBC_2.2.5'
- /usr/lib64/libm.so.6: error adding symbols: DSO missing from command line
- collect2: error: ld returned 1 exit status
解決方法:在編譯選項中加入-lm。
暫時記錄了以上的幾個問題,實際在移植過程中,由於最開始Makefile寫的不好,也出現了不少編譯錯誤,後來完善了Makefile後,一些不必要的錯誤才消失。後面準備寫一篇如何編寫Makefile的文章。