我有一个自定义的LLVM后端,并希望为该自定义(nostd)目标交叉编译Rust。我想分两个步骤编译Rust程序:
rustc
生成LLVM IR。opt
和llc
将LLVM IR转换为机器代码。我尝试使用cargo rustc -- --emit=llvm-ir
。我得到.ll
个文件,然后使用llc
得到.o
个文件。
然后,我以相同的方式交叉编译libcore
。当我尝试将所有对象链接在一起时,它告诉我一个未定义的引用。我正在使用libcore
和rustc
的相同提交。 LLVM版本似乎有问题,但我不确定。
答案 0 :(得分:0)
您应该注意几件事。最重要的是,如果从rustup或发行版软件包管理器获得rustc,则rustc默认使用的LLVM版本是/ not /实际的LLVM版本,并且实际上可能与特定的llvm版本不兼容。我们通过使用--llvm-root
标志进行配置来从源构建锈来解决我项目中的此问题。然后,您可以使用rustup toolchain link
将内置的rustc链接到自定义的rustup工具链中。
第二,如果至少使用rustc 1.34并将-C linker-plugin-lto标志传递给rustc,则可以使rustc发出包含llvm位代码而不是机器代码的.rlib文件。我还编写了以下脚本,可以对包含目标代码的rlib文件进行解压缩,然后将其打包为包含llvm位代码的rlib文件,如果上述方法对您不起作用。
#!/bin/bash
dir="$(mktemp -d)"
trap "rm -rf $dir" INT TERM EXIT
archive=$(realpath -m $1)
cd "$dir"
ar x "$archive"
rm ./*.rcgu.o
for file in *.bc.z; do
len=`od -An -t u4 -j 15 -N4 $file`
blen=`od -An -t u8 -j $((len+19)) -N8 $file`
tail -c+$((len+28)) $file | head -c $blen > $file.bc.gz
printf "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00" |cat - $file.bc.gz |gzip -dc > ${file%.bc.z}.o
done
rm *.bc.z
rm *.gz
rm "$archive"
llvm-ar rs "${archive}" ./*
一旦有了rlib文件,就可以对它们使用任何llvm工具链工具,就像处理包含llvm位代码的.a文件一样。
在执行最终链接方面,需要牢记一些注意事项。首先,rustc自动生成符号__rust_alloc
,__rust_alloc_zeroed
,__rust_dealloc
和__rust_realloc
,并将它们指向__rg_alloc
(以及相似的__rg_
符号分别是),这是默认情况下使用jemalloc的GlobalAlloc实现,或__rdl_alloc
(以及类似的__rdl_
符号),它是由libc malloc支持的系统分配器。如果您不使用rustc进行最终链接,则必须自己实现这些符号。
第二,libstd和libcore依赖于您可能还必须链接的其他一些库。根据您使用的标准库的哪个部分,您可能会发现需要不同的库集,因此如果没有特定的错误消息,我将无法为您提供帮助,但是我可以告诉您应用程序的库列表最终要求的顺序是:std, core, alloc, unwind, compiler_builtins, panic_abort, backtrace_sys, rustc_demangle
。如果您使用的是panic = unwind,则显然必须使用它。如果发现仍然缺少符号,我建议使用nm查找包含丢失符号的库,并通过反复试验找出它在链接器顺序中的位置。
希望这会有所帮助,因为我花了很多精力来设计解决此确切问题的解决方案(尽管不是出于交叉编译的目的)。