1. 程式人生 > >LLVM之編寫我的第一個Clang外掛

LLVM之編寫我的第一個Clang外掛

外掛效果圖
外掛效果圖

步驟:

1、原始碼編譯

clang需要用CMake和Ninja來編譯,可以通過Homebrew安裝

  • 安裝brew。官網:https://brew.sh/
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  • 安裝cmake和ninja
$ brew install cmake
$ brew install ninja
  • ninja如果安裝失敗,可以直接從github獲取release版放入【/usr/local/bin】中。官網:https://github.com/ninja-build/ninja/releases 

2、原始碼下載

  • 下載llvm;大小 648.2 M,僅供參考
$ git clone https://git.llvm.org/git/llvm.git/
  •  下載clang。注意要在剛下載的llvm資料夾下的tools下
$ cd llvm/tools
$ git clone https://git.llvm.org/git/clang.git/

3、原始碼編譯 

  • 使用ninja 編譯

1、在LLVM原始碼同級目錄下新建一個【llvm_build】目錄(最終會在【llvm_build】目錄下生成【build.ninja】

$ cd llvm_build
$ cmake -G Ninja ../llvm -DCMAKE_INSTALL_PREFIX=../llvm_release

2、依次執行編譯、安裝指令。編譯完畢後, 【llvm_build】目錄大概 21.05 G(僅供參考),安裝完畢後,安裝目錄大概 11.92 G(僅供參考)

$ ninja
$ ninja install

在llvm同級目錄下新建一個【llvm_xcode】目錄 

  • 使用Xcode編譯 
$ cd llvm_xcode
$ cmake -G Xcode ../llvm


在 llvm_Xcode 目錄下開啟 LLVM.xcodeproj 檔案,選擇自動建立 Schemes: 

選擇 ALL_BUILD,來編譯,大概要一個小時以上

4、編寫外掛

這個外掛實現的功能是檢測類中的宣告規範,如果有下劃線就報錯並提示警告資訊

1、在llvm/tools/clang/tools原始碼目錄下新建一個外掛目錄,我取名叫做wsh_plugin。如圖所示

2、修改如下圖所示的CMakeLists.txt檔案,在最後一行新增add_clang_subdirectory(wsh-plugin)

3、在wsh-plugin資料夾中新增WSHPlugin.cpp,用於編寫外掛程式碼

4、在wsh-plugin資料夾中新增CMakeLists.txt檔案,並新增內容add_llvm_loadable_module(WSHPlugin WSHPlugin.cpp),如下圖所示。

5、在WSHPlugin.cpp中編寫如下程式碼

#include <iostream>
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendPluginRegistry.h"

using namespace clang;
using namespace std;
using namespace llvm;
using namespace clang::ast_matchers;

namespace WSHPlugin {
    class MJHandler : public MatchFinder::MatchCallback {
    private:
        CompilerInstance &ci;
        
    public:
        MJHandler(CompilerInstance &ci) :ci(ci) {}
        
        void run(const MatchFinder::MatchResult &Result) {
            if (const ObjCInterfaceDecl *decl = Result.Nodes.getNodeAs<ObjCInterfaceDecl>("ObjCInterfaceDecl")) {
                size_t pos = decl->getName().find('_');
                if (pos != StringRef::npos) {
                    DiagnosticsEngine &D = ci.getDiagnostics();
                    SourceLocation loc = decl->getLocation().getLocWithOffset(pos);
                    D.Report(loc, D.getCustomDiagID(DiagnosticsEngine::Error, "溫馨提示:類名中不能帶有下劃線"));
                }
            }
        }
    };
    
    class MJASTConsumer: public ASTConsumer {
    private:
        MatchFinder matcher;
        MJHandler handler;
        
    public:
        MJASTConsumer(CompilerInstance &ci) :handler(ci) {
            matcher.addMatcher(objcInterfaceDecl().bind("ObjCInterfaceDecl"), &handler);
        }
        
        void HandleTranslationUnit(ASTContext &context) {
            matcher.matchAST(context);
        }
    };
    
    class MJASTAction: public PluginASTAction {
    public:
        unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &ci, StringRef iFile) {
            return unique_ptr<MJASTConsumer> (new MJASTConsumer(ci));
        }
        
        bool ParseArgs(const CompilerInstance &ci, const vector<string> &args) {
            return true;
        }
    };
}

static FrontendPluginRegistry::Add<WSHPlugin::MJASTAction>
X("WSHPlugin", "The WSHPlugin is my first clang-plugin.");

6、編寫完程式碼後,重新輸入一下命令

cmake -G Xcode ../llvm

然後選擇WSHPlugin這個target進行編譯。編譯完之後會在product中生成一個動態庫檔案“WSHPlugin.dylib”。如圖所示

 

5、載入外掛

1、hack Xcode首先要對Xcode進行Hack,才能修改預設的編譯器

下載【XcodeHacking.zip】,解壓,修改【HackedClang.xcplugin/Contents/Resources/HackedClang.xcspec】的內容,設

置一下自己編譯好的clang的路徑

然後在XcodeHacking目錄下進行以下命令列,將XcodeHacking的內容剪下到Xcode內部 

$ sudo mv HackedClang.xcplugin `xcode-select -print-
path`/../PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins


$ sudo mv HackedBuildSystem.xcspec `xcode-select -print- path`/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications

執行完以上操作後,重啟Xcode

2、點選 Target 的 Build Settings,修改 Compiler for C/C++/Objective-C 項為 Clang LLVM Trunk

3、在Xcode專案中指定載入外掛動態庫:Build Settings > OTHER_CFLAGS,下圖示記地方按自己需求修改

以上操作結束後編譯就會得到文章開頭的圖所示效果。

6、總結

在第5部hackXcode的時候路徑要注意是編譯之後product下的clang路徑,如果寫錯路徑並已經替換了原來Xcode的HackedClang.xcplugin檔案,可以通過前往“/Applications/Xcode.app/Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/HackedClang.xcplugin”這個路徑去重新替換。

相關推薦

LLVM編寫一個Clang外掛

外掛效果圖步驟: 1、原始碼編譯 clang需要用CMake和Ninja來編譯,可以通過Homebrew安裝 安裝brew。官網:https://brew.sh/ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubuser

CLANG技術分享系列一:編寫你的一個CLANG外掛

轉:http://kangwang1988.github.io/blog/ 引子 以前遇到一個需求,檢測iOS App程式碼中使用到的API是否存在開始支援的系統版本高於當前deploy target,或已經在當前支援的最新系統之前(包括當前系統)已經被標記為棄用(depr

一個vscode外掛

max+ 遊戲 資訊 一個可以讓你在vscode中閱讀max+上的遊戲資訊的小外掛. 特徵 支援的遊戲資訊:守望先鋒、爐石傳說、CSGO、Dota2,安裝後直接可以從側邊欄中開啟使用和切換遊戲,前提時你需要連線網路才能獲取資訊資料. 由於vscode的限制,資訊中的視訊無法播放. 示例: 要求 需要網路連

編寫一個maven外掛(含完整專案)

基本上快把maven實戰這本書看完了,對裡面的知識點不敢說全懂,但至少懂了個百分之六七十,不過大部分概念還是清楚地, 剩下的就需要實際的碼程式碼中去學習了。 迴歸正題,編寫一個maven外掛: 第一步: 建立一個maven專案,可以用命令列的方式建立如:mvn archet

USTCOJ程式碼檢視功能的實現(一個Chrome外掛,UstcOjSourceView)

因工作需要,會不時的在USTCOJ上產看程式原始碼。檢視原始碼的流程通常是這樣的: 1,根據指定題號、賬號,或許相關的RunID。 3,在如下所示的輸入框中輸入RunID號,點選View按鈕檢視程式碼。 (圖片一) 採用這種方式檢視原始碼是相當痛苦的,因為judge.p

使用python編寫BurpSuite外掛(2. 編寫你的一個burp外掛

執行外掛的一些基本要點 在我們以任何語言執行burp外掛之前,我們需要明白:burp尋找一個名為BurpExtender的class來啟動(class不需要包含任何引數),之後再呼叫registerExtenderCallbacks()方法,且該方法包含cal

dotNet Core初學創建一個dotNetCore項目

程序包 -o 視圖控制器 top tar 一個 lex .net core database 首先創建解決方案dotNetCrazy 一、創建項目 1、這裏選擇.Net Core 選擇ASP.NET Core Web 應用程序 名稱暫且叫CoreCrazy 這裏我們選擇

Jenkins高階篇Pipeline-2-一個Pipeline指令碼練習

前面一篇,介紹了什麼是Pipeline,和Pipeline的基本概念,和幾個關鍵字的基本含義的介紹,真正的涉及到Pipeline的語法還沒有開始介紹。這篇先來介紹第一個Pipeline程式碼,分別用兩種模式來寫,逐漸開始展開Pipeline的語法學習。 1.前提條件準備 1)準備一個Je

Jenkins高階篇Pipeline-3-一個Pipeline程式碼詳細解釋

        前面一篇,我用Jenkins支援的指令碼輸入框執行構建,還用了github上拉取程式碼下來進行構建專案。這篇,就來詳細解釋下每行程式碼的含義,還有就是複習一下第一篇提到的幾個關鍵字,這樣的基礎中的基礎知識。

C++禿頭旅:一個C++程式

經典的程式,列印hello,world:   //C++的第一個程式,列印hello world #include <iostream> //標頭檔案 意思:stdio in out stream using namespace std; int main()

【python】用Notepad++編寫一個python程式

首先我們要安裝Notepad++ 官網下載:https://notepad-plus-plus.org/ 網盤下載:https://pan.baidu.com/s/1b3FNZ8w47HYes57YeG3KmA 提取碼: cu89 安裝簡單,選擇簡體中文安裝就好了,中間會有個配置安裝路徑

開發一個VUE外掛

背景 專案中用到element-ui,裡面用到了彈出元件,但是效果不太滿意,於是自己就想寫一個簡單的彈出元件。目前已經發布到npm:可以通過npm i dialog-wxy -s 進行下載使用頁面呼叫效果: 實現步驟 第一步 搭建vue簡單工程 vue init w

一個AndroidStudio外掛,一鍵建立Activity

前言 之前寫過一個建立Activity的Gradle外掛CreateActivityPlugin,但是使用起來並非像使用AndroidStudio自帶的功能new Activity一樣方便。 而且我也做了一些思考,覺得建立Activity這個過程,其實和Grad

一個JS外掛——輪播圖

開發外掛,本人這裡採用的是模組化開發方式(Module),確保記憶體中只有一個物件引用,這樣可以節省記憶體,也可以使程式碼簡潔高效。 // 這裡採用()()這種自呼叫函式,形成閉包,內部函式是一個匿名函式,防止外掛使用者定義函式與外掛衝突。 (function(){ "use stri

Clang 旅--使用 Xcode 開發 Clang 外掛

前言 最近在跟老大的聊天中聊到了一個比較特殊的需求:是否有辦法在編譯階段檢查某個方法的引數與返回值的型別相同,如果型別不一致的話能丟擲編譯錯誤的提示。這似乎已經不是 Objective-C 或者 Swift 的語言語法本身所能解決的了,老大還指點了可以從編譯器

oracle資料庫學習遇到的一個坑,查詢

今天再看oracle查詢語句,在定義大小寫問題上 我新建了一個表,名為user表,全都是小寫的,裡面的欄位也全是小寫,在執行select * from user時就出現了問題,告訴我找不到表 然後我看了一下Navicat下面自己執行的查詢,原來是在user上面加了雙引號,嘗

學習 | Python簡介&安裝&一個Python程式

一文推薦的廖雪峰的教程,有同學建議基於此寫一系列實踐過程,那麼從本篇開始,會陸續寫Python的

新手上路Hibernate:一個Hibernate例子

一、Hibernate概述 (一)什麼是Hibernate?            Hibernate核心內容是ORM(關係物件模型)。可以將物件自動的生成資料庫中的資訊,使得開發更加的面向物件。這樣

1.跨平臺開發~ VSCode開發一個C程式

寫一個簡單的C,然後F5執行,根據提示來配置檔案 刪掉前面的內容 執行發現還是不行,Ctrl+Shift+B,輸入Task 選擇Others 把command和args配置一下,${file}代表當前開啟檔案 Ctrl+Shift+B生成一下 F5執行除錯

如何為Apache JMeter開發外掛(二)——一個JMeter外掛

本篇將開啟為JMeter開發外掛之旅,我們選擇以Function(函式)元件作為外掛開發的入手物件,在前面的章節我們將其劃分為非GUI元件,選擇它的理由不僅僅是因為Function外掛在開發方面是極簡的,而且在實際運用JMeter執行測試時,對於Function