前面一篇文章 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
項目,咱們能夠建立一個名爲QTPluginTooling
的項目。bash
建立過程跟 建立插件 步驟差很少,前面 3 步都是同樣的,只須要把QTPlugin
替換爲QTPluginTooling
就能夠。app
只是在第 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()
複製代碼
在llvm_xcode
目錄下執行$ cmake -G Xcode ../llvm
,從新生成一下Xcode
項目。Tooling
項目在 Xcode 的Clang executables
目錄下能夠找到。工具
將以前 Plugin 的代碼複製過來,新增三個頭文件
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/Tooling.h"
複製代碼
新增一個命名空間
using namespace clang::tooling;
複製代碼
將QTASTAction
的繼承改成繼承至ASTFrontendAction
。
將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
的話則會直接退出。這是由於沒有「輸入源」。咱們能夠在QTPluginTooling
的Scheme
加入。
/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
複製代碼
參數解釋:
上面在
--
後面的參數,是傳遞給CI
的Compilation 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 指正。
轉載請註明出處!