【发布时间】:2012-02-27 06:22:27
【问题描述】:
我希望 clang 将我的 C/C++ 代码编译为 LLVM 位码,而不是二进制可执行文件。我怎样才能做到这一点?
如果我有 LLVM 位码,如何进一步将其编译为二进制可执行文件?
我想在编译为二进制可执行文件之前将一些我自己的代码添加到 LLVM 位码。
【问题讨论】:
我希望 clang 将我的 C/C++ 代码编译为 LLVM 位码,而不是二进制可执行文件。我怎样才能做到这一点?
如果我有 LLVM 位码,如何进一步将其编译为二进制可执行文件?
我想在编译为二进制可执行文件之前将一些我自己的代码添加到 LLVM 位码。
【问题讨论】:
给定一些 C/C++ 文件foo.c:
> clang -S -emit-llvm foo.c
生成foo.ll,这是一个 LLVM IR 文件。
-emit-llvm 选项也可以直接传递给编译器前端,而不是通过-cc1 的方式传递给驱动程序:
> clang -cc1 foo.c -emit-llvm
使用 IR 生成 foo.ll。 -cc1 添加了一些很酷的选项,例如 -ast-print。查看-cc1 --help了解更多详情。
要进一步编译 LLVM IR 以进行汇编,请使用 llc 工具:
> llc foo.ll
使用程序集生成foo.s(默认为您运行它的机器架构)。 llc 是 LLVM 工具之一 - here is its documentation。
【讨论】:
使用
clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc
【讨论】:
.o 应该引用二进制对象文件,.s 应该引用汇编文件,而其他东西(按照约定 .ll)应该引用 LLVM IR 文件。否则很容易混淆。 Clang/LLVM 现在没有自己的二进制对象链接器(尽管正在开发中)。 LLVM 链接器llvm-ld 只是将几个 IR 文件合并为一个
.bc,clang 前端实际上是正确的;另外,请记住llvm-ld 可以充当系统工具链的前端,即我之前使用llvm-ld -native 的答案应该可以按预期工作......
foo.bc 是一个 LLVM 位码文件
clang -emit-llvm -o test.bc -c test.c && file test.bc: test.bc: LLVM IR bitcode.
如果您有多个源文件,您可能实际上想要使用链接时间优化来为整个程序输出一个位码文件。给出的其他答案将导致您最终得到每个源文件的位码文件。
相反,您希望使用链接时间优化进行编译
clang -flto -c program1.c -o program1.o
clang -flto -c program2.c -o program2.o
对于最后的链接步骤,添加参数 -Wl,-plugin-opt=also-emit-llvm
clang -flto -Wl,-plugin-opt=also-emit-llvm program1.o program2.o -o program
这会给你both一个编译的程序和对应的位码(program.bc)。然后你可以用任何你喜欢的方式修改program.bc,并随时重新编译修改后的程序
clang program.bc -o program
但请注意,您需要在此步骤再次包含任何必要的链接器标志(用于外部库等)。
请注意,您需要使用黄金链接器才能使其正常工作。如果您想强制 clang 使用特定的链接器,请在计算机上某个名为“fakebin”的特殊目录中创建一个指向该链接器的符号链接,该链接器名为“ld”,并添加选项
-B/home/jeremy/fakebin
到上述任何链接步骤。
【讨论】:
如果您有多个文件并且不想键入每个文件,我建议您按照以下简单步骤操作(我使用的是clang-3.8,但您可以使用任何其他版本):
生成所有.ll 文件
clang-3.8 -S -emit-llvm *.c
将它们链接成一个
llvm-link-3.8 -S -v -o single.ll *.ll
(可选)优化你的代码(也许是一些别名分析)
opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
生成程序集(生成optimised.s 文件)
llc-3.8 optimised.ll
创建可执行文件(命名为a.out)
clang-3.8 optimised.s
【讨论】:
-S 选项(在步骤 2 中),我指定我想在 LLVM IR 中生成输出。基本上,将所有 *.ll 文件放入一个文件中。我这样做是为了检查优化是否真的改变了代码,即 single.ll 和 optimised.ll 现在看起来应该不同(代码方面),您还可以显示报告以查看是否有任何差异。
-basicaaa 是错误标志,必须使用-basicaa。
你读过clang documentation 吗?您可能正在寻找-emit-llvm。
【讨论】: