Accès à l’OS
Dans les chapitres sur la programmation système, nous avons étudié des primitives ayant vocation à être portables d’un système d’exploitation à l’autre.
En échange, le prix à payer est que nous ne pouvions pas tirer parti des spécificités de chaque système d’exploitation. Par exemple, nous ne pouvions pas interroger les inoeuds et permissions de fichiers sous Linux, ni avoir accès aux identifiants bruts de fichiers ouverts, connexions réseau, … afin de pouvoir appeler des fonctions spécifiques à chaque OS sur nos objets Rust.
Pour avoir accès à ces fonctionnalités et concepts non portables, il suffit
d’importer dans le scope les traits du module
std::os
. Ceux-ci ajoutent aux
types standard portable des fonctionnalités non-portables spécifiques à un
système d’exploitation donné.
Par exemple, dans un exemple du chapitre précédent sur #[cfg()]
, nous avons
utilisé un de ces traits pour obtenir le numéro de descripteur
d’un fichier ouvert :
#![allow(unused)] fn main() { // Ouverture d'un fichier en écriture (cf chapitre système) use std::fs::File; let fichier = File::create("/tmp/test.txt") .expect("Echec de création du fichier"); // Instructions spécifiques aux systèmes Unix (Linux, macOS...) #[cfg(unix)] { use std::os::unix::io::AsRawFd; let fd = fichier.as_raw_fd(); println!("On utilise le descripteur de fichier numéro {fd}"); } }
Notez l’utilisation de #[cfg(unix)]
: le trait AsRawFd
n’est disponible que
quand on compile pour un système Unix. Tenter d’utiliser quoi que ce soit du
module std::os::unix
sous un autre OS tel que Windows causera une erreur de
compilation : si on n’est pas sur le bons système, le code associé de la
bibliothèque standard n’est tout simplement pas compilé.
Les systèmes d’exploitation qui exposent un grand nombre de ces “traits
d’extension” fournissent également un module prelude
qui permet d’importer
facilement l’ensemble des traits d’un coup. Par exemple, le code ci-dessus
pourrait aussi s’écrire de la façon suivante :
#![allow(unused)] fn main() { // Ouverture d'un fichier en écriture (cf chapitre système) use std::fs::File; let fichier = File::create("/tmp/test.txt") .expect("Echec de création du fichier"); // Instructions spécifiques aux systèmes Unix (Linux, macOS...) #[cfg(unix)] { use std::os::unix::prelude::*; // Inclut notamment AsRawFd let fd = fichier.as_raw_fd(); println!("On utilise le descripteur de fichier numéro {fd}"); } }
Les traits de std::os
ne visent cependant qu’à compléter les types de la
bibliothèque standard par des fonctionnalités non portables. Ils n’ajoutent pas
de nouvelles notions complètement spécifiques à chaque système d’exploitation.
Donc si on veut utiliser des fonctionnalités complètement spécifiques à un
système d’exploitation, telles que
io_uring
sous Linux ou
Direct3D sous Windows, il faudra
utiliser des bibliothèques spécifiques à chaque système d’exploitation pour y
avoir accès.
Deux bons points d’entrée sont libc
pour
les systèmes Unix et windows
pour
Windows.