c - 如何使用 clang -emit-llvm 编译和保留“未使用”的 C 声明
问题描述
语境
我正在为需要大量运行时函数的语言编写编译器。我使用 LLVM 作为我的后端,因此 codegen 需要所有这些运行时类型(函数、结构等)的类型,而不是使用 LLVM API 手动定义所有这些类型或手写 LLVM IR 我想写C 中的头文件并编译为编译器可以使用LLVMParseBitcodeInContext2
.
问题
我遇到的问题是 clang 似乎没有保留任何函数定义未使用的任何类型声明。Clang听起来好像应该解决它,但不幸的是它不是,而且谷歌搜索表明它的命名错误,因为它只影响未使用的定义,而不是声明。-femit-all-decls
然后我想也许如果我只将头文件编译成.gch
文件,我可以用LLVMParseBitcodeInContext2
同样的方式把它们拉进来(因为文档说他们使用“相同的”位码格式”,但是这样做的错误error: Invalid bitcode signature
一定是不同的。也许区别小到可以解决吗?
有什么建议或相对简单的解决方法可以为复杂的运行时自动化?如果有人对处理这个一般用例有一个完全替代的建议,我也会感兴趣,记住我不想为我生成的每个目标文件静态链接运行时函数体,只是类型。我想这也是其他编译器也需要的东西,所以如果我接近这个错误我不会感到惊讶。
例如给定这个输入:
运行时.h
struct Foo {
int a;
int b;
};
struct Foo * something_with_foo(struct Foo *foo);
我需要一个具有等效 IR 的位码文件
运行时.ll
; ...etc...
%struct.Foo = type { i32, i32 }
declare %struct.Foo* @something_with_foo(%struct.Foo*)
; ...etc...
我可以手动编写所有内容,但这将是重复的,因为我还需要为其他互操作创建 C 标头,并且最好不必手动保持它们同步。运行时间相当大。我想我也可以反过来做:在 LLVM IR 中编写声明并生成 C 头文件。
几年前有人问过这个问题,但是对于这种大小和类型复杂的运行时,所提出的解决方案相当笨拙且相当不切实际:Clang - Compiling a C header to LLVM IR/bitcode
解决方案
Clang 的预编译头实现似乎没有输出 LLVM IR,而只输出 AST(抽象语法树),因此不需要再次解析头:
AST 文件本身包含 Clang 的抽象语法树和支持数据结构的序列化表示,使用与 LLVM 的位码文件格式相同的压缩位流存储。
底层的二进制格式可能相同,但听起来内容不同,LLVM 的位码格式在这种情况下只是一个容器。这从网站上的帮助页面上不是很清楚,所以我只是推测。LLVM/Clang 专家可以帮助澄清这一点。
不幸的是,似乎没有一种优雅的方式来解决这个问题。为了最大限度地减少实现您想要的工作所需的工作,我建议构建一个最小的 C/C++ 源文件,该文件以某种方式使用您想要编译为 LLVM IR 的所有声明。例如,您只需要声明一个指向结构的指针以确保它不会被优化掉,并且您可能只需为函数提供一个空定义以保留其签名。
一旦你有一个最小的源文件,编译它clang -O0 -c -emit-llvm -o precompiled.ll
以获得一个具有 LLVM IR 格式的所有定义的模块。
您发布的片段中的一个示例:
struct Foo {
int a;
int b;
};
// Fake function definition.
struct Foo * something_with_foo(struct Foo *foo)
{
return NULL;
}
// A global variable.
struct Foo* x;
显示保留定义的输出:https ://godbolt.org/g/2F89BH
推荐阅读
- r - 是否可以将 Shiny 作为主应用程序的子进程运行?
- .net - 升级任何应用程序时是否有任何问题,具有不同版本的 installshield
- java - Servlet 未与 MySQL 数据库连接
- python-3.x - 如何使用 Python 配置远程 iis 服务器
- flutter - 在创建期间将信息从页面传递到存储库
- http - 使用 ACOM632G-512 创建 SMS 网关
- r - 突出显示情节中的值
- python - 如何在此客户小部件中添加命令选项,例如 tkinter 按钮?
- angular - 如何重用我的模型类型属性?
- firebase - 是否有任何 REST api 可以在 Firebase 中创建用户?