LLVM和GCC的區別


最近在Mac OS X Mountain Lion下用Xcode進行開發,發現在編譯選項里有如下所示的這兩種編譯器:一個是Apple LLVM compiler 4.2,另外一個是LLVM GCC 4.2。

Xcode Compiler Setting

近幾年一直聽人說LLVM比GCC好,但是我一直沒有時間研究這二者的差別。由此問題出發,我又給自己拋出了很多疑問:

  • cc, c89, c99是什么?有何區別?
  • gcc, g++, cpp, gpp又是什么?
  • LLVM與GCC區別大嗎?
  • Apple LLVM compiler 4.2和LLVM GCC 4.2有何區別?
  • LLVM GCC 4.2到底是LLVM還是GCC?

接下來讓我們一起補補歷史課。

CC, C89, C99

Unix誕生之后,很多公司都開發了自己的Unix系統並且使用了自己專門的編譯器。這樣就導致在不同的Unix系統上,想編譯C語言代碼就需要使用不同的命令。於是POSIX標准Commands and Utilities中就規定了將CC作為不同編譯器的統一命令接口,並且也規定了CC命令需要提供哪些必須的參數。

隨着后續ISO C標准的確定,POSIX標准又規定分別將C89C99作為ISO C的接口,而CC則繼續作為非標准C的接口。但實際上后續大多數C語言編譯器都實現了ISO C標准,所以POSIX標准規定后續應將CC這一歷史遺留的命令取消。

GCC, G++, CPP, GPP

隨着開源運動的興起,自由軟件基金會開發了自己的開源免費的C語言編譯器GNU C Compiler,簡稱GCC。GCC中提供了C Preprocessor這個C語言的預處理器,簡稱CPP。后來GCC又加入了對C++等其它語言的支持,所以他的名字也改為GNU Compiler Collection。G++則是專門用來處理C++語言的。在GNU的官方手冊中,有一個章節叫做G++ and GCC介紹了這二者的區別。G++是GCC編譯器集合的一個前端。關於前端、后端的概念下面有更詳細的介紹。而GPP呢,這個名字比較特殊,如果你用的是Linux系統,可能並沒有這個命令。但是在某些特殊的系統下,例如DOS,是無法創建G++這樣帶有特殊符號的文件名的。所以按照DJGPP編譯器的做法,GPP其實就是G++。

LLVM與GCC

回顧GCC的歷史,雖然它取得了巨大的成功,但開發GCC的初衷是提供一款免費的開源的編譯器,僅此而已。可后來隨着GCC支持了越來越多的語言,GCC架構的問題也逐漸暴露出來。但GCC到底有什么問題呢?我們一起看看這篇文章:The Architecture of Open Source Applications: LLVM。LLVM的優點也正是GCC的缺點。

傳統編譯器

傳統編譯器的工作原理基本上都是三段式的,可以分為前端(Frontend)、優化器(Optimizer)、后端(Backend)。前端負責解析源代碼,檢查語法錯誤,並將其翻譯為抽象的語法樹(Abstract Syntax Tree)。優化器對這一中間代碼進行優化,試圖使代碼更高效。后端則負責將優化器優化后的中間代碼轉換為目標機器的代碼,這一過程后端會最大化的利用目標機器的特殊指令,以提高代碼的性能。

SimpleCompiler

事實上,不光靜態語言如此,動態語言也符合上面這個模型,例如Java。Java Virtual Machine也利用上面這個模型,將Java代碼翻譯為Java bytecode。

這一模型的好處是,當我們要支持多種語言時,只需要添加多個前端就可以了。當需要支持多種目標機器時,只需要添加多個后端就可以了。對於中間的優化器,我們可以使用通用的中間代碼。

Retargetable Compiler

這種三段式的結構還有一個好處,開發前端的人只需要知道如何將源代碼轉換為優化器能夠理解的中間代碼就可以了,他不需要知道優化器的工作原理,也不需要了解目標機器的知識。這大大降低了編譯器的開發難度,使更多的開發人員可以參與進來。

雖然這種三段式的編譯器有很多有點,並且被寫到了教科書上,但是在實際中這一結構卻從來沒有被完美實現過。做的比較好的應該屬Java和.NET虛擬機。虛擬機可以將目標語言翻譯為bytecode,所以理論上講我們可以將任何語言翻譯為bytecode,然后輸入虛擬機中運行。但是這一動態語言的模型並不太適合C語言,所以硬將C語言翻譯為bytecode並實現垃圾回收機制的效率是非常低的。

GCC也將三段式做的比較好,並且實現了很多前端,支持了很多語言。但是上述這些編譯器的致命缺陷是,他們是一個完整的可執行文件,沒有給其它語言的開發者提供代碼重用的接口。即使GCC是開源的,但是源代碼重用的難度也比較大。

LLVM

LLVM最初是Low Level Virtual Machine的縮寫,定位是一個虛擬機,但是是比較底層的虛擬機。它的出現正是為了解決編譯器代碼重用的問題,LLVM一上來就站在比較高的角度,制定了LLVM IR這一中間代碼表示語言。LLVM IR充分考慮了各種應用場景,例如在IDE中調用LLVM進行實時的代碼語法檢查,對靜態語言、動態語言的編譯、優化等。

LLVM Compiler

從上面這個圖中我們發現LLVM與GCC在三段式架構上並沒有本質區別。LLVM與其它編譯器最大的差別是,它不僅僅是Compiler Collection,也是Libraries Collection。舉個例子,假如說我要寫一個XYZ語言的優化器,我自己實現了PassXYZ算法,用以處理XYZ語言與其它語言差別最大的地方。而LLVM優化器提供的PassA和PassB算法則提供了XYZ語言與其它語言共性的優化算法。那么我可以選擇XYZ優化器在鏈接的時候把LLVM提供的算法鏈接進來。LLVM不僅僅是編譯器,也是一個SDK。

Pass Linkage

Apple LLVM compiler 4.2和LLVM GCC 4.2

現在我們可以回答本文最前面我遇到的那個問題了。Apple LLVM compiler 4.2是一個真正的LLVM編譯器,前端使用的是Clang,基於最新的LLVM 3.2編譯的。LLVM GCC 4.2編譯器的核心仍然是LLVM,但是前端使用的是GCC 4.2編譯器。從LLVM的下載頁面可以看出,LLVM從1.0到2.5使用的都是GCC作為前端,直到2.6開始才提供了Clang前端。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM