rust - 在 cdylib Rust crate 中使用 ld 版本脚本
问题描述
我试图在构建cdylib
Rust 板条箱时使用版本脚本,但是由于 Rust 编译器创建的匿名版本脚本,我遇到了问题。我关注了这个关于如何添加版本脚本的论坛帖子,但他们从未提到过这个问题。
执行
我cargo-make
用来构建我的项目。在我的Makefile.toml
我有这个任务:
[tasks.build]
toolchain = "nightly" # Running with nightly-x86_64-unknown-linux-gnu
command = "cargo"
args = ["rustc", "--release", "-p", "my_crate", "--", "-C", "link-args=-Wl,--version-script=versions.map"]
运行cargo make build
时,该任务执行此构建命令。
rustup run nightly cargo rustc --release -p my_crate -- -C link-args=-Wl,--version-script=versions.map
错误
但是,它不断产生此错误。据我所知,我的版本脚本(如下所示)与 Rust 生成的匿名版本脚本冲突(/tmp/rustcyXUHTy/list
在错误中)。不幸的是,Rust 生成的版本脚本在创建后立即被删除,所以我实际上并不知道它是什么样子。我试图按照这个答案查看其他版本的脚本,但它被删除得太快了,我无法看到输出。
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-Wl,--version-script=/tmp/rustcyXUHTy/list" ... "-Wl,--version-script=versions.map"
= note: /usr/bin/ld: anonymous version tag cannot be combined with other version tags
collect2: error: ld returned 1 exit status
锈
// I'm not completely sure which tags should be used and so far they have had no effect on the error
// #[no_mangle]
// #[export_name = "foo"]
pub unsafe extern "system" fn foo() {}
// The crate also contains other functions which are not covered by my version script
// I tried removing all of the other #[no_mangle] functions, but it had no effect
#[no_mangle]
pub unsafe extern "system" fn bar() {}
版本脚本
我对编写版本脚本不是很有经验,所以这是我想出的简单测试脚本。最终产品将使用来自现有 C 项目的类似版本脚本。
Project_1.0 {
global:
foo;
};
解决方案
itamarst 在Rust 论坛上提供的解决方案。
解释
如题所示,ld
不支持多版本脚本。但是,lld
这样做我们可以改用它。(可以sudo apt install lld
在 ubuntu 上安装)。要使用lld
代替ld
,请传递-Clink-arg=-fuse-ld=lld
给rustc
。
然而,这还不够。Rust 生成的版本脚本将优先,版本节点将不会按照我们的版本脚本中指定的方式应用。为了解决这个问题,可以给函数一个临时名称,并且可以通过链接器 args ( --defsym
) 将一个新符号链接到它。在版本脚本中可以自由使用新符号,并且可以将原来的函数名标记为本地,以防止重复符号被上传。
锈代码
// Name function foo_impl and rename it on the command line
#[no_mangle]
pub unsafe extern "system" fn foo_impl() {}
版本脚本
Project_1.0 {
global:
foo;
local:
foo_inner;
};
建造
所有的cdylib
rust/linker 参数都可以在build.rs
.
// Tell Rust to use lld instead of ld
println!("cargo:rustc-cdylib-link-arg=-fuse-ld=lld");
// Set version script path
println!("cargo:rustc-cdylib-link-arg=-Wl,--version-script=mapfile");
// Rename symbols to get around the anonymous version script
for symbol in &["foo"] {
println!("cargo:rustc-cdylib-link-arg=-Wl,--defsym={}={}_impl", symbol, symbol);
}
或者,所有这些参数都可以在命令行上传递。
cargo rustc -- -Clink-arg=-fuse-ld=lld -Clink-args=-Wl,--defsym=foo=foo_impl,--version-script=mapfile
推荐阅读
- android-studio - Searchview 应该只过滤来自 listview androidstudio 的前 5 个字符
- azure-devops - Azure Devops Pipelines 并行作业的每月或每分钟计费
- unity3d - 如何摆脱未找到统一目录的错误
- php - 用于重置密码的 ApiPlatform DataProvider
- android - 带有数字 InputType 的 EdiText 不接受键盘输入
- java - Removing duplicate numbers from Java list Using Java Lambda functions
- react-native - 了解在 expo-contacts react-native 中传递给 Contacts.getContactsAsync 的不同参数
- php - PHP 7.2:替换 mcrypt 方法“mcrypt_get_iv_size”
- prometheus - 如何在 Prometheus 中获取 PromQL 的报告次数
- json - 获取 Elasticsearch 响应