我正在尝试在C中构建一个最小程序来调用Rust函数,最好用#![no_std]Windows 编译,使用GCC 6.1.0和rustc 1.11.0-nightly (bb4a79b08 2016-06-15) x86_64-pc-windows-gnu.这是我先尝试过的:
main.c中
#include <stdio.h>
int sum(int, int);
int main()
{
printf("Sum is %d.\n", sum(2, 3));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
sum.rs
#![no_std]
#![feature(libc)]
extern crate libc;
#[no_mangle]
pub extern "C" fn sum(x: libc::c_int, y: libc::c_int) -> libc::c_int
{
x + y
}
Run Code Online (Sandbox Code Playgroud)
然后我试着跑:
rustc --crate-type=staticlib --emit=obj sum.rs
Run Code Online (Sandbox Code Playgroud)
但得到了:
error: language item required, but not found: `panic_fmt`
error: language item required, but not found: `eh_personality`
error: language item required, but not found: `eh_unwind_resume`
error: aborting due to 3 previous errors
Run Code Online (Sandbox Code Playgroud)
好的,所以其中一些错误与恐慌解除有关.我发现了一个Rust编译器设置来删除unwinding支持,-C panic=abort.使用它,错误eh_personality和eh_unwind_resume消失,但Rust仍然需要该panic_fmt功能.所以我在Rust文档中找到了它的签名,然后我将其添加到文件中:
sum.rs
#![no_std]
#![feature(lang_items, libc)]
extern crate libc;
#[lang = "panic_fmt"]
pub fn panic_fmt(_fmt: core::fmt::Arguments, _file_line: &(&'static str, u32)) -> !
{ loop { } }
#[no_mangle]
pub extern "C" fn sum(x: libc::c_int, y: libc::c_int) -> libc::c_int
{
x + y
}
Run Code Online (Sandbox Code Playgroud)
然后,我尝试再次构建整个程序:
rustc --crate-type=staticlib --emit=obj -C panic=abort sum.rs
gcc -c main.c
gcc sum.o main.o -o program.exe
Run Code Online (Sandbox Code Playgroud)
但得到了:
sum.o:(.text+0x3e): undefined reference to `core::panicking::panic::h907815f47e914305'
collect2.exe: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
恐慌功能参考可能来自添加时的溢出检查sum().这一切都很好,也很可取.根据这个页面,我需要定义自己的恐慌函数来使用libcore.但是我找不到关于如何这样做的说明:我应该panic_impl在文档中调用我应该提供定义的函数,但是链接器正在抱怨panic::h907815f47e914305,无论应该是什么.
使用objdump,我能够找到丢失的函数的名称,并将其入侵到C:
main.c中
#include <stdio.h>
#include <stdlib.h>
int sum(int, int);
void _ZN4core9panicking5panic17h907815f47e914305E()
{
printf("Panic!\n");
abort();
}
int main()
{
printf("Sum is %d.\n", sum(2, 3));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在,整个程序成功编译和链接,甚至可以正常工作.
如果我然后尝试在Rust中使用数组,则会生成另一种恐慌函数(用于边界检查),因此我也需要为此提供一个定义.每当我在Rust中尝试更复杂的东西时,就会出现新的错误.顺便说一下,panic_fmt即使恐慌确实发生,也似乎永远不会被召唤.
无论如何,这一切看起来都非常不可靠,并且与我在此事上可以通过Google找到的所有信息相矛盾.就是这样,但我试着按照说明无济于事.
这似乎是一件简单而基本的事情,但我无法让它以正确的方式运作.也许这是一个Rust夜间的虫子?但我需要libc和lang_items.如何在不展开或恐慌支持的情况下生成Rust对象文件/静态库?它可能只是在它想要恐慌时执行非法处理器指令,或者调用我可以在C中安全定义的恐慌函数.
你不应该使用--emit=obj; 只是rustc --crate-type=staticlib -C panic=abort sum.rs应该做正确的事情.(这修复了_ZN4core9panicking5panic17h907815f47e914305E链接错误.)
要修复另一个链接错误,您需要正确编写panic_fmt(注意使用extern):
#[lang="panic_fmt"]
extern fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32) -> ! {
loop {}
}
Run Code Online (Sandbox Code Playgroud)
随着这些变化,一切似乎都按照预期的方式发挥作用.
你需要panic_fmt所以你可以决定在发生恐慌时要做什么:如果你使用#![no_std],rustc假设没有标准的库/ libc /内核,所以它不能只调用abort()或期望非法指令做任何有用的事情.它应该以某种方式暴露在稳定的Rust中,但我不知道是否有人正在努力稳定它.
你不需要#![feature(libc)]用来获取libc; 你应该使用crates.io上发布的版本(或者你可以手动声明你需要的功能).
| 归档时间: |
|
| 查看次数: |
2251 次 |
| 最近记录: |