如何在Windows中构建和运行Clang插件

neekobn8  于 2022-11-30  发布在  Windows
关注(0)|答案(2)|浏览(245)

我已经克隆了llvm-project存储库。
然后,我使用

cmake -G "Visual Studio 16" -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON -DLLVM_TARGETS_TO_BUILD=X86 -DCLANG_BUILD_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=install ...\llvm-project\llvm

重要的部分是DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS,如建议的here
解决方案和所有项目都生成了。然后我构建了Clang本身和一个示例Clang插件,这个插件已经在llvm-project源代码中提供了。PrintFunctionNames似乎是Clang插件的Hello World,所以我根据the llvm documentation构建了它。
构建成功运行,现在我在安装目录中有llvm/clang,带有PrintFunctionNames插件。
有两种方法可以让clang使用插件:

clang -cc1 -load PrintFunctionNames.dll -plugin print-fns test.cpp
clang++ -c -Xclang -load -Xclang PrintFunctionNames.dll -Xclang -plugin -Xclang print-fns test.cpp

第一个可以,但是第二个不行。而且,在第一个命令行参数中使用clang也不行。这两个命令都可以使用clang,但是都不能使用clang ,所以看起来clang有问题。另外,省略-c命令并实际构建一个插件激活的可执行文件会产生链接错误(1137)。
看起来clang
不支持dll插件,这很奇怪,因为clang似乎是同一个clang驱动程序,除了与c库链接的预设不同。
我遇到的另一个问题是,当构建树外插件时,cmake install命令无法将库文件clang.lib复制到安装目录,没有它树外插件就无法构建。手动设置此库的路径(位于原始输出目录,而不是cmake install将其他构建输出移动到的位置)似乎可以正确构建树外插件。
但问题依然存在:您不能在Windows上使用Xclang插件加载程序或clang驱动程序。不能使用提供的示例插件,不能使用树外的测试插件。
问题是:我构建clang或者插件的方式有问题吗?如果是这样,-cc1 -load为什么可以使用clang.exe的插件呢?如何构建提供的示例插件并让它与clang
驱动程序一起工作呢?我看过这个GitHub repo,它实现了一个基本的树外插件,但是它没有提供任何关于在windows上构建的信息。

owfi6suc

owfi6suc1#

这不是正确答案,而是所遇到问题的解决方法。
虽然我没有让clang++与任何示例插件一起正常工作,但我现在对这个问题有了一点更好的理解。
使事情复杂化的是Windows。为了使插件可以使用clang符号,clang需要建立一个特殊的clang.lib文件,其中包含这些符号,因为在Windows上没有使用动态库中可执行文件符号的机制。这很好,链接这个额外的库(不会在cmake INSTALL命令中被复制!)使插件能够被构建。但是,任何插件都必须包含clang在CMakeLists文件中构建和定义的必要库。对于PrintFunctionNames示例插件,这些库的定义如下:

clang_target_link_libraries(PrintFunctionNames PRIVATE
    clangAST
    clangBasic
    clangFrontend
    )

然而,Visual Studio项目生成出现了一些问题,只有导出的符号库clang.lib被包含在内。如果您不仅想使用插件,还想让clang生成源文件,则需要手动添加这些库(需要这些链接来解决链接错误1136)。
然而,链接clangFrontend会打乱插件注册机制,为插件创建第二个插件注册表,这是愚蠢的。所以clangFrontend一定不能包含在插件中。但是它需要的所有其他东西都必须链接进去,即使cmake没有用这样的设置生成项目,这样编译器就不会抛出链接错误。
至于金属撞击声仍然不起作用:我广泛地研究了clang的编译步骤,发现clang.exe只是作为编译后的步骤被复制为clang.exe。由于二进制文件的大小完全相同,我想知道是否有任何区别。据我所知,您可以只使用clang.exe编译器编译C代码(驱动程序),所以只使用clang.exe似乎是好的。但是,IDE集成,期望clang的外部项目不能使用插件,所以存在这个问题。也许用符号链接重定向clang++调用可能是解决这个问题的一个方法。

o2rvlv0m

o2rvlv0m2#

我很肯定这是行不通的,因为Linux中.so文件的链接方式(很像静态库)与will的链接方式有很大的区别,而DLL与加载模块的分离程度更高。这意味着每个DLL的注册表静态成员都是独立的,clang.exe不知道实际的注册信息。
我确实尝试过通过在DLL中添加一个C函数来解决这个问题,这个函数可以返回注册的插件对象类型列表。这让插件注册了,但它绝对不起作用,因为AST遍历机制依赖于比较单例对象的地址,而在DLL系统中,这些单例在每个DLL中都是重复的,导致Assert,因为没有地址匹配。在我的例子中,有一个浮点类型没有找到,因为两个内容相同的对象的地址被比较。我的猜测是有很多这样的问题,不值得追究。
我最后做的是把插件静态地链接到clang驱动程序上,这样就可以了,但是要注意,你必须把它作为一个obj文件直接链接到exe项目上,或者确保引用在它里面声明的某个实体,比如主模块。这就确保了添加插件的静态对象实际上包含在链接中。

相关问题