Depurando Macros
Erros de macro aparecem como erros de compilador confusos nos locais de expansão. cargo expand, eprintln! em proc macros e testes trybuild são as principais ferramentas de depuração.
Receita
cargo install cargo-expand
cargo expand -p mycrate path::to::function
RUSTFLAGS="-Z unstable-options" cargo expand --theme=monokai # opcional// dentro da proc macro durante o desenvolvimento:
eprintln!("parseado: {:?}", input);Quando usar isso: Sempre que o código expandido não corresponder ao modelo mental ou os erros referenciarem spans incorretos.
Exemplo de Trabalho
# Expandir saída de derive
cargo expand -p api handlers::create_order
# Expandir módulo específico
cargo expand -p my_macros derive_validate
# Imprimir formatado em teste com macrotest// desenvolvimento de crate proc-macro
#[proc_macro_derive(MyTrait)]
pub fn derive_my_trait(input: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(input as DeriveInput);
if std::env::var("DEBUG_MACRO").is_ok() {
eprintln!("{:#?}", ast);
}
// ...
TokenStream::new()
}O que isso demonstra:
cargo expandmostra o Rust pós-macroeprintln!em proc macro é executado no tempo de compilaçãoDEBUG_MACROcomo gate de ambiente evita builds normais barulhentos- Comparar expansão entre versões de toolchain
Mergulho Profundo
Qualidade do Erro
return syn::Error::new_spanned(&field.ident, "field must have #[validate]")
.to_compile_error()
.into();- Spans bons superam mensagens boas na linha errada
compile_error!no braço de fallback demacro_rules!
trybuild
#[test]
fn ui() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/missing_field.rs");
}Armadilhas
- Ler erro sem expandir - tempo perdido. Correção: Hábito de expandir primeiro.
- eprintln em macro publicada - barulhento para usuários. Correção: flag de feature
debug-macros. - Pacote
-perrado - expansão vazia. Correção: workspacecargo expand -p proc_crate. - Expansão enorme ilegível - difícil de comparar. Correção:
rustfmtna saída expandida; snapshot commacrotest. - Recursos de expansão apenas noturnos - CI em estável. Correção: documentar truques opcionais noturnos.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
trace_macros! (instável) | Rastreamento de passo macro_rules! | CI Estável |
Snapshots macrotest | Regressão na expansão | Teste rápido único |
quote! manual em teste | Função geradora de teste unitário | Integração completa |
FAQs
expand não inclui derives std?
Algumas expansões embutidas diferem; foque em suas proc macros e macro_rules!.
Como expandir tokio::main?
cargo expand --bin myapp mostra a transformação principal.
Suporte de IDE para expand?
rust-analyzer "Expand macro recursively" para algumas macros; cargo-expand para fidelidade total.
Por que span é call_site?
Identificadores gerados resolvem na higiene do local de definição da macro; use deliberadamente.
Depuração de ambiguidade de macro_rules?
Comente braços; use um braço compile_error!(stringify!($($t)*)) para ver os tokens.
Testar expansões em CI?
macrotest ou verifique apenas em trybuild se passa/falha.
Expandir toda a crate?
cargo expand -p crate despeja a crate inteira - saída grande.
proc macro entra em pânico?
Mostra como erro de compilador com backtrace se RUST_BACKTRACE=1 na máquina do autor da macro.
Comparar duas toolchains?
Expanda a mesma entrada em 1.96 vs 1.97 ao atualizar MSRV.
Documentar depuração?
CONTRIBUTING para crate de macro: comando expand, trybuild, flags de ambiente.
Relacionado
- macro_rules! - macros declarativas
- syn & quote - depuração de AST
- Comandos Úteis do Cargo - instalação do expand
- Melhores Práticas de Macros
Versões da Pilha: 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+.