Clang Plugin 之 Debug

前面一篇文章 LLVM & Clang 入門 講了如何編寫一個 Clang 插件,而後將插件編譯成一個.dylib的動態連接庫。集成到 Xcode 中就能夠看到效果(正確的結果)。html

在獲得正確結果的過程當中,必不可少的一步就是Debug,沒有任何程序是一蹴而就的,除非你printf一個"Hello, World!",說不定你的world還寫成了word前端

在使用Plugin的模式下咱們是不能打斷點進行 Debug 的,可是咱們能夠在代碼中加日誌,而後在終端中執行命令看日誌進行 Debug。這種低效率(Low)的方式是你想要的嗎?顯然不是。c++

咱們只須要把.dylib動態庫變成可執行文件就能打斷點 debug。LibTooling 或許是一個不錯的選擇。使用 LibTooling 的話,咱們只須要改動不多部分的代碼就能夠。git

LibTooling 簡介github

LibTooling 是一個獨立的庫,它容許使用者很方便地搭建屬於你本身的編譯器前端工具,它基於 C++ 接口,提供給使用者強大全面的 AST 解析和控制能力,同時因爲它與 Clang 的內核過於接近致使它的版本兼容能力比 libclang 差得多,Clang 的變更很容易影響到 LibTooling。libTooling 還提供了完整的參數解析方案,能夠很方便的構建一個獨立的命令行工具。xcode

建立 LibTooling 項目及代碼調整

爲了方便,咱們直接建立一個可執行的LibTooling項目,咱們能夠建立一個名爲QTPluginTooling的項目。bash

  1. 建立過程跟 建立插件 步驟差很少,前面 3 步都是同樣的,只須要把QTPlugin替換爲QTPluginTooling就能夠。app

  2. 只是在第 4 步略有不一樣,QTPluginTooling目錄下的CMakeLists.txt的文件內容爲函數

    set(LLVM_LINK_COMPONENTS
        Support
    )
    
    add_clang_executable(QTPluginTooling
        QTPluginTooling.cpp
    )
    
    target_link_libraries(QTPluginTooling
        PRIVATE
        clangAST
        clangBasic
        clangDriver
        clangFormat
        clangLex
        clangParse
        clangSema
        clangFrontend
        clangTooling
        clangToolingCore
        clangRewrite
        clangRewriteFrontend
    )
    
    if (UNIX)
        set(CLANGXX__LING_OR_COPY create_symlink)
    else()
        set(CLANGXX_LINK_OR_COPY copy)
    endif()
    複製代碼

    tooling_cmakeLists

  3. llvm_xcode目錄下執行$ cmake -G Xcode ../llvm,從新生成一下Xcode項目。Tooling項目在 Xcode 的Clang executables目錄下能夠找到。工具

  4. 將以前 Plugin 的代碼複製過來,新增三個頭文件

    #include "clang/Tooling/CommonOptionsParser.h"
    #include "clang/Frontend/FrontendActions.h"
    #include "clang/Tooling/Tooling.h"
    複製代碼
  5. 新增一個命名空間

    using namespace clang::tooling;
    複製代碼
  6. QTASTAction的繼承改成繼承至ASTFrontendAction

  7. FrontendPluginRegistry註冊插件的方式註釋。更改成main()函數方式

    static llvm::cl::OptionCategory OptsCategory("QTPlugin");
    int main(int argc, const char **argv) {
        CommonOptionsParser op(argc, argv, OptsCategory);
        ClangTool Tool(op.getCompilations(), op.getSourcePathList());
        return Tool.run(newFrontendActionFactory<QTPlugin::QTASTAction>().get());
    }
    複製代碼

最後整個文件的內容能夠在 QTPluginTooling.cpp 看到。

輸入源

若是這時候就run的話則會直接退出。這是由於沒有「輸入源」。咱們能夠在QTPluginToolingScheme加入。

/Users/laiyoung_/Desktop/Plugin/ViewController.m
--
-isysroot
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk
-isystem
-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/10.0.0/include
-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1
-I/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include
-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks
複製代碼

參數解釋

上面在--後面的參數,是傳遞給CICompilation DataBase的,而不是這個命令行工具自己的。好比咱們的ViewController.m,由於有#import <UIKit/UIKit.h>這麼一條語句,以及繼承了UIViewController,那麼語法分析器(Sema)讀到這裏的時候就須要知道UIViewController的定義是從哪裏來的,換句話說就是它須要找到定義UIViewController的地方。怎麼找呢?經過指定的-I-F這些參數指定的目錄來尋找。--後面的參數,能夠理解爲若是你要編譯ViewController.m須要什麼參數,那麼這個後面就要傳遞什麼參數給咱們的 QTPlugin,不然就會看到Console裏打出找不到xxx定義或者xxx.h文件的錯誤。固然由於通常的編譯指令,會有-c參數指定源文件,可是--後面並不須要,由於咱們在--前面就指定了。--這種傳參的方式還有另一種方法,使用-extra-arg="xxxx"的方式指定編譯參數,這樣就不須要--了。

-extra-arg="-Ixxxxxx"
-extra-arg="-Fxxxxxx"
-extra-arg="-isysroot xxxxxx"
xxxxxx表示的路徑
複製代碼

最終效果:

參考文章

若有內容錯誤,歡迎 issue 指正。

Example

轉載請註明出處!

相關文章
相關標籤/搜索