Le blog du jour
OpenWrt facile
26 janvier 2025

Création d’un package Rust
Un package Rust nécessite le paquet rust-lang fourni par openwrt depuis la version 23.05. La création du package est similaire à celles des autres paquets, elle se base sur la présence d’un Makefile faisant appel à l’environnement de compilation d’OpenWrt. Ce paquet dépend du paquet hôte rust et inclut les règles rust-package. Le répertoire de génération doit contenir les fichiers du projet Rust, à minima Cargo.toml et mains.rs.
Le paquet basique testrust permet de créer un exécutable affichant un texte :
Paquet testrust
testrust
├── Cargo.toml
├── Makefile
└── src
└── main.rs
Makefile
include $(TOPDIR)/rules.mk
PKG_NAME:=testrust
PKG_VERSION:=0.0.1
PKG_RELEASE:=1
PKG_BUILD_DEPENDS:=rust/host
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/package/feeds/packages/rust/rust-package.mk
define Package/testrust
SECTION:=Perso
CATEGORY:=Utilities
TITLE:=Test rust
DEPENDS:=
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
mkdir -p $(PKG_BUILD_DIR)/src
$(CP) ./src/* $(PKG_BUILD_DIR)/src/
$(CP) Cargo.toml $(PKG_BUILD_DIR)/
endef
$(eval $(call RustBinPackage,testrust))
$(eval $(call BuildPackage,testrust))
src/main.rs code source
fn main() {
println!("[rust] start");
}
Cargo.toml fichier manifeste
[package]
name = "testrust"
version = "0.0.1"
La compilation du paquet nécessite la compilation de rust-lang qui se base sur les cibles rust pour générer l’environnement de compilation croisé.
Le paquet testrust génère un exécutable testrust que l‘on peut lancer sur la console :
root@OpenWrt:~# testrust
[rust] start
Le paquet testrust est ainsi intégré à l’environnement de compilation d’OpenWrt, l’utilisation des autres paquets s’en trouve facilitée.
L’utilisation d’une librairie personnelle développée en C est simple.
La librairie basique libcool permet de renseigner une structure avec des paramètres en entrée :
cool.h
typedef struct CoolStruct {
int x;
int y;
} CoolStruct;
void cool_function(int i, char c, CoolStruct* cs);
cool.c
#include <stdio.h>
#include "cool.h"
void cool_function(int i, char c, CoolStruct* cs) {
cs->x = i+c;
cs->y = i;
}
Pour l’utiliser dans le paquet testrust il suffit de la déclarer dans un nouveau fichier build.rs qui va l’indiquer au système de génération de l’exécutable :
build.rs
fn main() {
println!("cargo::rustc-link-lib=dylib=cool");
}
Ce fichier doit être incorporé au répertoire de génération, il suffit pour cela d’ajouter sa copie par le Makefile outre la dépendance :
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
mkdir -p $(PKG_BUILD_DIR)/src
$(CP) ./src/* $(PKG_BUILD_DIR)/src/
$(CP) Cargo.toml $(PKG_BUILD_DIR)/
$(CP) build.rs $(PKG_BUILD_DIR)/
endef
Il est ensuite nécessaire de définir l’interface avec la librairie dans le fichier source rust. Pour cela il est nécessaire d’utiliser les types explicitement C compatibles, d’indiquer explicitement la représentation C compatible des structures et d’indiquer l’utilisation de C ABI par les fonctions lors de la définition de leur signature. Enfin l’appel aux fonctions étrangères est forcément unsafe :
main.rs
use std::os::raw::c_int;
use std::os::raw::c_char;
#[repr(C)]
pub struct CoolStruct {
pub x: c_int,
pub y: c_int,
}
extern "C" {
pub fn cool_function(i: c_int, c: c_char, cs: *mut CoolStruct);
}
fn main() {
println!("[rust] start\n");
let mut cs = CoolStruct { x : 0, y : 0 };
unsafe {
cool_function(50,36,&mut cs);
println!("cool structure : {} {} gives x {} and y {}",50,36,cs.x,cs.y);
}
}
L’utilisation des fonctions de la libc, ici musl, est simple, il suffit de les définir en tant que C, ici les fonctions abs, sqrt et pow :
use std::os::raw::c_int;
use std::os::raw::c_double;
use std::os::raw::c_char;
extern "C" {
fn abs(num: c_int) -> c_int;
fn sqrt(num: c_double) -> c_double;
fn pow(num: c_double, power: c_double) -> c_double;
}
fn main() {
println!("[rust] start\n");
let x: i32 = -123;
println!("\nAbsolute value of {x}: {}.",
unsafe { abs(x) });
let n: f64 = 9.0;
let p: f64 = 3.0;
println!("\n{n} raised to {p}: {}.",
unsafe { pow(n, p) });
let mut y: f64 = 64.0;
println!("\nSquare root of {y}: {}.",
unsafe { sqrt(y) });
y = -3.14;
println!("\nSquare root of {y}: {}.",
unsafe { sqrt(y) });
}
Enfin l’utilisation des autres paquets rust est aussi très simple. Par exemple l’utilisation de rand nécessite juste sa déclaration en tant que dépendance dans le fichier manifeste.
Cargo.toml
[package]
name = "testrust"
version = "0.0.1"
[dependencies]
rand = "0.8.4"
Et la fonction random, par exemple est maintenant disponible :
fn main() {
println!("[rust] start\n");
let x: u8 = rand::prelude::random();
println!("\nrandom number {}", x);
}
Le paquet testrust génère maintenant un exécutable utilisant une librairie dynamique C, la libc, et le paquet rand.
main.rs
use std::os::raw::c_int;
use std::os::raw::c_double;
use std::os::raw::c_char;
#[repr(C)]
pub struct CoolStruct {
pub x: c_int,
pub y: c_int,
}
extern "C" {
pub fn cool_function(i: c_int, c: c_char, cs: *mut CoolStruct);
fn abs(num: c_int) -> c_int;
fn sqrt(num: c_double) -> c_double;
fn pow(num: c_double, power: c_double) -> c_double;
}
fn main() {
println!("[rust] start\n");
let mut cs = CoolStruct { x : 0, y : 0 };
unsafe {
cool_function(50,36,&mut cs);
println!("cool structure : {} {} gives x {} and y {}",50,36,cs.x,cs.y);
}
let x: i32 = -123;
println!("\nAbsolute value of {x}: {}.",
unsafe { abs(x) });
let n: f64 = 9.0;
let p: f64 = 3.0;
println!("\n{n} raised to {p}: {}.",
unsafe { pow(n, p) });
let mut y: f64 = 64.0;
println!("\nSquare root of {y}: {}.",
unsafe { sqrt(y) });
y = -3.14;
println!("\nSquare root of {y}: {}.",
unsafe { sqrt(y) });
let x: u8 = rand::prelude::random();
println!("\nrandom number {}", x);
}
Après génération l’éxécutable testrust est utilisable via la console :
root@OpenWrt:~# testrust
[rust] start
cool structure : 50 36 gives x 86 and y 50
Absolute value of -123: 123.
9 raised to 3: 729.
Square root of 64: 8.
Square root of -3.14: NaN.
random number 212
© 2018 isttechservice.fr
