|
| 1 | +# instrument-hooks |
| 2 | + |
| 3 | +Zig library that compiles to a single-file C library (`dist/core.c`) for controlling CodSpeed instrumentations via IPC. Consumed as FFI by integrations in multiple languages (Python, Rust, C/C++, etc.). |
| 4 | + |
| 5 | +## Build & Test |
| 6 | + |
| 7 | +```bash |
| 8 | +zig build # Build (outputs zig-out/lib/core.c) |
| 9 | +zig build test --summary all # Run tests |
| 10 | +just release # Build + generate dist/core.c |
| 11 | +just cmake-run-example # Build and run the C example via CMake |
| 12 | +just bazel-run-example # Build and run the C example via Bazel |
| 13 | +just test-valgrind # Compile example with gcc/clang and run under valgrind |
| 14 | +just fmt # Format Zig source |
| 15 | +``` |
| 16 | + |
| 17 | +Requires **Zig 0.14+**. Optional: [Just](https://github.com/casey/just) for convenience commands. |
| 18 | + |
| 19 | +## Architecture |
| 20 | + |
| 21 | +### Source layout |
| 22 | + |
| 23 | +- `src/c.zig` — C FFI export layer. All public API functions are defined here with `pub export fn`. |
| 24 | +- `src/instrument_hooks.zig` — Main `InstrumentHooks` struct combining all subsystems. |
| 25 | +- `src/instruments/root.zig` — Instrumentation backend union (valgrind, perf, analysis, none). Fallback chain: valgrind > analysis > perf > none. |
| 26 | +- `src/instruments/{valgrind,perf,analysis}.zig` — Individual backends. |
| 27 | +- `src/runner_fifo.zig` — IPC protocol with the CodSpeed runner via Unix named pipes. |
| 28 | +- `src/fifo.zig` — Low-level Unix pipe reader/writer with bincode serialization. |
| 29 | +- `src/shared.zig` — Protocol types (`Command` union, `MarkerType`, version). |
| 30 | +- `src/bincode.zig` — Bincode binary serialization (port of qbradley/bincode-zig). |
| 31 | +- `src/environment/root.zig` — Key-value integration/toolchain metadata and linked library collection, serialized to JSON. |
| 32 | +- `src/environment/linked_libraries/root.zig` — Collects metadata about dynamically linked libraries (path, soname, build ID, verdef). |
| 33 | +- `src/environment/linked_libraries/elf_view.zig` — Read-only ELF navigation helper for parsing in-memory program headers (PT_DYNAMIC, PT_NOTE, DT_VERDEF). Portable across all Linux architectures. |
| 34 | +- `src/environment/linked_libraries/testdata/test_lib.c` — Minimal C source compiled into a test fixture `.so` by `build.zig`. Linked into the test binary so it appears in `dl_iterate_phdr` for ElfView tests. |
| 35 | +- `src/features.zig` — Runtime feature flags (bit set). |
| 36 | +- `src/logger.zig` — Simple leveled logging via C `printf`. |
| 37 | +- `src/utils.zig` — Low-level utilities (clock_gettime, sleep). |
| 38 | +- `src/root.zig` — Test runner entry point (imports all modules for testing). |
| 39 | + |
| 40 | +### Headers & distribution |
| 41 | + |
| 42 | +- `includes/core.h` — Manually maintained C API header. Must be updated when adding/removing exported functions. |
| 43 | +- `includes/compat.h` — Cross-platform compatibility macros. |
| 44 | +- `includes/valgrind.h`, `includes/callgrind.h` — Valgrind client request headers. |
| 45 | +- `dist/core.c` — Generated single-file C library. Linux gets the full Zig-transpiled implementation, Windows/macOS get stubs from `scripts/stub.c`. |
| 46 | +- `scripts/release.py` — Combines generated C, stubs, and valgrind wrapper into `dist/core.c`. |
| 47 | +- `scripts/stub.c` — Stub implementations for Windows/macOS. Must be updated when adding exported functions. |
| 48 | + |
| 49 | +### IPC protocol |
| 50 | + |
| 51 | +Communication with the CodSpeed runner happens over two named pipes: |
| 52 | +- `/tmp/runner.ctl.fifo` — Commands (hooks -> runner) |
| 53 | +- `/tmp/runner.ack.fifo` — Acknowledgments (runner -> hooks) |
| 54 | + |
| 55 | +Messages use bincode serialization with `[u32 length][payload]` framing. Protocol version: 2. |
| 56 | + |
| 57 | +## Conventions |
| 58 | + |
| 59 | +### Adding a new exported function |
| 60 | + |
| 61 | +1. Implement the logic in the appropriate module. |
| 62 | +2. Add the `pub export fn` wrapper in `src/c.zig`. Return `u8` status codes (0 = success, non-zero = error). |
| 63 | +3. Add the declaration in `includes/core.h`. |
| 64 | +4. Add a stub in `scripts/stub.c`. |
| 65 | +5. Run `just release` to regenerate `dist/core.c`. |
| 66 | + |
| 67 | +### Code style |
| 68 | + |
| 69 | +- Zig code is formatted with `zig fmt`. |
| 70 | +- C/C++ code follows Google style (`.clang-format`), pointer-left alignment. |
| 71 | +- Pre-commit hooks enforce formatting and build checks. |
| 72 | +- Error handling at FFI boundary: return `u8` (0 = ok, 1 = error). Never panic in release builds (`std.debug.no_panic`). |
| 73 | +- Memory: `std.heap.c_allocator` in production, `std.testing.allocator` in tests. |
| 74 | +- Hot paths (FIFO read/write) use pre-allocated buffers to avoid allocations. |
| 75 | + |
| 76 | +### Testing |
| 77 | + |
| 78 | +- Tests live alongside the code in each `.zig` file. |
| 79 | +- `src/root.zig` imports all modules to run all tests. |
| 80 | +- `build.zig` compiles a test fixture shared library (`libtest_fixture.so`) from `src/environment/linked_libraries/testdata/test_lib.c` and links it into the test binary. ElfView tests use `dl_iterate_phdr` to find it at runtime — no file parsing, same code path as production. |
| 81 | +- CI tests across multiple platforms (Linux x86/ARM, macOS, Windows), compiler versions (GCC 9-15, Clang 13-19), and cross-compilation targets. |
| 82 | + |
| 83 | +### Commit messages |
| 84 | + |
| 85 | +Follow conventional commits. Reference Linear issues when applicable (inferred from branch name). |
0 commit comments