goa*_*iek 7 build linker-errors rust rust-cargo
我正在编写一个Rust CLI 工具,它使用我静态链接的 C 库。我按照bindgen教程开始使用,目前可以创建一个可以按预期与cargo build
.
但是,当我尝试使用 构建项目时cargo build --release
,我遇到了构建错误,表明我正在使用的外部 C 函数未定义,例如:
stumpless-logger/target/release/deps/libstumpless-292541b9e494f811.rlib(stumpless-292541b9e494f811.stumpless.7e987498-cgu.0.rcgu.o): In function `stumpless::FileTarget::new':
stumpless.7e987498-cgu.0:(.text._ZN9stumpless10FileTarget3new17hef1370275727c33dE+0x82): undefined reference to `stumpless_open_file_target'
Run Code Online (Sandbox Code Playgroud)
nm
显示调试和发布库构建在各自目标目录中的预期导出:
# first with the debug
stumpless-logger$ nm --defined-only target/debug/build/stumpless-sys-ca96d217a4e3d9db/out/lib/libstumpless.a | grep file
0000000000000000 T raise_file_open_failure
0000000000000000 T raise_file_write_failure
file.c.o:
0000000000000000 T destroy_file_target
0000000000000000 T file_open_default_target
0000000000000000 T new_file_target
0000000000000000 T sendto_file_target
0000000000000000 T stumpless_close_file_target
0000000000000000 T stumpless_open_file_target
# and now with the release
stumpless-logger$ nm --defined-only target/release/build/stumpless-sys-6f81199b96080c30/out/lib/libstumpless.a | grep file
00000000 T raise_file_open_failure
00000000 T raise_file_write_failure
file.c.o:
00000000 T destroy_file_target
00000000 T file_open_default_target
00000000 T new_file_target
00000000 T sendto_file_target
00000000 T stumpless_close_file_target
00000000 T stumpless_open_file_target
Run Code Online (Sandbox Code Playgroud)
我还可以从 C 库构建并运行一个使用示例,该示例使用据称未定义的函数之一,该函数可以按预期与调试和发布库一起工作:
# first with the debug version
stumpless/docs/examples/file$ gcc file_example.c -L "stumpless-logger/target/debug/build/stumpless-sys-ca96d217a4e3d9db/out/lib" -l:libstumpless.a -I "stumpless-logger/target/debug/build/stumpless-sys-ca96d217a4e3d9db/out/include" -o example-with-debug
stumpless/docs/examples/file$ ./example-with-debug && cat example.log
<14>1 2022-03-06T16:18:11.649456Z Angus example-app-name - example-msgid [basic-element basic-param-name="basic-param-value"] This is an example message.
# and then with the release
rm example.log
stumpless/docs/examples/file$ gcc file_example.c -L "stumpless-logger/target/release/build/stumpless-sys-6f81199b96080c30/out/lib" -l:libstumpless.a -I "stumpless-logger/target/release/build/stumpless-sys-6f81199b96080c30/out/include" -o example-with-release
stumpless/docs/examples/file$ ./example-with-release && cat example.log
<14>1 2022-03-06T16:21:16.255854Z Angus example-app-name - example-msgid [basic-element basic-param-name="basic-param-value"] This is an example message.
Run Code Online (Sandbox Code Playgroud)
起初,我认为可以通过将 FFI 绑定拆分到单独的 -sys 箱中来解决这个问题,这似乎是标准做法。然而,这样做后问题仍然存在(但至少现在已经完成了,我想还有一线希望)。
我可以通过修改构建配置文件以将优化级别设置为 0 来解决问题release
。也就是说,将其添加到我的Cargo.toml
清单中可以解决问题:
[profile.release]
opt-level = 0
Run Code Online (Sandbox Code Playgroud)
但这会把它带回来:
[profile.release]
opt-level = 1
Run Code Online (Sandbox Code Playgroud)
我尝试明确禁用配置文件文档中列出的其他优化,特别是 LTO,但无济于事。我想也许我的函数在 LTO 过程中被错误地删除了,但它默认是禁用的(至少根据文档),所以这不太可能是罪魁祸首。事实上,即使lto = false
在清单中,它仍然失败。可以预见的是,它也失败了lto = true
(虽然可能性不大,但我尝试过)。
我真的希望我的发布版本能够得到优化,因为我怀疑最终二进制文件的性能会更好。但不幸的是,在我明白为什么会发生这个问题之前,我不知道如何实现这一目标。任何能够解释为什么会发生这种情况和/或如何优化我的发布版本的人都将受到高度赞赏。
我是 Rust 开发的新手,所以我很可能错过了一些明显的东西。我确实在工具链的其他部分遇到了困难。然而,经过一天左右的研究和摆弄后,我无法在这个问题上找到任何答案,所以我向这里寻求帮助。至少,未来遇到同样问题的灵魂会更容易解决他们的问题。
旁注,如果您将事物追溯到 C 构建本身,请注意,我在调整某些内容时使用非默认分支,release-tune
sttumless 分支是此处相关的。
编辑 1我忘记包含我的 Rust 环境信息:我正在使用rustup
我的活动工具链来管理我的安装:
stable-x86_64-unknown-linux-gnu (default)
rustc 1.59.0 (9d1b2106e 2022-02-23)
Run Code Online (Sandbox Code Playgroud)
编辑2嗯,我设法解决了这个问题,但我仍然很困惑为什么这样可以解决它。我真的很感激您能提供的任何解释。
在我的build.rs
文件中,处理静态库链接的代码包含以下行:
stumpless-logger/target/release/deps/libstumpless-292541b9e494f811.rlib(stumpless-292541b9e494f811.stumpless.7e987498-cgu.0.rcgu.o): In function `stumpless::FileTarget::new':
stumpless.7e987498-cgu.0:(.text._ZN9stumpless10FileTarget3new17hef1370275727c33dE+0x82): undefined reference to `stumpless_open_file_target'
Run Code Online (Sandbox Code Playgroud)
在将我的代码与教程进行比较时,我记得我=static
在查看其他示例时添加了该部分,并决定最好更明确一些。我把它拿出来,你瞧,发布版本现在可以正常工作了。也就是说,该行变为:
# first with the debug
stumpless-logger$ nm --defined-only target/debug/build/stumpless-sys-ca96d217a4e3d9db/out/lib/libstumpless.a | grep file
0000000000000000 T raise_file_open_failure
0000000000000000 T raise_file_write_failure
file.c.o:
0000000000000000 T destroy_file_target
0000000000000000 T file_open_default_target
0000000000000000 T new_file_target
0000000000000000 T sendto_file_target
0000000000000000 T stumpless_close_file_target
0000000000000000 T stumpless_open_file_target
# and now with the release
stumpless-logger$ nm --defined-only target/release/build/stumpless-sys-6f81199b96080c30/out/lib/libstumpless.a | grep file
00000000 T raise_file_open_failure
00000000 T raise_file_write_failure
file.c.o:
00000000 T destroy_file_target
00000000 T file_open_default_target
00000000 T new_file_target
00000000 T sendto_file_target
00000000 T stumpless_close_file_target
00000000 T stumpless_open_file_target
Run Code Online (Sandbox Code Playgroud)
它仍然是静态的,至少据我所知:我在 CMake 构建步骤中禁用了共享库构建,因此它找不到动态库。有谁知道为什么指定库的类型会对发布版本产生如此灾难性的影响?我确实检查过以确保我没有意外安装动态库,并且它不存在(也就是说,ldconfig -p | grep stumpless
不产生任何输出。
lz4
我在尝试通过板条箱链接时也遇到了这个问题lz4
。
cargo test
编译良好并且测试是绿色的,因此代码可以运行。但是,cargo test --release
失败了undefined reference to LZ4_decompress_safe_partial
我个人通过简单地使用不同的链接器来“修复”它。我将以下内容放入我的~/.cargo/config
文件中,然后它就没有问题了。
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1329 次 |
最近记录: |