Clang:LLVM 的 C 语言家族前端
Clang:LLVM 的 C 語言家族前端
Clang 項目為LLVM 項目的 C 語言家族(C、C++、Objective C/C++、OpenCL、CUDA 和 RenderScript)中,提供了語言前端和工具基礎結構。提供了 GCC 兼容的編譯器驅動程序 ( clang ) 和 MSVC 兼容的編譯器驅動程序 ( clang-cl.exe )。可以立即獲取并構建源代碼。
特點和目標
該項目的一些目標包括:
最終用戶特點:
? 快速編譯和低內存使用
? 表情診斷(示例)
? GCC兼容性
實用程序和應用程序:
? 基于模塊化庫的架構
? 支持多樣化的客戶端(重構、靜態分析、代碼生成等)
? 允許與 IDE 緊密集成
? 使用 LLVM ‘Apache 2’ 許可證
內部設計和實現:
? 一個真實的、產品可靠的編譯器
? 一個簡單且可破解的代碼庫
? 用于 C、Objective C、C++ 和 Objective C++ 的單個統一解析器
? 與 C/C++/ObjC 及其變體的一致性
當然,這只是 Clang 的目標和特性的粗略概述。要真正了解全部內容,請參閱功能部分,對每個部分進行了分解,并進行了更詳細的解釋。
為什么?
新前端的開發是出于對編譯器的需求,該編譯器允許更好的診斷、與 IDE 的更好集成、與商業產品兼容的許可證,以及易于開發和維護的靈活編譯器。所有這些都是啟動開發可以滿足這些需求的新前端的動機。
當前狀態
當面向 X86-32、X86-64 和 ARM 時,Clang 被認為是產品可靠的 C、Objective-C、C++ 和 Objective-C++ 編譯器(其它目標可能有警告,但通常很容易修復)。例如,Clang 在產品中用于構建 Chrome 或 Firefox 等性能關鍵軟件。
如果正在尋找源分析或源到源轉換工具,Clang 可能是絕佳解決方案。Clang 支持 C++11、C++14 和 C++17,請查看C++ 狀態頁面了解更多信息。
獲取并參與其中!
首先獲取代碼、構建,并使用。可以做的各種事情,并將第一手獲得“Clang 體驗”:希望 “產生共鳴”。
完成此操作后,請考慮加入 Clang 社區。Clang 開發人員包括許多具有各種背景的志愿者,貢獻者。如果有興趣關注 Clang 的開發,注冊郵件列表是了解該項目如何運作的好方法。
Clang - 功能和目標
詳細地描述了Clang的特性和目標,提供了更廣泛的解釋。這些功能是:
最終用戶特點:
? 快速編譯和低內存使用
? 表達診斷
? GCC兼容性
實用程序和應用程序:
? 基于庫的架構
? 支持多樣化的客戶
? 與 IDE 集成
? 使用 LLVM ‘BSD’ 許可證
內部設計與實現:
? 一個真實的、產品可靠的編譯器
? 一個簡單且可破解的代碼庫
? 用于 C、Objective C、C++ 和 Objective C++ 的單個統一解析器
? 與 C/C++/ObjC 及其變體的一致性
最終用戶功能
快速編譯和低內存使用
在 clang 上工作的一個主要重點是使其快速、輕便和可擴展。clang 基于庫的架構,可以直接計算堆棧每一層的時間和成本,并且驅動程序有許多用于性能分析的選項。許多詳細的指標參數可以在網上找到。
編譯時性能很重要,當使用 clang 作為 API 時,通常內存使用更是如此:代碼占用的內存越少,一次可以放入內存的代碼就越多(例如,對于整個程序分析工具很有用) 。
除了在批處理模式下與 GCC 正面交鋒時高效之外,clang 還使用基于庫的架構構建,可以相對容易地適應,并使用構建新工具。這意味著通常可以應用開箱即用的思維和新技術以各種方式改進編譯。
表情診斷
除了快速和實用之外,目標是使 Clang 非常用戶友好。就命令行編譯器而言,這基本上歸結為使編譯器生成的診斷(錯誤和警告消息)盡可能有用。有幾種方法可以做到這一點,但最重要的是準確指出程序中的問題,突出顯示相關信息以便一目了然,并使描述盡可能清晰。
這是一個簡單的例子,說明了 Clang 診斷的可靠:
$ clang -fsyntax-only tc
tc:7:39: 錯誤:二進制表達式的無效操作數(‘int’ 和 ‘struct A’)
返回 y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
可以看到,甚至不需要查看原始源代碼,即可了解基于 Clang 錯誤的錯誤:因為 Clang 打印了一個插入符號,確切地知道它在抱怨哪個加號。范圍信息突出顯示了加號的左右兩側,這使得編譯器正在談論的內容一目了然,這對于涉及優先級問題和許多其它情況的情況非常有用。
Clang 診斷程序非常精致并且具有許多功能。有關更多信息和示例,請參閱“表情診斷”頁面。
GCC兼容性
GCC 目前是當今事實上的標準開源編譯器,經常編譯大量代碼。GCC 支持大量的擴展和特性(其中許多是未記錄的),并且許多代碼和頭文件依賴于這些特性來構建。
雖然能夠忽略這些擴展并專注于實現語言標準會很好,但實用主義迫使支持最常用的 GCC 擴展。許多用戶只希望代碼能夠編譯,不在乎爭論是否是迂腐的 C99。
如上所述,所有擴展都被明確識別并標有擴展診斷,可以映射到警告、錯誤或只是忽略。
實用程序和應用程序
基于庫的架構
clang 的一個主要設計理念是使用基于庫的架構。在這種設計中,前端的各個部分可以清晰地劃分為單獨的庫,然后可以根據不同的需求和用途進行混合。此外,基于庫的方法支持良好的接口,并使新開發人員更容易參與(因為只需要了解大局的一小部分)。
“世界需要更好的編譯器工具,即作為庫構建的工具。這個設計點允許以新的和新穎的方式重用這些工具。然而,將工具構建為庫是不夠的:必須具有可靠的 API,盡可能解耦盡可能相互隔離,并且易于修改/擴展。這需要干凈的分層、體面的設計,并保持庫獨立于任何特定客戶端。”
目前,clang 分為以下庫和工具:
? libsupport - 來自 LLVM 的基本支持庫。
? libsystem - 來自 LLVM 的系統抽象庫。
? libbasic - 診斷、SourceLocations、SourceBuffer 抽象、輸入源文件的文件系統緩存。
? libast - 提供類來表示 C AST、C 類型系統、內置函數以及用于分析和操作 AST 的各種幫助程序(訪問者、漂亮的打印機等)。
? liblex -詞法分析和預處理、標識符哈希表、pragma 處理、標記和宏擴展。
? libparse - 解析。該庫調用客戶端提供的粗粒度“操作”(例如 libsema 構建 AST),但對 AST 或其它客戶端特定的數據結構一無所知。
? libsema - 語義分析。這提供了一組解析器操作來為程序構建標準化的 AST。
? libcodegen - 將 AST 降低到 LLVM IR 以進行優化和代碼生成。
? librewrite - 編輯文本緩沖區(對于代碼重寫轉換很重要,例如重構)。
? libanalysis - 靜態分析支持。
? clang - 驅動程序,各級庫的客戶端。
作為這個基于庫的設計的強大功能的一個例子…如果想構建一個預處理器,可以使用 Basic 和 Lexer 庫。如果想要一個索引器,可以使用前兩個并添加解析器庫和一些索引操作。如果需要重構、靜態分析或源到源編譯器工具,則可以添加 AST 構建和語義分析器庫。
有關各種 clang 庫的低級實現細節的更多信息,請參閱 clang 內部手冊。
支持不同的客戶
Clang 的設計和構建,如何使用宏偉計劃。驅動力是每天都使用 C 和 C++ 的事實,并且由于缺乏可用的好工具而不得不痛苦。認為 C 和 C++ 工具生態系統受到了解析和表示這些語言源代碼的難度的極大限制,目標是在 clang 中糾正這個問題。
這個目標的問題在于不同的客戶有非常不同的要求。考慮代碼生成,例如:解析代碼生成的簡單前端,必須分析代碼的有效性并以某種中間形式發出代碼以傳遞給優化器或后端。由于有效性分析和代碼生成在很大程度上可以即時完成,因此前端實際上沒有為代碼中的所有表達式和語句構建完整的 AST 的硬性要求。TCC 和 GCC 是編譯器的例子,要么不構建真正的 AST(在前一種情況下),要么構建一個精簡和簡化的 AST(在后一種情況下),因為主要關注代碼生成。
另一方面,一些客戶端(如重構)想要關于原始源代碼的非常詳細的信息,并想要一個完整的 AST 來描述。重構想要獲得有關宏擴展的信息、每個括號表達式 ‘(((x)))’ 與 ‘x’ 的位置、完整位置信息等等。此外,重構希望查看 整個程序以確保它正在進行安全的轉換。使其高效并正確地實現這一點需要大量的工程和算法工作,而這些工作對于簡單的靜態編譯器來說是不必要的。
clang 方法的美妙之處在于它不限制如何使用它。特別是,可以使用 clang 預處理器和解析器來構建一個完全不構建 AST 的極其快速和輕量級的動態代碼生成器(類似于 TCC)。作為中間步驟,clang 支持使用當前的 AST 生成和語義分析代碼,并讓代碼生成客戶端在代碼生成后為每個函數釋放 AST。最后,clang 支持構建和保留成熟的 AST,甚至支持將寫出到磁盤。
使用可靠和簡單的 API 設計庫,允許在客戶端確定這些高級策略決策,而不是在任何這些庫的實現中強制采用“一種正確的方式”。做到這一點很難,并不總是第一次就做對,但是當意識到犯了錯誤時,會解決任何問題。
與 IDE 集成
相信集成開發環境 (IDE) 是將開發難題的各個部分整合在一起的好方法,旨在使 clang 在這樣的環境中運行良好。IDE 的主要優點是通常可以查看整個項目并且是長期存在的過程,而獨立編譯器工具通常在項目中的每個單獨文件上調用,因此范圍有限。
這種差異有很多含義,但重要的一個與效率和緩存有關:在項目中的不同文件之間共享地址空間,意味著可以使用智能緩存和其他技術來顯著減少分析/編譯時間。
IDE 和批處理編譯器之間的進一步區別在于,通常對前端提出非常不同的要求:依賴高性能以提供“快速”體驗,因此非常需要“增量編譯”、“模糊”等技術。解析”等。最后,IDE 的要求通常與代碼生成非常不同,通常需要僅代碼生成的前端可以丟棄的信息。Clang 是專門為捕獲這些信息而設計和構建的。
使用 LLVM ‘Apache 2’ 許可證
積極將 clang(以及整個 LLVM)用于商業項目,不僅作為獨立的編譯器,而且作為嵌入在專有應用程序中的庫。認為該許可證鼓勵貢獻者獲取源代碼并與之合作,并相信如果這些個人和組織不想永遠維護一個分支(合并時既耗時又昂貴),會回饋工作涉及)。此外,現在沒有人通過編譯器賺錢,但許多人需要來實現更大的目標:每個人一起工作是有意義的。
有關 LLVM/clang 許可證的更多信息,請參閱LLVM 許可證說明以獲取更多信息。
內部設計與實施
一個真實的、產品可靠的編譯器
Clang 由經驗豐富的編譯器開發人員設計和構建,對現有開源編譯器存在的問題越來越感到沮喪。Clang 是經過精心設計和構建的,旨在為全新一代 C/C++/Objective C 開發工具提供基礎,希望它具有產品可靠。
成為產品可靠的編譯器意味著很多事情:它意味著高性能、可靠和(相對)無錯誤,并且意味著最終會被廣泛的人使用和依賴。雖然仍處于早期開發階段,但堅信這將成為現實。
一個簡單且可破解的代碼庫
目標是讓任何對編譯器有基本了解和 C/C++/ObjC 語言工作知識的人都能理解和擴展 clang 源代碼庫。很大一部分原因在于決定讓 AST 盡可能地反映語言:擁有友好的 if 語句、for 語句、括號表達式、結構體、聯合等,所有這些都以簡單而明確的方式表示。
除了簡單的設計之外,還通過對源代碼庫進行良好的注釋,包括在適當的情況下引用語言標準,并設計簡單的代碼,從而使源代碼易于理解。除此之外,clang 提供了一組 AST 轉儲器、打印機和可視化器,可以輕松地將代碼放入并查看它是如何表示的。
用于 C、Objective C、C++ 和 Objective C++ 的單個統一解析器
Clang 是“C 語言家族前端”,這意味著打算支持 C 家族中最受歡迎的成員。確信,適合此類語言的解析技術是手工構建的遞歸下降解析器。由于是純C++代碼,遞歸下降使得新開發人員很容易理解代碼,它很容易支持C/C++所需的ad-hoc規則和其他奇怪的hacks,并且可以直接實現出色的診斷和錯誤恢復。
相信,在一個統一的解析器中實現 C/C++/ObjC 比維護一個單獨的 C 和 C++ 解析器更容易維護和發展,因為 C 和 C++ 解析器必須相互獨立地修復和維護。
與 C/C++/ObjC 及其變體的一致性
當開始著手實現一種語言時,會發現該語言的工作方式與大多數人對其工作的理解方式之間存在巨大差距。這個差距是普通程序員和(可怕的?超自然的?)“語言律師”之間的區別,知道語言的來龍去脈,可以輕松地理解標準。
在實踐中,與語言一致意味著目標是支持完整的語言,包括黑暗和塵土飛揚的角落(如三合字母、預處理器奧秘、C99 VLA 等)。在支持超出標準官方允許的擴展的地方,努力在代碼中明確地調用它并發出有關它的警告(默認情況下禁用,但可以選擇映射到警告或錯誤),允許如果愿意,可以在“嚴格”模式下使用 clang。
參考鏈接:
https://clang.llvm.org/features.html
總結
以上是生活随笔為你收集整理的Clang:LLVM 的 C 语言家族前端的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCL™(开放计算语言)概述
- 下一篇: C-V2X现场解析