Ok, para usar Linker primero debemos saber que es.
Teoria
Linker: es la parte de la compilación en la que se une los binarios de los programas y librerias para volverlos un ejecutable. Aqui hay una imagen que lo ilustra mejor.
Esta imagen explica todo el proceso que se hace al compilar.
Ahora, ¿Como hacemos para compilar 2 lenguajes?
Imaginemos que tenemos un lenguaje A y queremos usar una funcion el lenguaje B, lo que podemos hacer es usar el linker, en la parte donde se llega al linker se inserta el codigo de la libreria que se vaya a usar. Por ejemplo, tenemos el clasico main() de C:
#include <stdio.h>
int main() {
printf("Hola Mundo!!!");
return 0;
}
al compilar lo primero que hace es adonde se ubica el “#include <stdio.h>” inserta todo el codigo de que tiene el archivo “stdio.h” para que se puedan usar la funcione, que es ese el proceso de “Precompilado” al momento de llegar al linker, lo que hace el compilador es entrelazar los binarios de la libreria “stdio.h” que son funciones, variable, etc para al fin se convierta en un ejecutable. Cabe recalcar que este metodo lo usan proyecto como el kernel de linux y demas proyecto.
Practica
Ahora lo que vamos hacer es usar codigo en Rust en C y viseversa.
Primero vamos aver el usar funciones de C en Rust:
code_c
Aqui se ubica todo el codigo de C:
Aqui esta el codigo en C:
mylib.c
mylib.h
Esto es lo clasico al crear una libreria en C.
build.rs
Vamos a explicar cada archivo de aqui. Empezando por el build.rs, lo que hace este archivo es compilar la libreria “mylib” para su uso.
Cargo.toml
Creamos una variable que hace es decirle al compilador que para compilar “build.rs” aparte de compilar el resto del proyecto. Mas abajo esta “[build-dependencies]” que se declarar las dependecia que se usan en el archivo “build.rs”.
main.rs
Aqui es donde esta la chicha, con el keywords “unsafe” (le dice al compilador que no se preocupe por el codigo que hay dentro de “unsafe” que por lo general el compilador no dejaria compilar este codigo) y el "extern “C” " para aclarar que la funcion este en un archivo externo en C.
Para decir que funcion hay, lo que hay que hacer es crear una funcion con el mismo nombre y mismo atributos.
Aclaracion: Si tenemos una funcion en C que es:
int number(int n1, int n2)
para trasladarlo a Rust lo que hacemos es:
fn number(n1: i32, n2: i32) -> i32
Porque esto? i32 es el tamaño que maneja el compilador GCC. Por defecto al crear un entero en el compilador GCC el tamaño 32 bits.
Aclaración dentro de la Aclaración:
No estoy seguro de que esto sea asi, pero si por alguna razon esta compilando con otro compilador que no es gcc, debes tener en cuenta que tamaño es el que tiene el entero al declarar la variable. Repito no estoy tan seguro y mi logica dice que es asi, el que pueda averiguar eso se lo agradeceria mucho.
Despues en la funciona “main” se usa la misma keywords “unsafe” para decir que el codigo que se va a ejecutar no es seguro y que el compilador no moleste.
Ahora vamos con Rust en C:
main.rs
``` #[unsafe(no_mangle)] extern "C" fn Hello_C() { println!("Hello C!!!"); } ```En este archivo, vemos el atributo “no_mangle” dentro de la funcion unsafe, por el lado de unsafe, es lo mismo que el keywords unsafe. Por el lado de “no_mangle” lo que hace es que no cambie el id de la funcion y que se quede con el mismo nombre que en este caso es “Hello_C”. Despues de eso esta "extern “C” " esto le dice al compilador que la funcion que se va a declarar acontinuacion es puede ser accesible desde C.
Aclaracion: Por lo general antes de escribir “extern” se pone “pub” para decir que la funcion es publica, pero de igual manera me funciono sin “pub” si tienen algun problema de que la funcion es privada o no es accesible posiblemente sea ese el problema.
main.c
``` extern void Hello_C();int main() {
Hello_C();
return 0;
}
No me centrare mucho en lo que hace este codigo en C, solo dice que la funcion estan en un binario externo y que es una funcion sin mas, osea, no devuelve nada, en el caso que si devolviera un entero por ejemplo, tiene que declarar una funcion entero.
Ahora, la parte divertidad:
Primero vamos a compilar Rust, ya que en este caso es una libreria:
rustc --crate-type=staticlib main.rs
>Aclaracion: Es comando funciona unicamente si es un solo archivo, si quieres hacerlo desde un proyecto creado por cargo, tienes que añadir al archivo "Cargo.toml":
>```
>[lib]
>crate-type = ["cdylib"]
>```
>El flags "cdylib" lo que dice es que va a compilar a una libreria dinamica para C pero con "staticlib" funciona igual.
>
>y despues de eso ejecutar el comando
>```cargo build```
Despues de compilar el archivo de Rust, compilamos el archivo en C a binario con este comando:
gcc -c main.c
Ya despues de tener los 2 binarios, se compila los 2 otra vez con gcc:
gcc main.o libmain.a -o a
(Lo que tiene que devolver el compilador de rust es un .a o parecido)
Y listo ya sabes como combinar 2 lenguajes compilados.
<h1>Bibliografica</h1>
Este [video](https://www.youtube.com/watch?v=XJC5WB2Bwrc&t=337s) es donde saque la mayoria de infomacion de lo que es un linker.
[Aqui](https://doc.rust-lang.org/nomicon/ffi.html) es donde esta la mayoria de informacion mas detallada de compilar libreria en Rust para C y viseversa.