Cross-Platform Systems Code
Write portable systems code with cfg, conditional compilation, and platform abstraction crates.
Busca en todas las páginas de la documentación
Write portable systems code with cfg, conditional compilation, and platform abstraction crates.
#[cfg(unix)]
fn home_dir() -> Option<std::path::PathBuf> {
std::env::var_os("HOME").map(std::path::PathBuf::from)
}
#[cfg(windows)]
fn home_dir() -> Option<std::path::PathBuf> {
std::env::var_os("USERPROFILE").map(std::path::PathBuf::from)
}When to reach for this: Tools and libraries that ship on Linux, macOS, and Windows without maintaining separate codebases.
use std::path::{Path, PathBuf};
#[cfg(unix)]
mod platform {
use std::os::unix::fs::PermissionsExt;
pub fn is_executable(meta: &std::fs::Metadata) -> bool {
meta.permissions().mode() & 0o111 != 0
}
}
#[cfg(windows)]
mod platform {
pub fn is_executable(meta: &std::fs::Metadata) -> bool {
meta.is_file() && meta.file_name().to_string_lossy().ends_with(".exe")
}
}
pub fn find_in_path(name: &str) -> Option<PathBuf> {
let path_var = std::env::var_os("PATH")?;
for dir in std::env::split_paths(&path_var) {
let candidate = dir.join(name);
if candidate.is_file() {
if let Ok(meta) = std::fs::metadata(&candidate) {
if platform::is_executable(&meta) {
return Some(candidate);
}
}
}
}
None
}What this demonstrates:
cfg(unix) / cfg(windows) isolate platform codestd::env::split_paths handles PATH separator differences| Attribute | Matches |
|---|---|
unix | Linux, macOS, BSD |
windows | Windows MSVC/GNU |
target_os = "linux" | Linux only |
target_arch = "aarch64" | ARM64 |
| Crate | Role |
|---|---|
std::path::Path | / vs \ separators |
dirs / etcetera | Known folders (config, cache) |
tempfile | Cross-platform temp files |
which | PATH lookup |
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable]/ breaks on Windows. Fix: Always Path::join.\r\n on Windows. Fix: Use std::io::BufRead lines or #[cfg(windows)] trimming.cfg or optional features.| Alternative | Use When | Don't Use When |
|---|---|---|
| Separate binaries per OS | Radically different UX | 90% shared logic |
cfg_if! macro | Many nested cfgs | Simple two-platform split |
| WASM target | Sandboxed portability | Need raw OS access |
Prefer cfg for compile-time differences. Runtime std::env::consts::OS for logging only.
Cross-compile and run tests in CI on windows-latest runners.
std::net is mostly portable. Edge cases (Unix sockets) need cfg(unix).
notify crate abstracts inotify, FSEvents, and ReadDirectoryChangesW.
Windows has legacy MAX_PATH limits. Use \\?\ prefix for long paths when needed.
std::process::Command is cross-platform. Unix-specific pre_exec needs cfg.
#[no_mangle] exports differ from Unix. Test dlopen/LoadLibrary per platform.
Use target_os = "android" / "ios" cfgs. Mobile has stricter sandbox rules.
Treat WSL as Linux for cfg(unix). Path translation across /mnt/c needs care.
State supported OS list in README and fail with clear errors on unsupported platforms.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Revisado por Chris St. John·Última actualización: 16 jul 2026