Files
video-setup/conventions.md
mikael-lovqvists-claude-agent 1066f793e2 docs: sync docs with code; fix Makefile modules target
Makefile:
- Add reconciler and ingest to the `modules` target; they were only built
  as side-effects of `make node`, making `make modules` incomplete

planning.md:
- Add 4 missing CLI drivers: discovery_cli, config_cli, protocol_cli,
  query_cli (all existed in code and dev/cli/Makefile but were absent)
- Add header-only utilities table: stream_stats.h, v4l2_fmt.h

README.md:
- Add transport_cli, discovery_cli, config_cli, protocol_cli, query_cli
  to CLI tools list

conventions.md:
- Add ERR_NOT_FOUND to Error_Code enum example
- Replace placeholder Invalid_Error_Detail with actual fields
  (config_line, message) that have been in use since config module
- Add missing error macros: APP_INVALID_ERROR, APP_INVALID_ERROR_MSG,
  APP_NOT_FOUND_ERROR
- Update directory structure: node/ description (was "later"), add web/
  and tools/ entries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 21:55:43 +00:00

184 lines
5.5 KiB
Markdown

# Conventions and Preferences
## Language
- **C11** throughout (`-std=c11`)
- **`_GNU_SOURCE`** defined via `-D_GNU_SOURCE` in all Makefiles — enables the full GNU/Linux feature set (POSIX 2008, BSD, GNU and Linux-specific extensions); do not define this in source files
- **LTO enabled** via `-flto` in all Makefiles — the compiler handles inlining across translation units at link time; do not use `static` on functions solely to enable inlining
- Target platform: Linux (V4L2, epoll, etc. are Linux-specific)
---
## Naming
| Kind | Convention | Example |
|---|---|---|
| Structs | `Title_Snek_Case` | `struct App_Error`, `struct Frame_Header` |
| Enums (type) | `Title_Snek_Case` | `enum Error_Code` |
| Enum values | `CAPITAL_SNEK_CASE` | `ERR_NONE`, `ERR_SYSCALL` |
| Functions | `lower_snek_case` | `v4l2_ctrl_open()`, `app_error_print()` |
| Local variables | `lower_snek_case` | `frame_count`, `device_fd` |
| Constants (`#define`, `const`) | `CAPITAL_SNEK_CASE` | `MAX_FRAME_SIZE` |
| Module-level singletons | `lower_snek_case` | (treated as functions) |
Identifiers are prefixed with their module name where disambiguation is needed (e.g. `v4l2_ctrl_`, `media_ctrl_`, `transport_`).
---
## Types
### No typedefs for structs
Always use the `struct` keyword at the call site. This makes composite types unambiguous without inspecting declarations.
```c
/* correct */
struct App_Error err = app_error_ok();
void process(struct Frame_Header *header);
/* wrong */
typedef struct { ... } App_Error;
```
### typedefs are acceptable for
- Enums: `typedef enum Error_Code { ... } Error_Code;` — allows using the name without `enum` keyword
- Scalar aliases where the underlying type is genuinely irrelevant to the caller (e.g. `typedef uint32_t Frame_Id;`)
---
## Formatting
- **Indentation**: tabs (display width 4)
- **Braces**: always use block braces, including single-statement bodies
```c
/* correct */
if (err.code != ERR_NONE) {
return err;
}
/* wrong */
if (err.code != ERR_NONE)
return err;
```
- **Quotes**: double quotes for string literals (C standard)
---
## Error Handling
Errors are returned as `struct App_Error` values. Functions that can fail return `struct App_Error` directly, or take an out-parameter for the result alongside it.
### Structure
```c
/* modules/common/error.h */
typedef enum Error_Code {
ERR_NONE = 0,
ERR_SYSCALL = 1, /* errno is meaningful */
ERR_INVALID = 2,
ERR_NOT_FOUND = 3,
} Error_Code;
struct Syscall_Error_Detail {
int err_no;
};
struct Invalid_Error_Detail {
int config_line; /* source line number, or 0 if not applicable */
const char *message; /* static string describing what was wrong */
};
struct App_Error {
Error_Code code;
const char *file; /* __FILE__ — future: replaced by generated location code */
int line; /* __LINE__ — future: replaced by generated location code */
union {
struct Syscall_Error_Detail syscall;
struct Invalid_Error_Detail invalid;
} detail;
};
```
### Macros
```c
#define APP_OK \
((struct App_Error){ .code = ERR_NONE })
#define APP_IS_OK(e) \
((e).code == ERR_NONE)
#define APP_SYSCALL_ERROR() \
/* sets ERR_SYSCALL + captures errno */
#define APP_INVALID_ERROR() \
/* sets ERR_INVALID, no message */
#define APP_INVALID_ERROR_MSG(cfg_line, msg) \
/* sets ERR_INVALID with config_line and message */
#define APP_NOT_FOUND_ERROR() \
/* sets ERR_NOT_FOUND */
```
### Presentation
Each error kind is handled in `app_error_print()`, which writes a human-readable description to stderr. A JSON writer (`app_error_write_json()`) will be added later and will use the same structured fields.
### Future upgrade
When the custom preprocessor is available, `__FILE__` and `__LINE__` will be replaced by a generated numeric location code that uniquely identifies the error site in the project. JSON consumers will see the same struct shape either way.
---
## Directory Structure
```
video-setup/
src/ - all C source files
modules/ - translation units; each has a .c and a Makefile
common/ - shared types (error, base definitions); no external dependencies
<module>/
node/ - video node binary (source + display sink roles)
include/ - public headers (.h files)
dev/ - development aids; not part of the final deliverable
cli/ - exploratory CLI drivers, one per module
web/ - development web UI (Node.js/Express)
experiments/ - freeform experiments
tools/ - build-time code generators (e.g. gen_font_atlas)
tests/ - automated tests (later)
Makefile - top-level build
```
Source files live in `src/`. Public headers live in `include/`. CLI drivers and experiments live in `dev/`. Nothing in `dev/` is a dependency of anything in `src/`.
---
## Module Structure
Each module has its source under `src/modules/<name>/` and its public header under `include/`:
```
src/modules/<name>/
<name>.c - implementation
Makefile - builds a static object
include/
<name>.h - public API; minimal includes, no implementation details
```
The corresponding CLI driver lives at `dev/cli/<name>_cli.c`.
---
## Build
- **GNU make** with tabs for recipe indentation
- Each module builds to a static object (`.o`)
- CLI drivers link the module object(s) they need
- No CDN or vendored sources; dependencies are system libraries (libc, Linux kernel headers)