Clang插件开发 - ShenYj/ShenYj.github.io GitHub Wiki
-
clone llvm项目
llvm-project, 仓库地址中已经提供了编译步骤
-
CMake
clang、compiler-rt、libcxx 、libcxxabi 原始仓库以及早期版本的llvm仓库都已经归档,被整合到了llvm-project一个仓库下
进入到llvm-project 目录使用cmake进行编译,生成一个xcode项目
cmake -S llvm -B build -G Xcode -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi"
直到编译成功结束
...
...
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/shenyj/Documents/Code/GitHubSources/llvm-project/build
这样一个llvm的xcode项目就生成了, 用xode打开llvm项目,分别编译clang和clangTooling两个target
参数 | 描述 |
---|---|
-S | Explicitly specify a source directory. |
-B | Explicitly specify a build directory. |
-C | Pre-load a script to populate the cache. |
-D | Create or update a cmake cache entry. |
-U | Remove matching entries from CMake cache. |
-G | Specify a build system generator. |
-T | Specify toolset name if supported by generator. |
-A | Specify platform name if supported by generator. |
--DLLVM_ENABLE_PROJECTS=<...> | semicolon-separated list of the LLVM subprojects you’d like to additionally build. Can include any of: clang, clang-tools-extra, lldb, compiler-rt, lld, polly, or cross-project-tests. For example, to build LLVM, Clang, libcxx, and libcxxabi, use -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi". |
clang和clangTooling两个target编译成功后就开始开始clang插件开发了
-
进入到
llvm-project/clang/tools
路径下,这里存放的都是clang的插件,新建对应插件目录clang-plugin-demo
-
在
llvm-project/clang/tools
路径下的CMakeLists.txt
中最后面添加刚新建的目录,告诉clang需要加载的插件名称
add_clang_subdirectory(clang-plugin-demo)
-
准备插件资源文件
<project dir>/ | CMakeLists.txt <pass name>/ | CMakeLists.txt Pass.cpp ...
-
代码源文件
TestPlugin.cpp
-
CMake文件
CMakeLists.txt
CMake文件中添加如下:
add_llvm_library(clang-plugin-demo MODULE BUILDTREE_ONLY TestPlugin.cpp)
- clang-test 插件的名称
- TestPlugin.cpp 插件的代码文件
LLVM项目中包含示例代码,在
Loadable modules/LLVMHello
下,另外很多已有clang插件都是学习和参照的资源 -
-
CMake重新生成一下Xcode项目
回到
llvm-project
重新编译一遍增量编译,由于第一次我新建的
clang-test
对应target已存在,所以增量编译失败,所以给插件起名字的时候注意不要重名了编译失败log
CMake Error at /Users/shenyj/Documents/Code/GitHubSources/llvm-project/clang/test/CMakeLists.txt:180 (add_custom_target): add_custom_target cannot create target "clang-test" because another target with the same name already exists. The existing target is a module library created in source directory "/Users/shenyj/Documents/Code/GitHubSources/llvm-project/clang/tools/clang-test". See documentation for policy CMP0002 for more details.
编译成功后重新打开LLVM项目,就可以看到自己插件的target了
这里面我命名的文件夹名称和cpp文件名不同,为的是测试验证,一个是路径名,一个是Module的名称,需要注意,另外经过测试发现CMamke编译后llvm项目中生成了两个同名scheme 在 Building LLVM with CMake -
Developing LLVM passes out of source
中有提到,前面是资源的路径,后面是Pass的名称,我理解的是对应的scheme -
在自定义插件target下开始编写代码
-
编写完代码编译下这个target,在
llvm-project/build
的LLVM项目统计目录下的Debug/lib
中可以看到我们编译出的插件:clang-plugin-demo.dylib
,一个动态库
根据自己的需求通过C++编写完代码并生成clang插件后,在使用这个插件前我们需要注意一点,我们的插件是基于当前环境:llvm 和 clang的,使我们从github下载的一个指定版本,与我们本机xcode中内置的版本可能相同,也可能不同,这个很好理解,比如在使用OCLint做代码审查时,由于我们更新了Xcode版本,会同时升级内置的llvm以及clang版本,而在OCLint还未做更新时,这时就会出错,详情可以参考这篇笔记 OCLint 13.0 在Xcode 11下报错
在真正使用前,可以通过终端来测试一下制作的clang插件
命令格式如下:
当前环境llvm编译后clang文件所在路径 \
-isysroot sdk路径 \
-Xclang -load \
-Xclang clang插件(.dylib)路径 \
-Xclang -add-plugin \
-Xclang 插件名 \
-c 源码路径
当前demo实际命令
/Users/shenyj/Documents/Code/GitHubSources/llvm-project/build/Debug/bin/clang \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk \
-Xclang -load \
-Xclang /Users/shenyj/Documents/Code/GitHubSources/llvm-project/build/Debug/lib/clang-plugin-demo.dylib \
-Xclang -add-plugin -Xclang TestPlugin \
-c /Users/shenyj/Desktop/OCDemo/Test/Test/ViewController.m
经过测试满足了我们需要达到的效果,就可以集成Xcode来使用了,毕竟日常开发是在Xcode下进行的
打开自己的项目,在Build Settings -> Other C Flags下添加如下内容:
-Xclang -load -Xclang clang(.dylib)动态库路径 -Xclang -add-plugin -Xclang H clang插件名称
这时我们直接运行项目会build失败, 关键字flat namespace
编译失败log
error: unable to load plugin '/Users/shenyj/Documents/Code/GitHubSources/llvm-project/build/Debug/lib/clang-plugin-demo.dylib': 'dlopen(/Users/shenyj/Documents/Code/GitHubSources/llvm-project/build/Debug/lib/clang-plugin-demo.dylib, 0x0009): symbol not found in flat namespace '__ZN4llvm15SmallVectorBaseIjE13mallocForGrowEmmRm''
/Users/shenyj/Library/Developer/Xcode/DerivedData/WorkSpace-epmwormffbdoiaermqldmxamnvsq/Build/Intermediates.noindex/Test.build/Debug-iphonesimulator/Test.build/Objects-normal/x86_64/main.dia:1:1: warning: Could not read serialized diagnostics file: error("Failed to open diagnostics
这就是前面我们提到的环境问题,插件版本不同步导致
-
同步clang版本
在Build Settings 栏目中新增两项用户定义设置(Add User-Defined Setting):
分别是CC和CXX
- CC对应的是自己编译的clang的绝对路径
- CXX对应的是自己编译的clang++的绝对路径
-
接下来在 Build Settings栏目中搜索 index,将 Enable Index-Wihle-Building Functionality的Default改为NO
接下来就可以在Xcode中使用这个clang插件了
优化
目前仅仅是实现了本地环境下集成并使用了自己开发的clang插件, Build Setting设置是零散的,通过xcconfig来配置会更加醒目和方便
学习
- C++ 编写clang 插件的能力
- 本地编译后的clang插件如何能多端使用