Use cargo expand to inspect the final Rust code after macro expansion by running it as a subcommand within your project directory. This tool is essential for debugging complex macros, understanding generated code, and verifying that your procedural macros or declarative macros are producing the expected output.
First, install the tool globally using cargo install cargo-expand. Once installed, navigate to your project root and run cargo expand to see the expanded code for the default binary. You can target specific items like functions or modules using the --item flag to avoid printing the entire crate.
# Install the tool globally
cargo install cargo-expand
# Expand the entire default binary
cargo expand
# Expand a specific function named "my_macro"
cargo expand --item my_macro
# Expand a specific module named "utils"
cargo expand --item utils
If you need to see the expansion for a specific crate in a workspace or a library target, use the --lib or --bin flags. For example, cargo expand --lib will show the expanded code for the library target. This is particularly useful when working with procedural macros where the generated code can be significantly different from the source.
When debugging, you might encounter issues where the expansion fails due to missing dependencies or configuration. Ensure your Cargo.toml is clean and that you are running the command in the correct directory. If you need to see the expansion with specific features enabled, pass the --features flag just like you would with a normal cargo build command.
# Expand with a specific feature enabled
cargo expand --features "my-feature"
# Expand a specific binary target in a workspace
cargo expand --bin my_binary
Remember that cargo expand runs in a separate build context, so it might not reflect runtime optimizations or specific compiler flags unless explicitly configured. It is primarily a development tool for understanding macro behavior, not for production builds. If the output is too large, consider piping it to a file or using less for pagination.
# Pipe output to a file for inspection
cargo expand > expanded_code.rs
# View output in a pager
cargo expand | less
This approach saves time by eliminating the need to manually trace macro invocations or guess at generated code structures. It is a standard part of the Rust developer's toolkit for macro-heavy projects.