Rust-Funktionen von Go aus aufrufen

Zu einer Zeit gab es einen Artikel über Habr darüber, wie man Rust-Code von Go aus aufruft . Der Artikel ist nicht schlecht, aber schwer zu verstehen und wehrt Anfänger tatsächlich von dem Wunsch ab, auf beide Sprachen zu schauen. Der Zweck dieses Beitrags besteht nicht darin, sprachübergreifende Anrufe zu vertiefen, sondern zu zeigen, wie einfach dies möglich ist.

Bild

Wir werden nicht weit gehen und ein Beispiel aus einem Buch über das Erlernen der Rust-Sprache nehmen.

In diesem Beispiel werden lediglich 10 Threads gestartet, in denen die Variable 'x' auf 5 Millionen erhöht wird und eine Meldung zum Ende des Streams angezeigt wird.

use std::thread;

#[no_mangle]
pub extern "C" fn process() {
    let handles:Vec<_> = (0..10).map(|_|{
        thread::spawn(||{
            let mut x = 0;
            for _ in 0..5_000_000 {
                x += 1
            }
            x
        })
    }).collect();

    for h in handles {
        println!("Thread finished with count={}",
                 h.join().map_err(|_| "Could not join thread!").unwrap());
    }
    println!("Done!");
}


Sie müssen die Frachtdatei auch bearbeiten, indem Sie eine Zeile hinzufügen
Kistentyp = ["cdylib"]
Als Ergebnis wird eine Bibliothek mit der Möglichkeit erstellt, Funktionen über die Foreign Function Interface (FFI) aufzurufen .

Es ist erwähnenswert, dass libembed.dylib eine Bibliothek unter Mac OS ist, unter Linux libembed.so und unter Windows libembed.dll.

Vielen Dank: bingo347


Cargo.toml
[package]
name = "embed"
version = "0.1.0"

[lib]
crate-type = ["cdylib"]


Im Allgemeinen ist dies alles, was Sie in der Rust-Bibliothek tun müssen. Ein Beispiel aus dem Buch beschreibt dies ausführlicher und wir werden nicht weiter darauf eingehen.

Wir kompilieren die Bibliothek mit dem Befehl:
Frachtbau - Release
Jetzt ist es unser Ziel, diesen Code aus der Go-Anwendung aufzurufen. Wir erstellen eine einfache Anwendung und fügen in unserem Projekt den lib-Ordner hinzu, in den wir die Datei /target/release/libembed.dylib kopieren . Im Inneren erstellen wir eine Datei mit dem Namen der Funktion und beschreiben deren Aufrufsignatur.

lib / process.h
void process();


In der Go-Datei fügen wir solche Anweisungen hinzu und unsere main.go wird so aussehen

package main

/*
#cgo LDFLAGS: -L./lib -lembed
#include "./lib/process.h"
*/
import "C"

func main() {
	C.process()
}


Das Projekt zusammenstellen
go build -ldflags = "- r / lib" main.go
Achten Sie auf den Parameter ldflags. In diesem Fall legen wir lediglich den Pfad zum dynamischen ELF-Linker fest.

Alle. Führen Sie das Programm aus und erhalten Sie die Ausgabe.



Erwähnenswert ist auch, dass Sie die Lehren aus dem Go-Programm in die Rust-Bibliothek übertragen können. Dazu transformieren wir die Funktion in der Rust-Bibliothek so, dass sie einen Zeichenfolgenwert annimmt.

extern crate libc;
use std::thread;
use std::ffi::CStr;

#[no_mangle]
pub extern "C" fn process(name: *const libc::c_char) {

    let buf_name = unsafe { CStr::from_ptr(name).to_bytes() };
    let str_name = String::from_utf8(buf_name.to_vec()).unwrap();

    let handles:Vec<_> = (0..10).map(|_|{
        thread::spawn(||{
            let mut x = 0;
            for _ in 0..5_000_000 {
                x += 1
            }
            x
        })
    }).collect();

    for h in handles {
        println!("{}:Thread finished with count={}\n",
                 str_name,
                 h.join().map_err(|_| "Could not join thread!\n").unwrap());
    }
    println!("Done!");
}


Wir stellen unser Projekt zusammen, kopieren die Bibliothek erneut in den Ordner lib und ändern die Datei process.h auf diese Weise
void process (char * name);

Wir übergeben die Zeile aus der Go-Anwendung (in unserem Fall: „Hallo aus Golang“) .

package main

/*
#cgo LDFLAGS: -L./lib -lembed
#include "./lib/process.h"
*/
import "C"

func main() {
	C.process(C.CString("Hello from Golang !!"))
}


Alle. Führen Sie das Programm aus und erhalten Sie die Ausgabe.


All Articles