`logos-cpp-generator` bridges pure C++ module implementations to the Logos runtime's Qt plugin system. Module authors write standard C++ and the generator produces all Qt boilerplate automatically.
Universal modules are **header-first cdylibs**: the generator derives a LIDL contract from your impl header, then emits a Qt-free cdylib (exporting the common module-impl C ABI) wrapped by a uniform Qt-plugin glue that `logos_host` loads unchanged. Your module's own translation units stay Qt-free — Qt appears only in the generated glue.
This is how universal modules are built. You write only the impl class; `logos-module-builder` runs every step below for you in `preConfigure` (see [In flake.nix](#in-flakenix)).
All land in `generated_code/`. Don't edit them and don't list them in `CMakeLists.txt` — `LogosModule.cmake` globs them automatically (see [In CMakeLists.txt](#in-cmakeliststxt)).
**`<name>.lidl`** — the interface contract derived from your impl header. Doubles as the published events sidecar that dependents' typed-event codegen consumes.
**`<name>_cdylib_glue.h` / `<name>_cdylib_glue.cpp`** — the uniform Qt-plugin glue. A `QObject` subclass with `Q_PLUGIN_METADATA` + `Q_INTERFACES` and a `LogosProviderObject` that marshals method calls to JSON and forwards them to the cdylib's module-impl C ABI (`dispatch` / `getMethods` / `set_context` / emit callback / `accept_token`). The glue is identical regardless of the module's source language — it only knows the C ABI.
**`<name>_module_impl.cpp`** — the Qt-free C-ABI export wrapper. Implements the common module-impl C ABI (`logos_module_impl.h`) around your hand-written impl class, plus typed event emitters. This translation unit links no Qt; it is what makes a universal module a cdylib.
`LogosMap` and `LogosList` (from `<logos_json.h>`) are `nlohmann::json` aliases for returning structured data without Qt. The generator sets a `jsonReturn` flag on these methods so the dispatch layer carries the JSON through faithfully.
LIDL is a lightweight Interface Definition Language. The universal pipeline derives a `.lidl` from your header automatically (step 1 above), but you can also hand-write one to define the interface before the implementation:
A hand-written `.lidl` feeds steps 2 & 3 directly (this is the `cdylib` interface; the `universal` interface just derives the `.lidl` from your header first). Both routes produce identical generated output.
- **Generated files not found by CMake**: You do *not* list `generated_code/` files in `SOURCES` — `LogosModule.cmake` globs them. Just make sure `generated_code` is in `INCLUDE_DIRS`.
List only your own sources. `LogosModule.cmake` globs `generated_code/*.cpp` and `*.h` automatically (excluding `logos_sdk`/`*_api`), so the generated glue is picked up without being named: