1. 程式人生 > >LLVM在Windows下使用VisualStudio2017新增編譯自定義pass

LLVM在Windows下使用VisualStudio2017新增編譯自定義pass

該方法仍然有效,只不過還需要一些修改,遇到的錯誤需要解決。

錯誤1

CMake Error at CMakeLists.txt:658 (message):
  Unexpected failure executing llvm-build: llvm-build: fatal error: missing
  LLVMBuild.txt file at:
  'F:\\svnlocal\\temp\\llvm\\llvm6.0/lib\\Transforms\\Hello\\LLVMBuild.txt'

這樣的錯誤是說明缺少LLVMBuild.txt檔案,只要在CMakeLists.txt的同目錄下配置一個LLVMBuild.txt

檔案。

錯誤2

CMake Error at CMakeLists.txt:658 (message):
  Unexpected failure executing llvm-build: Traceback (most recent call last):

    File "F:/svnlocal/temp/llvm/llvm6.0/utils/llvm-build/llvm-build", line 6, in
 <module>
      llvmbuild.main()
    File "F:\svnlocal\temp\llvm\llvm6.0\utils\llvm-build\llvmbuild
\main.py", lin e 952, in main opts.optional_components) File "F:\svnlocal\temp\llvm\llvm6.0\utils\llvm-build\llvmbuild\main.py", lin e 332, in write_library_table tg = c.get_parent_target_group() File "F:\svnlocal\temp\llvm\llvm6.0\utils\llvm-build\llvmbuild\componentinfo .py", line 87, in get_parent_target_group return self.parent_instance.get_parent_target_group() File "F:\svnlocal
\temp\llvm\llvm6.0\utils\llvm-build\llvmbuild\componentinfo .py", line 87, in get_parent_target_group return self.parent_instance.get_parent_target_group() File "F:\svnlocal\temp\llvm\llvm6.0\utils\llvm-build\llvmbuild\componentinfo .py", line 87, in get_parent_target_group return self.parent_instance.get_parent_target_group() [Previous line repeated 992 more times] File "F:\svnlocal\temp\llvm\llvm6.0\utils\llvm-build\llvmbuild\componentinfo .py", line 82, in get_parent_target_group if self.type_name == 'TargetGroup': RecursionError: maximum recursion depth exceeded in comparison

最初看到這個錯誤還以為LLVM不支援Python3,於是安裝了Python2,結果發現問題依然存在。最後確定下來原因是:LLVMBuild.txt內容的parent配置不正確,正確的配置是:LLVMBuild.txt檔案的父目錄的父目錄,例如llvm/lib/Transforms/Custom(或者llvm/lib/Transforms/Hello)下的LLVMBuild.txt內容中parent應該是Transforms,這裡放一個完整的llvm/lib/Transforms/Custom/LLVMBuild.txt內容:

[component_0]
type = Library
name = Custom
parent = Transforms

這一點上,原參考文章裡是沒有介紹的,需要自己摸索。

錯誤3

-- Clang version: 6.0.0
-- SampleAnalyzerPlugin ignored -- Loadable modules not supported on this platform.
-- PrintFunctionNames ignored -- Loadable modules not supported on this platform.
-- AnnotateFunctions ignored -- Loadable modules not supported on this platform.
CMake Error at cmake/modules/LLVM-Config.cmake:105 (target_link_libraries):
  Target "LLVMCustom" of type UTILITY may not be linked into another target.
  One may link only to INTERFACE, STATIC or SHARED libraries, or to
  executables with the ENABLE_EXPORTS property set.
Call Stack (most recent call first):
  cmake/modules/LLVM-Config.cmake:93 (explicit_llvm_config)
  cmake/modules/AddLLVM.cmake:759 (llvm_config)
  cmake/modules/AddLLVM.cmake:860 (add_llvm_executable)
  tools/bugpoint/CMakeLists.txt:24 (add_llvm_tool)


-- BugpointPasses ignored -- Loadable modules not supported on this platform.
CMake Error at cmake/modules/LLVM-Config.cmake:105 (target_link_libraries):
  Target "LLVMCustom" of type UTILITY may not be linked into another target.
  One may link only to INTERFACE, STATIC or SHARED libraries, or to
  executables with the ENABLE_EXPORTS property set.
Call Stack (most recent call first):
  cmake/modules/LLVM-Config.cmake:93 (explicit_llvm_config)
  cmake/modules/AddLLVM.cmake:759 (llvm_config)
  cmake/modules/AddLLVM.cmake:860 (add_llvm_executable)
  tools/opt/CMakeLists.txt:26 (add_llvm_tool)


-- Configuring incomplete, errors occurred!
See also "F:/svnlocal/temp/llvm/llvm6.0/build/CMakeFiles/CMakeOutput.log".
See also "F:/svnlocal/temp/llvm/llvm6.0/build/CMakeFiles/CMakeError.log".

這個錯誤是因為我偷懶導致,直接複製了Hello資料夾下的CMakeLists.txt,然後只修改了LLVMHello為:LLVMCustom

add_llvm_loadable_module( LLVMCustom
  MyPass.cpp
  Custom.cpp

  DEPENDS
  intrinsics_gen
  PLUGIN_TOOL
  opt
  )

實際上應該是add_llvm_library:

add_llvm_library( LLVMCustom
    MyPass.cpp
    Custom.cpp
)

這一點參考文章是正確的,只是因為直接複製了Hello的CMakeLists.txt而沒有完全修改正確而已,add_llvm_loadable_module也要修改掉,修改為add_llvm_library

錯誤4

CMake Error at cmake/modules/AddLLVM.cmake:1333 (add_dependencies):
  The dependency target "LLVMHello" of target "check-all" does not exist.
Call Stack (most recent call first):
  CMakeLists.txt:919 (add_lit_target)


CMake Error at cmake/modules/AddLLVM.cmake:1333 (add_dependencies):
  The dependency target "LLVMHello" of target "check-llvm" does not exist.
Call Stack (most recent call first):
  cmake/modules/AddLLVM.cmake:1354 (add_lit_target)
  test/CMakeLists.txt:157 (add_lit_testsuite)

llvm/test/CMakeLists.txt中刪除LLVMHello,如果出現類似的錯誤,就找到所有有關Hello工程的CMakeLists.txt和LLVMBuild.txt,把關於對Hello的行註釋掉或去掉。

錯誤5

not found unwrap

參考文章的CPP檔案程式碼中少了標頭檔案引用,導致unwrap找不到,正確的Custom.cpp程式碼如下:

#include "llvm/InitializePasses.h"
#include "llvm-c/Initialization.h"
#include "llvm/InitializePasses.h"
#include "llvm/PassRegistry.h"


using namespace llvm;

/// initializeCustom - Initialize all passes in the Custom library
void llvm::initializeCustom(PassRegistry &Registry) {
  initializeMyPassPass(Registry);
}

/// LLVMInitializeCustom - C binding for initializeCustom.
void LLVMInitializeCustom(LLVMPassRegistryRef R) {
    initializeCustom(*unwrap(R));
}

梳理一遍完整的步驟

基於llvm6.0介紹

步驟1:建立模組及原始碼檔案

在llvm/lib/Transforms目錄下建立一個Custom資料夾,這裡存放要自定義的pass,建立一個MyPass.cpp,內容如下:

#define DEBUG_TYPE "mypass"
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Custom.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {
  struct MyPass : public FunctionPass {
      bool m_flag;
    static char ID;
    MyPass() : MyPass(ID) { m_flag = false; }
    MyPass(bool flag) : FunctionPass(ID) {
        this->m_flag = flag;
      initializeMyPassPass(*PassRegistry::getPassRegistry());
    }

    /*
     * Just print the function name 
     */
    bool runOnFunction(Function &F) {
        bool Changed = false;
        if (m_flag == false) {
            return Changed;
        }

        errs().write_escaped(F.getName()) << "\n";
        return Changed;
    }
  };
}

char MyPass::ID = 0;
INITIALIZE_PASS(MyPass, "mypass", "Print all function names", false, false)

FunctionPass *llvm::createMyPassPass(bool flag) {
  return new MyPass(flag);
}

再建立一個Custom.cpp,內容如下:

#include "llvm/InitializePasses.h"
#include "llvm-c/Initialization.h"
#include "llvm/InitializePasses.h"
#include "llvm/PassRegistry.h"


using namespace llvm;

// initializeCustom - Initialize all passes in the Custom library
void llvm::initializeCustom(PassRegistry &Registry) {
  initializeMyPassPass(Registry);
}

// LLVMInitializeCustom - C binding for initializeCustom.
void LLVMInitializeCustom(LLVMPassRegistryRef R) {
    initializeCustom(*unwrap(R));
}

步驟2 配置LLVMBuild.txt和CMakeLists.txt

在Custom資料夾下建立LLVMBuild.txt,內容如下:

[component_0]
type = Library
name = Custom
parent = Transforms

簡單解釋下:
- type:是該模組的編譯後的檔案形式,這裡是Library,也就是編譯作為庫檔案。
- name:是該模組的名稱,這裡就填Custom,一般跟當前所在的資料夾同名。
- parent:當前資料夾的父目錄,一般是Transforms。

在Custom資料夾下建立CMakeLists.txt,內容如下:

add_llvm_library( LLVMCustom
    MyPass.cpp
    Custom.cpp
)

步驟3 建立模組包含標頭檔案

在llvm/include/llvm/Transforms/目錄下建立Custom.h,內容如下:

#ifndef LLVM_CUSTOM_H
#define LLVM_CUSTOM_H

#include "llvm/Pass.h"


namespace llvm {

FunctionPass *createMyPassPass(bool flag);

}

#endif

開啟編輯檔案llvm/include/llvm/InitializePasses.h,在名稱空間llvm中的程式碼塊末尾新增程式碼:

void initializeCustom(PassRegistry&);
void initializeMyPassPass(PassRegistry&);

開啟編輯檔案llvm/include/llvm/LinkAllPasses.h,在ForcePassLinking建構函式中新增程式碼:

#include "llvm/Transforms/Custom.h"

// This part must reside in the constructor of struct ForcePassLinking
(void) llvm::createMyPassPass(true);

步驟4 修改各種LLVMBuild.txt和CMakeLists.txt

  • 修改llvm/lib/Transforms/LLVMBuild.txt,common節的subdirectories內容新增:Custom
  • 修改llvm/lib/Transforms/CMakeLists.txt,末尾新增:
add_subdirectory(Custom)
  • 修改llvm/tools/opt/LLVMBuild.txt,required_libraries內容新增:Custom
  • 修改llvm/tools/opt/CMakeLists.txt,在set(LLVM_LINK_COMPONENTS中新增:Custom
  • 修改llvm/tools/bugpoint/LLVMBuild.txt,required_libraries內容新增:Custom
  • 修改llvm/tools/bugpoint/CMakeLists.txt在set(LLVM_LINK_COMPONENTS中新增:Custom

步驟5 修改opt.cpp

修改llvm/tools/opt/opt.cpp,在main函式中新增程式碼:

initializeCustom(Registry);

步驟6 CMake GUI重新生成下sln

因為是直接修改的CMakeLists.txt和LLVMBuild.txt,VisualStudio是識別不了的,如果直接編譯opt專案最終會出現連結錯誤,提示找不到Custom中新增的函式。

這個時候再次開啟CMakeGUI再次生成下sln工程,由於CMakeGUI有快取機制,不會對其他檔案造成修改,速度是很快的。

目的就是要讓llvm/lib/Transforms/CMakeLists.txt中的這句生效:

add_subdirectory(Custom)

然後重新開啟VisualStudio,直接定位到opt專案,單獨編譯即可。

編譯執行

VisualStudio2017開啟專案工程,找到Tools分組下的opt,單獨編譯,比全部編譯時間會少一些。連結的過程略長,編譯的opt.exe在llvm/build/Debug/bin目錄下,debug版本的有100多MB!總共耗時30多分鐘吧,也夠長的了。

命令列下執行

opt.exe -help

輸出的內容:

……
-mypass                                         - Print all function names
……

說明自定義的pass已經被編譯進opt裡啦。

原理解讀

上面程式碼中並沒有看到函式initializeMyPassPass的定義,這個是由巨集INITIALIZE_PASS自動生成的。

INITIALIZE_PASS(MyPass, "mypass", "Print all function names", false, false)

可以參見INITIALIZE_PASS巨集定義:

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)                    \
  static void *initialize##passName##PassOnce(PassRegistry &Registry) {        \
    PassInfo *PI = new PassInfo(                                               \
        name, arg, &passName::ID,                                              \
        PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis);     \
    Registry.registerPass(*PI, true);                                          \
    return PI;                                                                 \
  }                                                                            \
  static llvm::once_flag Initialize##passName##PassFlag;                       \
  void llvm::initialize##passName##Pass(PassRegistry &Registry) {              \
    llvm::call_once(Initialize##passName##PassFlag,                            \
                    initialize##passName##PassOnce, std::ref(Registry));       \
  }

整合到CLANG

完成上面的步驟,可以把pass整合到opt中,但是如果使用clang的話是沒有這些功能的,所以仍需要做些處理。
- llvm/lib/Transforms/IPO/PassManagerBuilder.cpp

#include "llvm/Transforms/Custom.h"

static cl::opt<bool>
MyPass("mypass", cl::init(false), cl::Hidden,
    cl::ZeroOrMore, cl::desc("Print all function names"));

在PassManagerBuilder::populateModulePassManager函式中新增:

MPM.add(createMyPassPass(MyPass));

這裡設計的是一個開關,當用戶使用了-mllvm -mypass引數的時候,MyPass為true,相當於啟用了該pass。

  • llvm/lib/Transforms/IPO/LLVMBuild.txt新增Custom
  • llvm/lib/Target/X86/LLVMBuild.txt新增Custom

最後記住用CMkaeGUI重新生成一下解決方案,然後VisualStudio只編譯clang模組即可。

使用clang時開啟該pass:

clang.exe -mllvm -mypass example.c -o example.exe

相關推薦

LLVM在Windows使用VisualStudio2017新增編譯定義pass

該方法仍然有效,只不過還需要一些修改,遇到的錯誤需要解決。 錯誤1 CMake Error at CMakeLists.txt:658 (message): Unexpected failure executing llvm-build: l

LLVM在Windows用opt呼叫定義pass

步驟1 建立測試C程式碼 首先編寫一個測試用的C程式碼example.c,內容如下: #include<stdio.h> void test() { printf("hello\n"); } int main(int argc, c

Yii2框架 model方法setAttributes用法(定義model 新增方法)

正如我們知道的yii2框架中一般使用的增加資料有兩種方式 1、使用createCommand()方法: Yii::$app->db->createCommand()->insert('user', [       'name' => 'test', 

linuxSNMP的extend--定義監控

linux snmp extend snmp除了具有系統默認的監控項,還提供了一個強大的功能,可自定義監控項。在snmpd.conf配置文件中的exec選項(高版本的snmp中,extend替代了exec)提供了自定義的監控功能,可以將命令或者腳本的執行結果添加到snmp的查詢中。格式為:extend

Unity NGUI UIPanel對粒子或定義Mesh的剪裁

ngui unity uipanel 裁切 剪裁 粒子 寫在開篇: 越來越煩那些無腦轉發自己不做驗證的博主論壇樓主,網上好不容易找到一些資料,結果代碼搞下來卻是錯的,有些確實是因為版本問題太老不兼容,但是有些明顯是有問題的,轉發前自己試試就知道肯定是不能用的。結果。。。哎。。。真

[Visual Studio C++] [MFC] 新增使用者定義訊息及訊息響應函式講解

一、前言           本文介紹 兩種方法 新增使用者自定義訊息及訊息響應函式。  第一種,使用者手動新增兩個檔案((.h)和 (.cpp))的內容。  第二種,利用 MFC 的整合功能,自動新增。(推薦

在NetSuite Sublist,增加/刪除定義記錄行

NetSuite 產品群:779253701 在實施過程中,遇到一個客戶的需求:在聯絡人介面增加從業經歷,記錄其之前所在公司、起止時間、部門和職務。這要求在NetSuite的標準聯絡人記錄中,增加一個“從業經歷”的sublist,並可以增加/刪除和修改行資訊,即從業經歷條目。 在Goog

iOS-對圖片操作---新增定義相簿

轉自:https://www.jianshu.com/p/7113c2c15e2c   圖片操作---新增到自定義相簿 實際上,自定義相簿中的圖片並不是實際的圖片,而是對系統【相機膠捲】這個相簿中的圖片進行一個引用,所以將圖片儲存到自定義相簿的第一步就是先儲存到系統的【相機膠捲

Maven編譯定義jar包

在實際開發過程中經常遇到需要呼叫第三方jar包的情況,這裡有兩種解決方式: 1.將第三方jar包放在lib下(之前的處理方式,不過多介紹) 2.將第三方jar包打入maven倉庫,在pom.xml加入配置即可    mvn install:install-file -

關於nagios系統使用shell指令碼定義監控外掛的編寫以及沒有實時監控圖的問題

關於nagios系統下shell自定義監控外掛的編寫、指令碼規範以及沒有實時監控圖的問題的解決辦法 在自已編寫監控外掛之前我們首先需要對nagios監控原理有一定的瞭解 Nagios的功能是監控服務和主機,但是他自身並不包括這部分功能,所有的監控、檢測功能都是通過各種外掛來完成的。 啟動Nagios後,

在MFC中新增使用者定義訊息

首先弄清楚兩點: (1)誰要傳送這個訊息(2)誰要接受這個訊息。   用一個簡單的例子來說明。物件A向B(也可以就是A到A)傳送訊息。   1 傳送訊息   首先在A的標頭檔案中定義這個訊息:     #define WM_USERMESSAGE WM_USER+30      所有自定義訊息都

[C++][Visual Studio] [MFC] 新增使用者定義訊息及訊息響應函式講解

一. 在對應類的標頭檔案中自定義訊息。          程式碼: #define WM_MyMessage  WM_USER+100            說明:                             MFC自有的訊息都是在WM_USER內的,所以

Android8.1 新增系統定義服務一 (SELinux許可權)

           一開始並沒有注意到android8.0以後和之前有多大區別,知道最近有需求要求增加一個自定義服務,一直沒有生效報avc許可權問題 在SystemServer startOthreService中 ServiceManager.addService (

C# 直接建立一個DataTable,併為之新增資料(定義DataTable)

DataTable dt=new DataTable("cart"); DataColumn dc1=new DataColumn("prizename",Type.GetType("System.String")); DataColumn dc2=new Da

Pixhawk---通過串列埠方式新增一個定義感測器(超聲波為例)

Pixhawk—新增一個自定義感測器—超聲波(串列埠方式) 1 說明   首先超聲波模組是通過串列埠方式傳送(Tx)出資料,使用的模組資料傳送週期為100ms,資料格式為: R0034 R0122 R0122 R0046 R0127 R0044 R00

.NET開發環境VS中新增簡單定義程式碼段

程式碼段極大增加了我們的開發效率,使我們可以快速調出固定的程式碼格式。 比如說,我們在程式中輸入cw,並按下兩次tab鍵,開發環境就會自動為我們生成程式碼。 按兩下tab鍵後 再比如我們輸入 prop 自動生成 我們只需要改一下相應的屬性型別和屬性名即可。 我們

關於RecyclerView的拉重新整理,定義幀動畫,第三方框架PtrFrameLayout使用手冊

首先放上一張gif圖片 首先是xml檔案:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res

照片儲存到相簿,並新增定義相簿中

-(void)addAssetURL:(NSURL*)assetURL toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock { //相簿存在標

為自己的站點新增Google定義搜尋

這裡面很多都不需要設定,呼叫的時候一般都是設定在程式碼中。點選獲取程式碼,可以檢視你的程式碼,其實是一段js程式碼,格式如下:<script>  (function() {    var cx = '000737368xxxxxxxxxxx:yyyyyyyyy';    var gcse = do

CC2640之新增一個定義的特性值

測試環境 協議棧版本:BLE-STACK V2.1 IAR開發環境版本:IAR for Arm 7.40 硬體裝置:Amo-SmartRF v2.0 開發板(對應TI官方的SmartRF06EB 開發板) 示例測試Demo工程:simpleBLEPeriphera