Código de Sistemas Multiplataforma
Escreva código de sistemas portável com cfg, compilação condicional e crates de abstração de plataforma.
Receita
#[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)
}Quando usar isso: Ferramentas e bibliotecas que funcionam em Linux, macOS e Windows sem a necessidade de manter bases de código separadas.
Exemplo de Trabalho
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
}O que isso demonstra:
cfg(unix)/cfg(windows)isolam o código da plataforma- API compartilhada com implementações específicas da plataforma
std::env::split_pathslida com diferenças de separador doPATH- Verificações de executável diferem por sistema operacional
Mergulho Profundo
Atributos cfg
| Atributo | Corresponde |
|---|---|
unix | Linux, macOS, BSD |
windows | Windows MSVC/GNU |
target_os = "linux" | Apenas Linux |
target_arch = "aarch64" | ARM64 |
Crates de Abstração
| Crate | Papel |
|---|---|
std::path::Path | Separadores / vs \ |
dirs / etcetera | Pastas conhecidas (config, cache) |
tempfile | Arquivos temporários multiplataforma |
which | Pesquisa no PATH |
Matriz de CI
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable]Armadilhas
- Suposições de strings de caminho -
/codificado em hard break no Windows. Correção: Sempre usePath::join. - Finais de linha -
\r\nno Windows. Correção: Use linhasstd::io::BufReadou#[cfg(windows)]para remover. - Caminhos sensíveis a maiúsculas/minúsculas - O padrão do macOS não diferencia maiúsculas de minúsculas. Correção: Normalize caminhos em testes; documente o comportamento.
- Derivação de recursos entre destinos - O código compila apenas no Linux. Correção: Requer CI em todos os três destinos de SO.
- Dependências exclusivas do Unix em recursos padrão - A compilação do Windows falha. Correção: Use
cfgou recursos opcionais.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Binários separados por SO | UX radicalmente diferente | 90% de lógica compartilhada |
Macro cfg_if! | Muitos cfg aninhados | Divisão simples de duas plataformas |
| Alvo WASM | Portabilidade em sandbox | Necessidade de acesso direto ao SO |
FAQs
cfg vs detecção em tempo de execução?
Prefira cfg para diferenças em tempo de compilação. Use std::env::consts::OS em tempo de execução apenas para logs.
Como testar código Windows no Linux?
Compile cruzado e execute testes em CI em executores windows-latest.
Diferenças de socket?
std::net é majoritariamente portável. Casos extremos (sockets Unix) precisam de cfg(unix).
Observação de arquivos?
O crate notify abstrai inotify, FSEvents e ReadDirectoryChangesW.
Comprimento máximo do caminho?
O Windows tem limites legados de MAX_PATH. Use o prefixo \\?\ para caminhos longos quando necessário.
APIs de processo?
std::process::Command é multiplataforma. O pre_exec específico do Unix precisa de cfg.
Nomenclatura de símbolos no Windows?
#[no_mangle] exporta diferentemente do Unix. Teste dlopen/LoadLibrary por plataforma.
Android / iOS?
Use cfgs target_os = "android" / "ios". Mobile tem regras de sandbox mais rigorosas.
Considerações sobre WSL?
Trate WSL como Linux para cfg(unix). A tradução de caminhos entre /mnt/c requer cuidado.
Documentar suporte de plataforma?
Declare a lista de SOs suportados no README e falhe com erros claros em plataformas não suportadas.
Relacionados
- Noções Básicas de Sistemas - uso de std portável
- Sinais e Controle de Processos - sinais específicos do SO
- libc e Syscalls - baixo nível específico da plataforma
- Melhores Práticas de Programação de Sistemas - checklist de portabilidade
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.