Встраивание задач ржавчины в программу C?

Вызов функции библиотеки C из программы Rust (исполняемый файл, скомпилированный rustc) работает хорошо, а также цель команды Rust.

Вызов функции Rust crate из программы C (исполняемый файл, скомпилированный clang) работает для простых вещей, но если я создаю задачу, она сработает.

Как я могу заставить задачи Rust работать?


Здесь мои источники и сообщения об ошибках. Вы также можете скачать с 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

результат выполнения

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

Это не так просто, боюсь. Задачи ржавчины - это не простые потоки, такие как pthreads или другие на C. Они нуждаются в некоторой поддержке из Rust runtime, поэтому для создания задач вам нужно запустить среду выполнения. Один из способов - вызвать функцию Rust из вашей программы на C, которая, в свою очередь, вызовет другую функцию 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();
}

Ржавчина:

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");
    });
}

Компиляция (на моем 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

Продолжительность:

% ./example
Hello from C program
Hello from task

Это требует от вас изменения основной функции. В любом случае весь код, который получает доступ к функциям, зависящим от времени выполнения от Rust (задачи, Rust I/O, boxes и т.д.), Должен быть "под" native::start() вызовом в стеке вызовов. Это самый простой способ, о котором я знаю. Или, если это приемлемо, вы можете написать свою функцию main() в Rust, поэтому ваш исполняемый двоичный файл будет выводиться rustc, хотя его работа действительно произойдет в коде C.