I want to create a multi-platform application that accesses the file system, and while I can use std::fs
, I've found that the OS specific crates simplify the code a bit. So, I wrote up some code using std::os::windows::fs
, and it worked as expected.
My issue now, is that I want to write code for both Windows and Linux. To do this, I've created separate functions that in theory will use std::os::windows
and std::os::linux
respectfully. However when trying to compile on Linux for Linux, I came across the error that std::os::windows
was not a recognised crate.
My question is, is there any way for me to either use std::os::windows
on Linux and vice versa, or only compile specific chunks of code depending on the operating system cargo is used on?
I know this is a bit of a stupid question, considering the fact that I could just write separate modules for different OSes, but I do want to try and contain everything in one module.
My current Code is something along the lines of:
pub fn run(os: &str, path: &str){
let files = fs::read_dir(path).unwrap_or_else(|error: std::io::Error| {
println!("Error: {error}");
process::exit(1);
});
// The 'os' variable is obtained from std::env::consts::OS
if os == "windows" {
// Use std::os::windows in the following function
printDir_win(files);
} else if os == "linux" {
// Use std::os::linux in the following function
printDir_lin(files);
} else {
println!("{}OS not recognised: defaulting to std::fs methods{}","\x1b[31m","\x1b[0m");
printDir(files);
}
}
Use the #[cfg(…)
attribute for conditional compilation depending on the target OS. That way the compiler won't try to compile code that targets a different OS:
pub fn run(path: &str){
let files = fs::read_dir(path).unwrap_or_else(|error: std::io::Error| {
println!("Error: {error}");
process::exit(1);
});
// The 'os' variable is obtained from std::env::consts::OS
#[cfg (target_os = "windows")]
{
// Use std::os::windows in the following function
use std::os::windows::*;
printDir_win(files);
}
#[cfg (target_os = "linux")]
{
// Use std::os::linux in the following function
use std::os::linux;
printDir_lin(files);
}
#[cfg (not (any (target_os = "windows", target_os = "linux")))]
{
println!("{}OS not recognised: defaulting to std::fs methods{}","\x1b[31m","\x1b[0m");
printDir(files);
}
}
Note that from an organization standpoint, it is considered good practice to group your platform-specific code in a module that abstracts the differences behind a common API:
#[cfg (target_os = "windows")]
mod platform {
use std::os::windows::*;
pub fn print_dir (files: std::fs::ReadDir) {
unimplemented!()
}
}
#[cfg (target_os = "linux")]
mod platform {
use std::os::linux::*;
pub fn print_dir (files: std::fs::ReadDir) {
unimplemented!()
}
}
#[cfg (not (any (target_os = "windows", target_os = "linux")))]
mod platform {
pub fn print_dir (files: std::fs::ReadDir) {
unimplemented!()
}
}
Then the rest of your code doesn't need to check the OS everywhere to know which function to call:
pub fn run(path: &str){
let files = std::fs::read_dir(path).unwrap_or_else(|error: std::io::Error| {
println!("Error: {error}");
std::process::exit(1);
});
platform::print_dir (files);
}