Funciones de llamada de 贸xido desde Go

Hubo un tiempo en que hab铆a un art铆culo sobre Habr sobre c贸mo llamar al c贸digo Rust desde Go . El art铆culo no es malo, pero es bastante dif铆cil de entender y de hecho repele a los principiantes del deseo de mirar hacia ambos idiomas. El prop贸sito de esta publicaci贸n no es tanto entrar en las tripas de las llamadas en varios idiomas, sino mostrar cu谩n f谩cil se puede hacer.

imagen

No llegaremos lejos y tomaremos un ejemplo de un libro sobre el aprendizaje del idioma Rust.

Todo lo que hace este ejemplo es iniciar 10 subprocesos, dentro de los cuales incrementa la variable 'x' a 5 millones y muestra un mensaje sobre el final de la secuencia.

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


Tambi茅n debe editar el archivo de carga agregando una l铆nea
crate-type = ["cdylib"]
Como resultado, se crear谩 una biblioteca con la capacidad de invocar funciones a trav茅s de la Interfaz de funciones externas (FFI) .

Vale la pena se帽alar que libembed.dylib es una biblioteca en Mac OS, en Linux ser谩 libembed.so y en Windows ser谩 libembed.dll

Gracias: bingo347


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

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


En general, esto es todo lo que tiene que hacer en la biblioteca Rust. Un ejemplo del libro describe esto con m谩s detalle y no nos detendremos en esto.

Compilamos la biblioteca con el comando:
construcci贸n de carga - liberaci贸n
Ahora nuestro objetivo es llamar a este c贸digo desde la aplicaci贸n Go. Creamos una aplicaci贸n simple y, dentro de nuestro proyecto, agregamos la carpeta lib en la que copiamos el archivo /target/release/libembed.dylib . En el interior, creamos un archivo con el nombre de la funci贸n y describimos su firma de llamada.

lib / process.h
void process();


Dentro del archivo Go agregamos tales directivas y nuestro main.go se ver谩 as铆

package main

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

func main() {
	C.process()
}


Poniendo el proyecto juntos
ir a construir -ldflags = "- r / lib" main.go
Preste atenci贸n al par谩metro ldflags, en este caso todo lo que hacemos es establecer la ruta al enlazador din谩mico ELF.

Todas. Ejecute el programa y obtenga la salida.



Tambi茅n vale la pena mencionar por separado que puede transferir las ense帽anzas del programa Go a la biblioteca Rust. Para hacer esto, transformamos la funci贸n en la biblioteca Rust para que tome un valor de cadena.

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


Ensamblamos nuestro proyecto, copiamos la biblioteca a la carpeta lib nuevamente, modificamos el archivo process.h de esta manera
proceso nulo (char * name);

Pasamos la l铆nea desde la aplicaci贸n Go (en nuestro caso: "Hola desde Golang") .

package main

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

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


Todas. Ejecute el programa y obtenga la salida.


All Articles