Funções de chamada Rust da Go

Ao mesmo tempo, havia um artigo sobre Habr sobre como chamar o código Rust da Go . O artigo não é ruim, mas difícil de entender e realmente repele os iniciantes do desejo de olhar para os dois idiomas. O objetivo deste post não é muito para entrar nas entranhas das chamadas em vários idiomas, mas mostrar como é fácil fazer isso.

imagem

Não iremos longe e daremos um exemplo de um livro sobre o aprendizado da linguagem Rust.

Tudo o que este exemplo faz é iniciar 10 threads, nos quais incrementa a variável 'x' para 5 milhões e exibe uma mensagem sobre o final do fluxo.

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


Você também precisa editar o arquivo de carga adicionando uma linha a ele
tipo de caixa = ["cdylib"]
Como resultado, será criada uma biblioteca com a capacidade de chamar funções por meio da Foreign Function Interface (FFI) .

Vale ressaltar que libembed.dylib é uma biblioteca no Mac OS, no Linux será libembed.so e no Windows será libembed.dll

Obrigado: bingo347


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

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


Em geral, isso é tudo o que você precisa fazer na biblioteca Rust. Um exemplo do livro descreve isso com mais detalhes e não vamos nos deter sobre isso.

Nós compilamos a biblioteca com o comando:
construção de carga - liberação
Agora, nosso objetivo é chamar esse código do aplicativo Go. Criamos um aplicativo simples e, dentro do nosso projeto, adicionamos a pasta lib na qual copiamos o arquivo /target/release/libembed.dylib . Dentro, criamos um arquivo com o nome da função e descrevemos sua assinatura de chamada.

lib / process.h
void process();


Dentro do arquivo Go, adicionamos essas diretivas e nosso main.go ficará assim

package main

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

func main() {
	C.process()
}


Montando o projeto
vá construir -ldflags = "- r / lib" main.go
Preste atenção ao parâmetro ldflags, neste caso, tudo o que fazemos é definir o caminho para o vinculador dinâmico ELF.

Todos. Execute o programa e obtenha a saída.



Também é importante mencionar separadamente que você pode transferir os ensinamentos do programa Go para a biblioteca Rust. Para fazer isso, transformamos a função na biblioteca Rust para que ela use um valor de string.

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


Montamos nosso projeto, copiamos a biblioteca para a pasta lib novamente, modificamos o arquivo process.h dessa maneira
processo nulo (char * name);

Passamos a linha do aplicativo Go (no nosso caso: "Hello from Golang") .

package main

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

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


Todos. Execute o programa e obtenha a saída.


All Articles