LLVM和GCC的區別
最近在Mac OS X Mountain Lion下用Xcode進行開發,發現在編譯選項裡有如下所示的這兩種編譯器:一個是Apple LLVM compiler 4.2,另外一個是LLVM GCC 4.2。
近幾年一直聽人說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標準又規定分別將C89、C99作為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)。優化器對這一中間程式碼進行優化,試圖使程式碼更高效。後端則負責將優化器優化後的中間程式碼轉換為目標機器的程式碼,這一過程後端會最大化的利用目標機器的特殊指令,以提高程式碼的效能。
事實上,不光靜態語言如此,動態語言也符合上面這個模型,例如Java。Java Virtual Machine也利用上面這個模型,將Java程式碼翻譯為Java bytecode。
這一模型的好處是,當我們要支援多種語言時,只需要新增多個前端就可以了。當需要支援多種目標機器時,只需要新增多個後端就可以了。對於中間的優化器,我們可以使用通用的中間程式碼。
這種三段式的結構還有一個好處,開發前端的人只需要知道如何將原始碼轉換為優化器能夠理解的中間程式碼就可以了,他不需要知道優化器的工作原理,也不需要了解目標機器的知識。這大大降低了編譯器的開發難度,使更多的開發人員可以參與進來。
雖然這種三段式的編譯器有很多有點,並且被寫到了教科書上,但是在實際中這一結構卻從來沒有被完美實現過。做的比較好的應該屬Java和.NET虛擬機器。虛擬機器可以將目標語言翻譯為bytecode,所以理論上講我們可以將任何語言翻譯為bytecode,然後輸入虛擬機器中執行。但是這一動態語言的模型並不太適合C語言,所以硬將C語言翻譯為bytecode並實現垃圾回收機制的效率是非常低的。
GCC也將三段式做的比較好,並且實現了很多前端,支援了很多語言。但是上述這些編譯器的致命缺陷是,他們是一個完整的可執行檔案,沒有給其它語言的開發者提供程式碼重用的介面。即使GCC是開源的,但是原始碼重用的難度也比較大。
LLVM
LLVM最初是Low Level Virtual Machine的縮寫,定位是一個虛擬機器,但是是比較底層的虛擬機器。它的出現正是為了解決編譯器程式碼重用的問題,LLVM一上來就站在比較高的角度,制定了LLVM IR這一中間程式碼表示語言。LLVM IR充分考慮了各種應用場景,例如在IDE中呼叫LLVM進行實時的程式碼語法檢查,對靜態語言、動態語言的編譯、優化等。
從上面這個圖中我們發現LLVM與GCC在三段式架構上並沒有本質區別。LLVM與其它編譯器最大的差別是,它不僅僅是Compiler Collection,也是Libraries Collection。舉個例子,假如說我要寫一個XYZ語言的優化器,我自己實現了PassXYZ演算法,用以處理XYZ語言與其它語言差別最大的地方。而LLVM優化器提供的PassA和PassB演算法則提供了XYZ語言與其它語言共性的優化演算法。那麼我可以選擇XYZ優化器在連結的時候把LLVM提供的演算法連結進來。LLVM不僅僅是編譯器,也是一個SDK。
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前端。
相關推薦
LLVM和GCC的區別
最近在Mac OS X Mountain Lion下用Xcode進行開發,發現在編譯選項裡有如下所示的這兩種編譯器:一個是Apple LLVM compiler 4.2,另外一個是LLVM GCC 4.2。 近幾年一直聽人說LLVM比GCC好,但是我一直沒有時間研究這二者的差別。由此問題出發,我又給自己
編譯器二:LLVM和GCC的區別
文章來源:http://lionelliu.com/?p=1771 最近在Mac OS X Mountain Lion下用Xcode進行開發,發現在編譯選項裡有如下所示的這兩種編譯器:一個是Apple LLVM compiler 4.2,另外一個是LLVM GCC 4.2。 近幾年一直聽人說LLVM比G
GCC、g++編譯器和gcc編譯器的區別
GCC:(GNU Compiler Collection,GNU編譯器套件),是由 GNU 開發的程式語言編譯器。它是以GPL許可證所發行的自由軟體,也是 GNU計劃的關鍵部分。 gcc:GNU的C語言編譯器。 g++:GNU的C++語言編譯器。 區別一: gcc:編譯檔案字尾為.c的檔案時,編譯成編
Richard Stallman 談 GCC、LLVM 和 Copyleft
ESR(Eric S.Raymond)在GCC郵件列表上發貼預言,LLVM/Clang編譯器將在3到5年內威脅到GCC的統治地位,認為GCC編譯器的反外掛政策正成為一大障礙。雖然Clang尚未達到GCC的成熟度,但在某些方面它擁有比GCC更出色的特性,例如錯誤資訊。
g++ 和 gcc 的相同點和區別
gcc 和g++ 的區別和聯絡 gcc和g++都是GNU(一個組織)的編譯器。 1、對於.c字尾的檔案,gcc把它當做是C程式;g++當做是C++程式; 2、對於.cpp字尾的檔案,gcc和g++都會當做c++程式。 3、編譯階段,g++會呼叫gcc; 4、連線
GCC和G++區別
原文:http://www.cnblogs.com/samewang/p/4774180.html 看的Linux公社的一篇文章,覺得不錯,內容複製過來了。 其實在這之前,我一直以為gcc和g++是一個東西,只是有兩個不同的名字而已,今天在linux下編譯一個c程式碼
GCC選項-Xlinker和-Wl區別
轉自:http://www.cnblogs.com/rickyk/p/4186902.html 備忘:在一次使用GCC的過程中發現了原來傳遞給連結器ld可以同時使用Xlinker和Wl兩種命令,這兩個命令都可以正確傳遞給ld作為使用,現在總結下兩者的區別。 Xlin
GET和POST區別總結
get 、post 、區別一、GET和POST區別的普遍看法:HTTP 定義了與服務器交互的不同方法,最常用的有4種,Get、Post、Put、Delete,如果我換一下順序就好記了,Put(增),Delete(刪),Post(改),Get(查),即增刪改查,下面簡單敘述一下:1)Get, 它用於獲取信息,註
JS中const、var和let區別
方法 pre 命令 con 使用 它的 comm 作用 影響 在JavaScript中有三種聲明變量的方式:var、let、const。 1.const 聲明創建一個只讀的常量。這不意味著常量指向的值不可變,而是變量標識符的值只能賦值一次,必須初始化。 const b
make file 和 GCC標誌學習
tomat 所有 相等 ria 程序 pac depend extra gdb GCC: -Wall : 打開警告標誌 -std=standard : -ansi 相等 -std=c89 -ansi : 指定代碼應該符合什麽標準。 -c : Compile and asse
equals 和== 的區別
strong 都是 什麽 brush -s 新的 equals方法 實現 繼承 首先 看比較的對象是否為字符串,若為(String)字符串用equals 比較, 比較的是他們的值。相同返回 true ,不相同返回false. package one; p
mybatis中的#和$的區別
背景 插入 trac sql註入 -m .com article 參數 -s 1. #將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:order by #user_id#,如果傳入的值是111,那麽解析成sql時的值為order by "111", 如果傳
hibernate中hql語句中list和iterate區別
每次 hibernate 寫入 所有 讀取 條件 iter 查詢 hql 1.使用list()方法獲取查詢結果,每次發出一條語句,獲取全部數據。2.使用iterate()方法獲取查詢結果,先發出一條SQL語句用來查詢滿足條件數據的id,然後依次按照這些id查詢記錄,也就是要
java中ArrayList和LinkedList區別
插入 list 新的 查找 arr tro 基於 列表 時間復雜度 ArrayList和LinkedList最主要的區別是基於不同數據結構 ArrayList是基於動態數組的數據結構,LinkedList基於鏈表的數據結構,針對這點,從時間復雜度和空間復雜度來看主要區別:
mysql中replicate_wild_do_table和replicate_do_db區別
lan rep cati mil 多人 pan think lte 避免 使用replicate_do_db和replicate_ignore_db時有一個隱患,跨庫更新時會出錯。 如在Master(主)服務器上設置 replicate_do_db=test(my.conf
2000行之宏中#和##的區別
ret fun color bsp nbsp urn div def include #include<stdio.h> #define Fun(a,b) a##b int main() { x=‘H‘; y=‘W‘; printf("
HTML提交方式post和get區別(實驗)
des url action 通過 性別 清除數據 map pass pack HTML提交方式post和get區別(實驗) 一、post和get區別 get提交,提交的信息都顯示在地址欄中。 post提交,提交的信息不顯示地址欄中,顯示在消息體中。 二、客戶端代碼
stringbuffer 和 stringbuilder區別
uil build 線程 區別 單線程 線程安全 多線程操作 buffer 少量數據 stringbuffer 和 stringbuilder速度 小於 線程安全 線程非安全 單線程操作
水晶頭鍍金30U和50區別
style 價格 -1 font 質量 穩定性 tex 穩定 size U是厚度單位,1μm≈40u。一般來說鍍金越厚,越耐插播,耐酸堿腐蝕,觸點壽命越長,傳輸穩定性越好,價格越貴。但是事實上,鍍金層的質量,或者說鍍金對水晶頭質量的影響,跟工藝的關系更密切。水晶頭鍍金30U
MyBatis Mapper.xml文件中 $和#的區別
優先 註入 sql註入 jdb 防止 自動 || myba 由於 1.優先使用#{paramName,jdbcType=VARCHAR} 寫法,除了可以防止sql註入以外,它還能在參數裏含有單引號的時候自動轉義, 而${paramName}由於是類似於拼接sql的寫法,不具