Annotation Processor¶
The annotation processor (bpf-processor) is a standard javac annotation processor that runs at round 1. It handles @BPF, @BPFMapClass, @BPFMapDefinition, and @Type annotations — tasks that need the full type hierarchy and field declarations but not the method bodies.
Responsibilities¶
- Discover
@BPF-annotated classes and verify they extendBPFProgram(Processor.java:135–142). - Resolve
@Type-annotated Java records, classes, and enums to BTF struct layouts viaTypeProcessor. - Emit a generated implementation class (e.g.
MyProgram$Impl) with agetByteCode()override; the compiler plugin later fills in the bytecode (Processor.java:300–367). - Write a
META-INF/ebpf-shared-from/<FQN>.jsonresource for cross-module@SharedFrommap references (Processor.java:198–202). - Validate
@GlobalVariablefield declarations: must be non-static, final, and initialised asnew GlobalVariable<>(...)(TypeProcessor.java:602–632). - Validate map field names and types for
@BPFMapDefinitionfields. - Invoke clang (via
Processor.compile()) to produce the.obytes that are embedded intogetByteCode().
Key classes¶
| Class | File | Role |
|---|---|---|
Processor |
bpf-processor/.../processor/Processor.java |
Entry-point AbstractProcessor; dispatches to TypeProcessor, generates implementation class, calls clang |
TypeProcessor |
bpf-processor/.../processor/TypeProcessor.java |
Resolves @Type records/classes/enums to BPFType instances; emits C struct/enum declarations |
BPFTypeLike |
bpf-processor/.../processor/BPFTypeLike.java |
Sealed hierarchy of BPF-representable type wrappers (struct, enum, typedef, verbatim, …) |
DefinedTypes |
bpf-processor/.../processor/DefinedTypes.java |
Name registry: maps Java names ↔ BPF names ↔ spec field names; detects cycles |
AnnotationUtils |
bpf-processor/.../processor/AnnotationUtils.java |
Helpers for reading annotation mirrors in a javac-version-safe way |
CompilationCache |
bpf-processor/.../processor/CompilationCache.java |
Caches clang compilation results keyed by C source hash to avoid recompiling unchanged programs |
CompilerErrorProcessor |
bpf-processor/.../processor/CompilerErrorProcessor.java |
Parses clang error output and maps C line numbers back to Java source positions |
TailCallTableInfo |
bpf-processor/.../processor/TailCallTableInfo.java |
Holds resolved metadata for @BPFTailCallTable-annotated prog-array fields |
How it differs from the compiler plugin¶
The processor sees only annotations and type declarations, not method bodies. It runs at annotation-processing time (before the compilation phase), so it can generate new source files that javac will then compile. The compiler plugin runs at compilation time (after all annotation processors have finished), when method ASTs are available. The two components communicate indirectly: the processor generates the $Impl class skeleton, and the compiler plugin patches getByteCode() by embedding the compiled BPF object file into that class.
Extending the processor¶
- Add a new annotation. Define the annotation in the
annotations/module (not inbpf-processor/orbpf/). - Add a processor round in
TypeProcessororProcessor. If the annotation describes a type shape, add a resolution branch inTypeProcessor.processType(). If it affects the generated implementation class, add logic inProcessor.processBPFProgram(). - Write an integration test. Use the
InMemoryJavaCompilerhelper already used inbpf-compiler-plugin-test/. Compile a minimal@BPFclass that uses the new annotation and assert on the generated Java source or on any diagnostic messages emitted.
Next: Error Classifier