Attributes and cfg
Attributes are annotations that give the compiler extra instructions about a piece of code. They appear above the item they apply to, using the #[...] syntax.
The three you will use most
#[cfg(test)] — conditional compilation
#![allow(unused)] fn main() { #[cfg(test)] mod tests; }
This tells the compiler: include this module only when running cargo test. When you build normally (cargo build, cargo run), the test module does not exist. Test code stays completely out of production binaries.
Common conditions:
#![allow(unused)] fn main() { #[cfg(test)] // only during cargo test #[cfg(target_os = "macos")] // only on macOS #[cfg(debug_assertions)] // only in debug builds }
#[test] — marking a test function
#![allow(unused)] fn main() { #[test] fn test_jp() { let mut cpu = Cpu::new(); // ... assert_eq!(cpu.pc, 0x300); } }
#[test] marks a function as a test case. The test runner (cargo test) finds every function with this attribute and runs them. Without it, the function is just a regular function that never gets called automatically.
#[derive(...)] — auto-implementing traits
#![allow(unused)] fn main() { #[derive(Debug, Clone)] pub struct Cpu { ... } }
derive asks the compiler to generate a trait implementation automatically. It reads the struct definition and writes the code for you. Without derive, you would have to write:
#![allow(unused)] fn main() { impl std::fmt::Debug for Cpu { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { // ... 20+ lines of boilerplate } } }
Applying to the whole file
An attribute with ! applies to the entire enclosing module instead of the next item:
#![allow(unused)] #![allow(dead_code)] // suppress dead_code warnings for this whole file fn main() { }
Summary
| Attribute | Effect |
|---|---|
#[cfg(test)] | compile only during cargo test |
#[test] | mark as a test function |
#[derive(...)] | auto-generate trait implementations |
#[allow(...)] | suppress a compiler warning |
In the emulator: Every test file uses
#[cfg(test)]on the module declaration and#[test]on each test function.#[derive(Debug)]is on most structs so test assertion failures print readable output. See Modules for how test files are structured.