在Rust程序中嵌入Rust任务?

时间:2022-09-06 21:24:21

Calling a C library function from Rust program (an executable compiled by rustc) is working well, and and a goal of the Rust team.

从Rust程序(由rustc编译的可执行文件)调用C库函数运行良好,并且是Rust团队的目标。

Calling a Rust crate function from C program (an executable compiled by clang) is working for simple stuffs, but if I spawn a task, it crashes.

从C程序(由clang编译的可执行文件)调用Rust crate函数正在处理简单的事情,但是如果我生成一个任务,它就会崩溃。

How can I make Rust tasks to work?

如何使Rust任务起作用?


Here's my sources and error messages. You also can download from https://github.com/Eonil/TeachingMyselfRust

这是我的来源和错误消息。您也可以从https://github.com/Eonil/TeachingMyselfRust下载

a.rs

#[no_mangle]
pub fn test1()
{
    let a1  =   proc()
    {
    };
    spawn(a1);
}

b.c

#include <stdio.h>

extern void test1();


int main(int argc, char** argv)
{
    test1();
    return 0;
}

build script

rm -rf ./Build
mkdir ./Build

rustc a.rs --crate-type=staticlib -o ./Build/rust-stuffs.a
clang b.c ./Build/rust-stuffs.a -o Build/out

cd Build
./out

execution result

warning: unlinked native library: System


There are not many persons who know what wonders are opened to them in the
stories and visions of their youth; for when as children we listen and dream,
we think but half-formed thoughts, and when as men we try to remember, we are
dulled and prosaic with the poison of life. But some of us awake in the night
with strange phantasms of enchanted hills and gardens, of fountains that sing
in the sun, of golden cliffs overhanging murmuring seas, of plains that stretch
down to sleeping cities of bronze and stone, and of shadowy companies of heroes
that ride caparisoned white horses along the edges of thick forests; and then
we know that we have looked back through the ivory gates into that world of
wonder which was ours before we were wise and unhappy.

fatal runtime error:  assertion failed: !ptr.is_null()
stack backtrace:
   1:        0x108bc7944 - rt::backtrace::imp::write::hdaa6a604147ca757g8b::v0.10
   2:        0x108b5f4aa - rt::util::abort::h3d7b16d436532c64Bmc::v0.10
   3:        0x108bc605a - rt::local_ptr::compiled::take::hb1c4b940f0aa52aea9a::v0.10
   4:        0x108b5e6ad - task::TaskBuilder::spawn::h2dcf43b5eaa6805aQhC::v0.10
   5:        0x108b5eb6d - task::spawn::hff1c6bd6cfded263NjC::v0.10
   6:        0x108b29670 - test1
   7:        0x108b295fd - main
./run.bash: line 8: 38948 Illegal instruction: 4  ./out

1 个解决方案

#1


7  

It's not that simple, I'm afraid. Rust tasks are not plain threads, like pthreads or others in C. They do need some support from Rust runtime, so in order to create tasks you need to start the runtime. One of the ways is to call a Rust function from your C program which in turn will call another C function:

我担心的并不是那么简单。 Rust任务不是普通线程,比如pthreads或C中的其他线程。它们确实需要Rust运行时的一些支持,因此为了创建任务,您需要启动运行时。其中一种方法是从C程序调用Rust函数,然后调用另一个C函数:

#include <stdio.h>

extern int run(int argc, char** argv, void (*kont)(void));
extern void do_work();

void actual_main(void);

int main(int argc, char** argv) {
    return run(argc, argv, actual_main);
}

void actual_main(void) {
    printf("Hello from C program\n");
    do_work();
}

Rust:

extern crate native;

#[no_mangle]
pub extern fn run(argc: int, argv: *const *const u8, kont: extern fn()) {
    native::start(argc, argv, proc() kont());
}

#[no_mangle]
pub extern fn do_work() {
    spawn(proc() {
        println!("Hello from task");
    });
}

Compilation (on my Linux box; if you're using another OS, you probably have to tweak it):

编译(在我的Linux机器上;如果你正在使用另一个操作系统,你可能需要调整它):

% rustc --crate-type staticlib --crate-name ex lib.rs
% gcc -c example.c
% gcc -L. -o example example.o -lex -lm -lpthread -lgcc_s -ldl

Running:

% ./example
Hello from C program
Hello from task

This does require you to change the main function. In any case, all code which access runtime-specific functions from Rust (tasks, Rust I/O, boxes, etc) have to be "under" native::start() call in the call stack. This is the simplest way I know of. Or, if that is acceptable, you can write your main() function in Rust, so your executable binary will be rustc output, even though its work will actually happen in C code.

这确实需要您更改主要功能。在任何情况下,从Rust(任务,Rust I / O,盒子等)访问特定于运行时的函数的所有代码都必须在调用堆栈中的“native”下调用native :: start()。这是我所知道的最简单的方法。或者,如果这是可以接受的,你可以在Rust中编写main()函数,因此你的可执行二进制文件将是rustc输出,即使它的工作实际上会在C代码中发生。

#1


7  

It's not that simple, I'm afraid. Rust tasks are not plain threads, like pthreads or others in C. They do need some support from Rust runtime, so in order to create tasks you need to start the runtime. One of the ways is to call a Rust function from your C program which in turn will call another C function:

我担心的并不是那么简单。 Rust任务不是普通线程,比如pthreads或C中的其他线程。它们确实需要Rust运行时的一些支持,因此为了创建任务,您需要启动运行时。其中一种方法是从C程序调用Rust函数,然后调用另一个C函数:

#include <stdio.h>

extern int run(int argc, char** argv, void (*kont)(void));
extern void do_work();

void actual_main(void);

int main(int argc, char** argv) {
    return run(argc, argv, actual_main);
}

void actual_main(void) {
    printf("Hello from C program\n");
    do_work();
}

Rust:

extern crate native;

#[no_mangle]
pub extern fn run(argc: int, argv: *const *const u8, kont: extern fn()) {
    native::start(argc, argv, proc() kont());
}

#[no_mangle]
pub extern fn do_work() {
    spawn(proc() {
        println!("Hello from task");
    });
}

Compilation (on my Linux box; if you're using another OS, you probably have to tweak it):

编译(在我的Linux机器上;如果你正在使用另一个操作系统,你可能需要调整它):

% rustc --crate-type staticlib --crate-name ex lib.rs
% gcc -c example.c
% gcc -L. -o example example.o -lex -lm -lpthread -lgcc_s -ldl

Running:

% ./example
Hello from C program
Hello from task

This does require you to change the main function. In any case, all code which access runtime-specific functions from Rust (tasks, Rust I/O, boxes, etc) have to be "under" native::start() call in the call stack. This is the simplest way I know of. Or, if that is acceptable, you can write your main() function in Rust, so your executable binary will be rustc output, even though its work will actually happen in C code.

这确实需要您更改主要功能。在任何情况下,从Rust(任务,Rust I / O,盒子等)访问特定于运行时的函数的所有代码都必须在调用堆栈中的“native”下调用native :: start()。这是我所知道的最简单的方法。或者,如果这是可以接受的,你可以在Rust中编写main()函数,因此你的可执行二进制文件将是rustc输出,即使它的工作实际上会在C代码中发生。