C/C++編譯器的一些易混淆概念,總結(jié)一下。
關(guān)于什么是Unix-like操作系統(tǒng),常見操作系統(tǒng)間差異,什么是操作系統(tǒng)接口等等,請參考《操作系統(tǒng)寶鑒》。
C/C++編譯器有哪些?
首先是如雷貫耳的這幾位仁兄,MSVC、GCC、Cygwin、MingW(Cygwin和MingW的英文發(fā)音),另外還有些小眾和新秀,像ICC(Intel C/C++ Compiler)、BCC(Borland C/C++ Compiler,快銷聲匿跡了)、RVCT(ARM的匯編/C/C++編譯器,內(nèi)置在ARM的IDE——RVDS中)、Pgi編譯器……其實(shí)有一大串,我們只要熟悉常用的最強(qiáng)大的幾款就可以了。
主流C/C++編譯器|編譯環(huán)境簡介
MSVC
MSVC是微軟Windows平臺Visual Studio自帶的C/C++編譯器。
優(yōu)點(diǎn):對Windows平臺支持好,編譯快。
缺點(diǎn):對C++的新標(biāo)準(zhǔn)支持得少。
GCC
GCC原名GNU C Compiler,后來逐漸支持更多的語言編譯(C++、Fortran、Pascal、Objective-C、Java、Ada、Go等),所以變成了GNU Compiler Collection(GNU編譯器套裝),是一套由GNU工程開發(fā)的支持多種編程語言的編譯器。GCC是自由軟件發(fā)展過程中的著名例子,由自由軟件基金會以GPL協(xié)議發(fā)布,是大多數(shù)類Unix(如Linux、BSD、Mac OS X等)的標(biāo)準(zhǔn)編譯器,而且適用于Windows(借助其他移植項(xiàng)目實(shí)現(xiàn)的,比如MingW、Cygwin等)。GCC支持多種計(jì)算機(jī)體系芯片,如x86、ARM,并已移植到其他多種硬件平臺。
優(yōu)點(diǎn):類Unix下的標(biāo)準(zhǔn)編譯器,支持眾多語言,支持交叉編譯。
缺點(diǎn):默認(rèn)不支持Windows,需要第三方移植才可用于Windows。
Cygwin
Cygwin是一個(gè)Windows下Unix-like模擬環(huán)境,具體說就是Unix-like接口(OS API,命令行)重定向?qū)樱淠康氖遣恍薷能浖创a僅重新編譯就可以將Unix-like系統(tǒng)上的軟件移植到Windows上(這個(gè)移植也許還算不上嚴(yán)格意義上的無縫移植)。始于1995年,最初作為Cygnus軟件公司工程師Steve Chamberlain的一個(gè)項(xiàng)目。
和GCC的關(guān)系:Cygwin是讓W(xué)indows擁有Unix-like環(huán)境的軟件而不是編譯器,GCC是安裝在Cygwin上的編譯器。
優(yōu)點(diǎn):可以比MingW移植更多的軟件到Windows上,對Linux接口模擬比MingW全面。
缺點(diǎn):軟件運(yùn)行依賴cygwin1.dll,速度受點(diǎn)影響。
注意:Unix-like模擬環(huán)境不是Unix虛擬環(huán)境,很多論述中都聲稱Cygwin是在Windows上盡可能模擬類Unix環(huán)境,這容易造成誤解,好像類Unix的elf程序可以直接運(yùn)行在安裝了Cygwin的Windows上一樣。Cygwin和Wine的思路是不同的。在Windows+Cygwin上你可以像類Unix那樣使用命令行和編程,但elf等非exe格式的程序是不能被Cygwin運(yùn)行的,所以Cygwin和Unix虛擬機(jī)、Wine是完全不同的,叫Unix-like環(huán)境,模擬非虛擬,是有限的選擇性的模擬,請不要誤解。
MingW
MingW(Minimalist GNU on Windows)是一個(gè)Linux/Windows下的可以把軟件源碼中Unix-like OS API調(diào)用通過頭文件翻譯替換成相應(yīng)的Windows API調(diào)用的編譯環(huán)境,其目的和Cygwin相同。從而把Linux上的軟件在不修改源碼的情況下編譯為可直接在Win下執(zhí)行的exe。
和GCC的關(guān)系:MingW是編譯環(huán)境,不是編譯器,GCC是MingW中的核心組成。
優(yōu)點(diǎn):在Win下可以和Linux一樣的方式編譯C/C++源碼,可以說是Win版的GCC,其生產(chǎn)的Windows PE程序相比Cygwin不依賴任何第三方庫,比Cygwin純粹,理論上也更快速。
缺點(diǎn):編譯速度、編譯出的程序在算法上可能都比MSVC慢。
注意:與Windows下其它編譯器不同的是,MinGW與Linux下廣泛使用的GNU近乎完全兼容,這意味著,在Linux下如何編譯源代碼,在MinGW中也可以以完全相同的方式編譯。有些Linux下的開發(fā)人員(比如開源陣營)發(fā)布的源代碼通常只提供Linux下的編譯方式,而不提供Windows下的編譯方式(這可能與其不熟悉windows操作系統(tǒng)有關(guān)),但確實(shí)有不少用戶需要在在Windows下編譯使用此源代碼。這在種情況下,如果Windows用戶想用VC、BC等編譯器編譯該源代碼,必須重寫Makefile(各種編譯器所支持的Makefile不盡相同),工作量比較大不說,還很難保證不出錯(cuò)。MinGW的出現(xiàn),提供了兩個(gè)平臺下的“跨平臺編譯方案”。MinGW與MSYS相配合,連./configure都有了。與GNU不同的是,MinGW編譯生成的是Windows下的可執(zhí)行文件(.exe)或庫文件(.dll,.lib)——不過編譯過程中的的中間文件仍然是.o文件,而不是.obj文件(這當(dāng)然無所謂了,中間文件嘛,編譯完成后就沒有用了)。
在我們對比Cygwin和MingW之前,請先理清一件事,那就是,
如何從Unix-like系統(tǒng)向Windows系統(tǒng)移植軟件?
現(xiàn)代操作系統(tǒng)包括Windows和Linux的基本設(shè)計(jì)概念,像進(jìn)程線程地址空間虛擬內(nèi)存這些都大同小異,二者之上的程序之所以不兼容,主要是它們對這些功能具體實(shí)現(xiàn)上的差異:
首先,是可執(zhí)行文件的格式,Window使用PE的格式,并且要求以.EXE為后綴名,Linux則使用Elf。
其次,操作系統(tǒng)API也同,比如,Windows用CreateProcess()創(chuàng)建進(jìn)程,而Unix-like系統(tǒng)則使用fork(),其他還有很多諸如spawn、signals、select、sockets等。
分析之后可知,要把Unix-like系統(tǒng)上的軟件移植到Windows上,有幾種思路:
第一種:修改軟件源碼并重新編譯,這個(gè)方法最笨,類Unix下大量的軟件要修改工作量很大,編譯生成目標(biāo)平臺可執(zhí)行文件格式。
第二種:不修改軟件源碼但把類Unix接口調(diào)用悄悄替換為WinAPI,還是需要重新編譯,編譯生成目標(biāo)平臺可執(zhí)行文件格式。
第三種,無縫移植的運(yùn)行環(huán)境,無需重新編譯,在一種OS上建立另一中OS的應(yīng)用軟件虛擬環(huán)境(和虛擬機(jī)不一樣),比如Wine(把Windows上的可執(zhí)行程序直接原樣移植到Linux上)。
Cygwin和MingW的對比
作為編譯環(huán)境時(shí),都依賴于GCC
用它們作編譯環(huán)境、交叉編譯,根本上都是因?yàn)镚CC編譯器的支持,它們做的工作是為GCC的編譯掃除Unix-like、Windows間OS API的差異這個(gè)障礙。
二者都必須重新編譯后實(shí)現(xiàn)移植,生成的程序都是PE格式
二者都不能讓Linux下的程序直接運(yùn)行在Windows上(無縫移植),必須通過源代碼重新編譯。有些人聲稱cygwin支持rpm的壓縮包,注意,rpm壓縮包其實(shí)是src.rpm,內(nèi)部還是源碼而非elf格式,cygwin不支持常規(guī)rpm包的安裝。
Cygwin運(yùn)行在Windows上,MingW運(yùn)行在Linux或者Windows上
Cygwin是Windows上運(yùn)行的Unix-like環(huán)境,MingW是運(yùn)行在Linux或者Windows上的Windows PE編譯環(huán)境。
MingW中的子項(xiàng)目MSys和Cygwin更像
Cygwin除了全面模擬Linux的接口(命令行,OS API),提供給運(yùn)行在它上面的的Windows程序使用,并提供了大量現(xiàn)成的軟件,更像是一個(gè)平臺。MingW也有一個(gè)叫MSys(Minimal SYStem)的子項(xiàng)目,主要是提供了一個(gè)模擬Linux的Shell和一些基本的Linux工具。因?yàn)榫幾g一個(gè)大型程序,光靠一個(gè)GCC是不夠的,還需要有Autoconf等工具來配置項(xiàng)目,所以一般在Windows下編譯ffmpeg等Linux下的大型項(xiàng)目都是通過Msys來完成的,當(dāng)然Msys只是一個(gè)輔助環(huán)境,根本的工作還是MingW來做的。
實(shí)現(xiàn)思路有同有異
Cygwin和MingW都是第二種軟件移植思路,當(dāng)然,二者還是有區(qū)別,區(qū)別就在于“替換”方式,Cygwin編譯時(shí),程序依然以Linux的方式調(diào)用系統(tǒng)API,只不過把Unix-like接口link到自己的cygwin1.dll上,然后在cygwin1.dll中重新調(diào)用Windows API,cygwin1.dll再調(diào)用Windows對應(yīng)的實(shí)現(xiàn),來把結(jié)果返回給程序。也就是說,他們基于Win32 API中寫了一個(gè)Unix系統(tǒng)API的重定向?qū)?,所以用它移植的軟件都依賴于cygwin1.dll,MingW編譯時(shí)通過特有的WinAPI頭文件把類Unix-like調(diào)用替換為WinAPI,用它移植的軟件無需依賴第三方庫,可直接運(yùn)行在Windows平臺。為了達(dá)到類Unix軟件僅通過重新編譯移植到Win的目的,Cygwin在運(yùn)行時(shí)偷梁換柱,MingW在編譯時(shí)偷梁換柱。
用一個(gè)PE格式查看工具檢查一下就能發(fā)現(xiàn),Cygwin生成的程序依然有fork()這樣的Linux系統(tǒng)調(diào)用,但目標(biāo)庫是cygwin1。而MingW生成的程序,則全部使用從KERNEL32導(dǎo)出的標(biāo)準(zhǔn)Windows系統(tǒng)API。
使用方式有同有異
把類Unix上的軟件移植到Windows是二者的主要目標(biāo),除此之外,順帶的,MingW和Cygwin都可以用來跨平臺開發(fā)等等其他事情,
Windows + Cygwin:可以在Windows上學(xué)習(xí)Linux命令,還可以在Windows上做Linux軟件的開發(fā),包括用GCC編譯elf(交叉編譯)。
Linux + MingW:可以在Linux上做Windows軟件的開發(fā),包括用GCC編譯exe(交叉編譯)。
Windows/Linux + MingW:可以擺脫MSVC的“束縛”,用GNU的自由軟件來編譯生成不依賴第三方庫的純粹Windows PE格式(exe)二進(jìn)制程序。
Cygwin重量級,MingW輕量級
與MingW思路一致的,兩者相比,Cygwin是重量級的(需下載50M以上直至數(shù)百兆不等,安裝后占用空間可達(dá)1G),MinGW是輕量級的(需下載的文件只有20M,安裝后70M左右),這是單純從體積上說的,另外Cygwin現(xiàn)在據(jù)說也不是完全免費(fèi)的了。
網(wǎng)絡(luò)上的對比列表(UnxUtils自行無視,僅供參考)
功能 | UnxUtils | MinGW | Cygwin |
設(shè)計(jì)原理 | 原生 | 原生 | 模擬 |
運(yùn)行依賴 | 無依賴 | 依賴msys.dll(一定依賴它嗎?值得驗(yàn)證) | 依賴cygwin.dll |
運(yùn)行性能(比較) | 最快 | 中等 | 慢 |
DOS執(zhí)行 | 可以 | 可以 | 不可以 |
更新速度 | 完善停止更新 | 較慢 | 基本同步gcc |
shell命令 | 較多 | 較少 | 較多 |
uname | WindowsNT | MINGW32_NT-5.1 | CYGWIN_NT-5.1 |
env | 同Windows | 同Windows | 不完全同Windows |
root | C:/ | C:/ | / |
home | C:/Documents and Settings/test | /home/test: No such file or directory | /home/test |
pwd | C:/bin | /usr/bin | /home/test |
df | cannot read table of mounted filesystems | 無 | /cygdrive/c |
vi | 無 | 無 | 有 |
gcc套件 | 無 | 有 | 有 |
開發(fā)庫 | 無 | WinAPI | POSIX |
圖形庫 | 無 | GTK/QT | GTK/QT |
可移植性 | 無 | Win32API不可移植 | 無縫移植 |
程序運(yùn)行 | 無 | 原生 | 模擬 |
程序依賴 | 無 | 無 | cygwin.dll |
程序性能(比較) | 無 | 較快(慢于VC和Linux下的gcc) | 較慢(快于java) |
小拓展
一個(gè)編譯器編譯時(shí)能否調(diào)用編譯其他編譯器產(chǎn)生的lib、dll?
不可以,name***不同,也就是名字混淆方式不同。
http://rendao.org/blog/1071/