There are many ways to detect the target OS, e.g. #[cfg(windows)]
, #[cfg(unix)]
, std::env::consts::OS
. For cross-compilation, how can we detect the OS that our Rust program gets compiled on?
Since build.rs
is run on the workstation (not the target), I guess it can detect some workstation related properties then generate features (cfg
) that can be tested in the target related code.
For example, here is a build.rs
script that detects a specific file on your workstation.
fn main() {
// detected on the workstation (not the target)
if let Ok(_attr) = std::fs::metadata("dummy_file.txt") {
println!("cargo:rustc-cfg=detected");
}
if cfg!(windows) {
println!("cargo:rustc-cfg=from_windows");
}
if cfg!(unix) {
println!("cargo:rustc-cfg=from_unix");
}
}
Then, src/main.rs
can test the detected feature.
#[cfg(detected)]
fn hello() {
if cfg!(from_windows) {
println!("hello from windows with detected file");
}
if cfg!(from_unix) {
println!("hello from unix with detected file");
}
}
#[cfg(not(detected))]
fn hello() {
if cfg!(from_windows) {
println!("hello from windows");
}
if cfg!(from_unix) {
println!("hello from unix");
}
}
fn main() {
// run on the target (not the workstation)
hello();
}
Depending on whether dummy_file.txt
exists or not on the workstation when building the project, the resulting binary for the target will use one version or the other of hello()
.
Each of these two functions can adapt their behaviour depending on the OS the workstation.