Platform-Specific Code
Rust provides built-in #[cfg(...)] target predicates and platform-specific standard library extension modules (std::os::unix, std::os::windows, std::os::fd) to write platform-specific code while presenting a unified cross-platform API to callers.
Operating System and Environment #[cfg] Predicates
| Predicate Key | Common Values | Meaning |
|---|---|---|
target_family (or shorthand) |
unix, windows, wasm |
Broad OS family (#[cfg(unix)] is shorthand for #[cfg(target_family = "unix")], matching Linux, macOS, FreeBSD, iOS, Android) |
target_os |
"linux", "macos", "windows", "freebsd", "ios", "android", "none" |
Specific operating system kernel ("none" for bare-metal targets) |
target_env |
"gnu", "musl", "msvc", "sgx", "" |
C runtime / ABI environment (distinguishes x86_64-unknown-linux-gnu from x86_64-unknown-linux-musl) |
target_vendor |
"apple", "pc", "unknown", "fortanix" |
Hardware / OS vendor |
Relationship Between `target_family` and `target_os`:
#[cfg(unix)] (`target_family = "unix"`)
+-- target_os = "linux" (target_env = "gnu" | "musl")
+-- target_os = "macos" (target_vendor = "apple")
+-- target_os = "freebsd"
+-- target_os = "android" / "ios"
#[cfg(windows)] (`target_family = "windows"`)
+-- target_os = "windows" (target_env = "msvc" | "gnu")
Accessing OS-Specific Extension Traits (std::os)
The Rust standard library keeps std::fs::File, std::process::Command, and std::net::TcpStream strictly portable, and exposes OS-specific capabilities—such as raw file descriptors (RawFd), Unix file permissions (mode), inode numbers (ino), or Windows security attributes—through extension traits under std::os::<platform>:
use std::fs::File;
#[cfg(unix)]
fn inspect_os_handle(file: &File) {
use std::os::fd::AsRawFd;
use std::os::unix::fs::MetadataExt;
let fd = file.as_raw_fd();
let meta = file.metadata().unwrap();
println!(
"Unix file -> raw fd = {}, mode = {:o}, ino = {}",
fd,
meta.mode() & 0o777,
meta.ino()
);
}
#[cfg(windows)]
fn inspect_os_handle(file: &File) {
use std::os::windows::io::AsRawHandle;
println!("Windows file -> raw HANDLE = {:?}", file.as_raw_handle());
}
fn main() -> std::io::Result<()> {
let path = std::env::temp_dir().join("rust_ch42_platform_demo.tmp");
let file = File::create(&path)?;
inspect_os_handle(&file);
drop(file);
std::fs::remove_file(&path)?;
Ok(())
}
Unix file -> raw fd = 3, mode = 644, ino = 48192014
Structuring Cross-Platform Abstractions Without Duplicating Call Sites
Never scatter #[cfg(unix)] and #[cfg(windows)] across application business logic. Instead, define a single cross-platform function or struct signature and place the platform-specific implementations inside private helper functions or platform modules so callers remain 100% platform-agnostic.