* [[https://www.amazon.com/Language-Implementation-Patterns-Domain-Specific-Programming/dp/193435645X|Language Implementation Patterns]] * 簡介前端主要幾個元件。 * 簡介函式庫。 clang 的簡介請見 * [[http://llvm.org/devmtg/2007-05/09-Naroff-CFE.pdf|New LLVM C Front-end]] * [[http://llvm.org/devmtg/2008-08/Naroff_Clang.pdf|Clang Intro]] * [[http://llvm.org/devmtg/2009-10/StateOfClang.pdf|State of Clang]] * [[http://llvm.org/devmtg/2011-11/Gregor_ExtendingClang.pdf|Extending Clang]] 線上文章: * [[http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang/|Parsing C++ in Python with Clang]] * [[http://eli.thegreenplace.net/2014/05/01/modern-source-to-source-transformation-with-clang-and-libtooling|Modern source-to-source transformation with Clang and libTooling]] * [[https://kevinaboos.wordpress.com/2013/07/23/clang-tutorial-part-i-introduction/|CLANG TUTORIAL PART I: INTRODUCTION]] * [[https://kevinaboos.wordpress.com/2013/07/23/clang-tutorial-part-ii-libtooling-example/|CLANG TUTORIAL PART II: LIBTOOLING EXAMPLE]] * [[https://kevinaboos.wordpress.com/2013/07/29/clang-tutorial-part-iii-plugin-example/|CLANG TUTORIAL PART III: PLUGIN EXAMPLE]] * [[http://bastian.rieck.ru/blog/posts/2015/baby_steps_libclang_ast/|Baby steps with `libclang`: Walking an abstract syntax tree]] * [[http://bastian.rieck.ru/blog/posts/2016/baby_steps_libclang_function_extents/|Baby steps with `libclang`: Counting function extents]] ====== 使用範例 ====== # 這裡的 clang 是 compiler driver,負責解析命令行,調用相關工具,並傳遞對應的命令行參數。 # -Xclang 代表其後參數是給 clang -cc1 調用的編譯器。 $ clang -Xclang -ast-dump sum.c # 這裡的 clang -cc1 調用的是實際上的編譯器。 $ clang -cc1 -ast-dump sum.c # -### 列出完整的命令行參數。 $ clang -### sum.c # -xir 指示輸入的是 LLVM IR。 $ clang -xir -c sum.ll * ''clang'' 本身是 compiler driver。 $ lldb clang (lldb) b Driver.cpp:97 (lldb) r --help * 入口點 ''llvm/tools/clang/tools/driver/driver.cpp:main''。 * 下斷點在實際的前端和後端,跳過 compiler driver。 # 可以看到實際上下給前端的命令行選項。 $ clang -c -v sum.c $ lldb clang (lldb) b X86TargetLowering::LowerOperation (lldb) r -cc1 -triple x86_64-apple-macosx10.11.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -main-file-name sum.c -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 274.2 -v -dwarf-column-info -debugger-tuning=lldb -coverage-notes-file /Users/chenwj/Projects/temp/sum.gcno -resource-dir /Users/chenwj/Projects/install/lib/clang/5.0.0 -fdebug-compilation-dir /Users/chenwj/Projects/temp -ferror-limit 19 -fmessage-length 179 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.11.0 -fencode-extended-block-signature -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o sum.o -x c sum.c * 如果使用 GDB,可以下 ''set follow-fork-mode child'' ([[http://stackoverflow.com/questions/28105766/how-to-debug-llvm-source|How to debug llvm source?]])。 * 如果只是要查看後端,可以於 ''llc'' 下斷點。 ====== 內部實現 ====== 透過 gdb 下斷點,觀察 backtrace。 * [[http://clang.llvm.org/docs/InternalsManual.html|"Clang" CFE Internals Manual]] 底下是 Clang 前端主要流程: Driver -> Lex -> Parse -> Sema -> CodeGen (LLVM IR) 分別在 include/clang 和 lib 底下有對應。Driver 負責調用編譯流程中所需的工具鏈,並傳遞相應參數。真正意義上的前端是自 Lex 以後至 CodeGen 的部分。 * [[https://clang.llvm.org/doxygen/Driver_8h_source.html|Driver]] # 可以觀察 driver 如何調用所有工具鏈。 $ clang -v sum.c * [[http://clang.llvm.org/docs/DriverInternals.html|Driver Design & Internals]] * [[https://clang.llvm.org/doxygen/Lexer_8h_source.html|Lexer]] $ clang -cc1 -dump-tokens sum.c * [[http://clang.llvm.org/docs/InternalsManual.html#the-lexer-and-preprocessor-library|The Lexer and Preprocessor Library]] * [[https://clang.llvm.org/doxygen/Parse_2Parser_8h_source.html|Parser]] $ clang -cc1 -fsyntax-only -ast-dump sum.c * [[http://clang.llvm.org/docs/InternalsManual.html#the-parser-library|The Parser Library]] * [[http://clang.llvm.org/docs/IntroductionToTheClangAST.html|Introduction to the Clang AST]] * [[https://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html|TranslationUnitDecl]] 是 AST 根節點,對應當前正在編譯的檔案。 * [[https://clang.llvm.org/doxygen/Sema_8h_source.html|Sema]] * 提供回調函式 ''ActOn'' 供 Parse 調用,建立 AST 和進行語義檢查。 * ''lib/CodeGen'' 迭代 AST 生成 LLVM IR。例如: [[https://clang.llvm.org/doxygen/CodeGenFunction_8h_source.html|CodeGenFunction]]。 * 編譯錯誤或是警告,全部寫成 *.td 檔,位於 ''include/clang/Basic/''。 * [[http://clang.llvm.org/docs/InternalsManual.html#the-diagnostics-subsystem|The Diagnostics Subsystem]] * ''DiagnosticParseKinds.td'' 包含所有 ''lib/Parse/*'' 會報出的警告或錯誤。其它檔案依此類推。想要添加新的警告或是錯誤,可以在 *.td 檔中尋找類似的項目,反推應該在哪裡做相關的檢查。 * Parse 所得資訊皆存成 AST 節點。 * [[http://clang.llvm.org/docs/InternalsManual.html#the-ast-library|The AST Library]] * [[http://clang.llvm.org/docs/InternalsManual.html#canonical-types|Canonical Types]] * [[http://stackoverflow.com/questions/25231080/what-are-canonical-types-in-clang|What are canonical types in Clang?]] * 概念應該近似 GCC 的 [[https://gcc.gnu.org/onlinedocs/gccint/Types.html|TYPE_CANONICAL]]。 * [[http://clang.llvm.org/docs/InternalsManual.html#canonical-types|The QualType class]] * 包含 type 本身,和與其相關連的 qualifier。 ====== IRBuilder ====== 熟悉生成 LLVM IR 生成的方式,和使用到相關的類。 * [[https://clang.llvm.org/doxygen/classclang_1_1CodeGen_1_1CGBuilderTy.html|CGBuilderTy]] * 基本上是 [[http://llvm.org/doxygen/classllvm_1_1IRBuilder.html|IRBuilder]] 的包裝。 * [[https://clang.llvm.org/doxygen/Address_8h.html|Address.h]] * [[https://clang.llvm.org/doxygen/CGValue_8h.html|CGValue.h]] * 基本上是 [[http://llvm.org/doxygen/classllvm_1_1Value.html|Value]] 的包裝。 * [[https://clang.llvm.org/doxygen/classclang_1_1CodeGen_1_1LValue.html|LValue]] * [[https://clang.llvm.org/doxygen/classclang_1_1CodeGen_1_1RValue.html|RValue]] * [[https://clang.llvm.org/doxygen/CodeGenFunction_8h.html|CodeGenFunction.h]] * [[https://clang.llvm.org/doxygen/classclang_1_1CodeGen_1_1CodeGenFunction.html#ada2bbe60d33f290a0ef688d71c491ca8|EmitScalarExpr]] * [[https://clang.llvm.org/doxygen/classclang_1_1CodeGen_1_1CodeGenFunction.html#aa0edab9cd404123428caf6cf599aa09e|EmitLValue]] * [[https://clang.llvm.org/doxygen/CodeGenFunction_8cpp_source.html|CodeGenFunction.cpp]] * 觀察 LLVM IR 生成的方式。 llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType()); * [[https://clang.llvm.org/doxygen/CGBuiltin_8cpp.html|CGBuiltin.cpp]] ====== 函式庫 ====== * [[http://clang.llvm.org/docs/Tooling.html|Choosing the Right Interface for Your Application]] * [[http://llvm.org/devmtg/2010-11/Gregor-libclang.pdf|libclang: Thinking Beyond the Compiler]] $ cat example.c #include "clang-c/Index.h" #include int main(int argc, char *argv[]) { CXIndex Index = clang_createIndex(0, 0); CXTranslationUnit TU = clang_parseTranslationUnit(Index, 0, argv, argc, 0, 0, CXTranslationUnit_None); for (unsigned I = 0, N = clang_getNumDiagnostics(TU); I != N; ++I) { CXDiagnostic Diag = clang_getDiagnostic(TU, I); CXString String = clang_formatDiagnostic(Diag, clang_defaultDiagnosticDisplayOptions()); fprintf(stderr, "%s\n", clang_getCString(String)); clang_disposeString(String); } clang_disposeTranslationUnit(TU); clang_disposeIndex(Index); } $ clang example.c -I/PATH/TO/INCLUDE -L/PATH/TO/LIB -lclang -o example $ export LD_LIBRARY_PATH=/PATH/TO/LIB $ cat bug.c void foo() { int i = 1 } $ ./example bug.c bug.c:2:12: error: expected ';' at end of declaration * [[http://clang.llvm.org/doxygen/group__CINDEX.html|libclang: C Interface to Clang]] ====== Sanitizer ====== * [[https://compiler-rt.llvm.org/|"compiler-rt" runtime libraries]] * [[https://github.com/google/sanitizers]] 是原來的代碼庫,現在已合入 compiler-rt。 * compiler-rt 基本上是 LLVM 版的 [[https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html|libgcc]]。 * [[http://llvm.org/docs/GettingStarted.html|Getting Started with the LLVM System]] 已說明 sanitizer 需要編譯 compiler-rt。 $ cd llvm/projects $ git clone http://llvm.org/git/compiler-rt.git * [[http://clang.llvm.org/docs/AddressSanitizer.html|AddressSanitizer]] 可用。 ====== 靜態檢查 ====== * [[https://clang-analyzer.llvm.org/|Clang Static Analyzer]] * [[http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf|A Memory Model for Static Analysis of C Programs]] * 透過 [[wp>Symbolic execution]] 進行檢查。 # 列出可用的 CHECKER 列表。 $ clang -cc1 -analyzer-checker-help $ cat bug.c #include int main() { int i; printf("%d", i); } $ clang -cc1 -analyze -analyzer-checker=core bug.c bug.c:5:3: warning: Function call argument is an uninitialized value printf("%d", i); ^~~~~~~~~~~~~~~ 1 warning generated. * 編譯整個 project 建議使用 ''scan-build''。 ====== 其它 ====== * 添加 builtin 函式。 * include/clang/Basic/BuiltinsNVPTX.def * lib/CodeGen/CGBuiltin.cpp ====== 外部連結 ====== * [[http://clang.llvm.org/|clang: a C language family frontend for LLVM]] * [[http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Clang-Defending-C-from-Murphy-s-Million-Monkeys|Clang: Defending C++ from Murphy's Million Monkeys]] * [[http://kitoslab.blogspot.tw/2012/01/clang-llvm-as-cross-compiler.html|Clang + LLVM as cross compiler]] * [[http://amnoid.de/tmp/clangtut/tut.html|How to parse C programs with clang: A tutorial in 9 parts]]