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',
linux下SNMP的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