From c2cd6f09eb181469caba5c847d54db3f6c042eee Mon Sep 17 00:00:00 2001 From: Dario Lipicar Date: Mon, 8 Jun 2026 12:22:30 -0300 Subject: [PATCH] docs: LIDL-based dependency consumption + dependency_overrides (#65) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: document LIDL-based dependency consumption + dependency_overrides Tutorial-sync for "concrete dependencies via LIDL": - Developer guide §9.2: explain that each module publishes a cheap LIDL interface contract (packages..lidl) and that consuming a dependency generates modules(). from that LIDL WITHOUT building the dependency's plugin — only the standalone-app run (#run) bundles/builds deps. Notes the cross-language pipeline (Rust -> LIDL -> C++) and the transitional fallback for deps that don't yet expose a `lidl` output. - Document the new `dependency_overrides` metadata field (§9.2 + field table). - Composing Modules tutorial: correct the prose that said the builder "fetches calc_module's headers" — it now reads calc_module's published LIDL contract and does not build calc_module's plugin at the aggregator build step. Depends on logos-cpp-sdk#77, logos-plugin-qt#9, logos-module-builder#110 (the described behavior ships with those). Co-Authored-By: Claude Opus 4.7 (1M context) * address review: regenerate composing tutorial md; reconcile §8.2/§9.2 - Regenerate outputs/tutorial-composing-modules.md so the committed markdown matches the updated YAML prose (it had stale "fetch headers" / "exported interface" wording). Verified identical to `doctest generate`. - Developer guide §9.2: add a note tying the LIDL-contract dependency wrapper generation to §8.2 — it's the same logos-cpp-generator driven by the dep's LIDL/.h contract (like interface_dependencies) rather than inspecting a compiled plugin (the manual/standalone path), so the two sections no longer read as conflicting mechanisms. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- logos-developer-guide.md | 22 ++++++++++++++++++++++ outputs/tutorial-composing-modules.md | 4 ++-- tests/tutorial-composing-modules.test.yaml | 4 ++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/logos-developer-guide.md b/logos-developer-guide.md index d819374..bffc691 100644 --- a/logos-developer-guide.md +++ b/logos-developer-guide.md @@ -233,6 +233,7 @@ The full set of available fields: | `view` | Yes (`ui_qml`) | -- | Relative path to the QML entry file (e.g. `Main.qml`). Required for `ui_qml` modules. | | `dependencies` | No | `[]` | Other Logos module names this depends on. Each entry must match the `name` field in that dependency's `metadata.json`. | | `interface_dependencies` | No | `[]` | Header *interfaces* this module binds at runtime, decoupled from any concrete module. Each entry is `{ name, file, impl_class?, input? }` — see [Dependency interfaces](#dependency-interfaces) and the [tutorial](tutorial-interface-dependencies.md). | +| `dependency_overrides` | No | `{}` | Per-dependency LIDL-contract source overrides, keyed by dependency name → `{ file, input?, impl_class? }`. Forces where a dependency's interface is read from; normally auto-resolved from the dep's `lidl` output. See [§9.2 Module Dependencies](#92-module-dependencies). | | `include` | No | `[]` | Additional files (e.g. shared libraries like `libwaku.so`, `libwaku.dylib`) to bundle alongside the plugin in the output. | | `nix.packages.build` | No | `[]` | Nix packages for build time | | `nix.packages.runtime` | No | `[]` | Nix packages for runtime | @@ -1103,6 +1104,27 @@ Each entry in `dependencies` must match the `name` field in that module's own `m When your module is installed via `lgpm`, its dependencies are automatically resolved and installed first. When loaded via `logos-basecamp`, core module dependencies are loaded before your module. +#### How dependencies are consumed — the LIDL contract + +Each module publishes a small, language-neutral **LIDL interface contract** as a cheap flake output (`packages..lidl`), generated from its source with no plugin compile. When you depend on a module, the builder generates the typed `modules().` wrapper **from that published LIDL** — so building (or packaging) your module **does not build the dependency module**. The only step that still builds and bundles dependency plugins is the standalone-app run (`nix run` / `#run`), which has to, because it loads them. + +This is the same `logos-cpp-generator` from [§8.2](#82-the-c-sdk-code-generator), just driven by the dependency's LIDL contract — the same kind of `.lidl`/`.h` contract `interface_dependencies` uses — instead of inspecting a compiled plugin. Inspecting a compiled plugin (as §8.2 describes) is the manual/standalone path; for declared module dependencies the builder uses the contract path, which is why no dependency plugin is built. + +Because the contract is LIDL, the dependency's implementation language doesn't matter: the pipeline is `source → LIDL → C++` for a C++ module today, and `Rust → LIDL → C++` for a Rust module tomorrow — the same generated `modules().` wrapper either way. + +> **Transitional fallback.** A dependency built by an older `logos-module-builder` won't expose a `lidl` output yet; for those the builder falls back to the previous behavior (build the dependency and copy its generated headers), so mixed dependency graphs keep working. + +To force a specific contract source for a dependency — a committed `.lidl`, a header in another repo, etc. — add a `dependency_overrides` entry keyed by the dependency name: + +```json +"dependencies": ["calc_module"], +"dependency_overrides": { + "calc_module": { "file": "interfaces/calc.lidl" } +} +``` + +Each override is `{ file, input?, impl_class? }`: `file` is the `.lidl`/`.h` path (relative to this repo, or to the flake `input` if given), and `impl_class` is required for a `.h` file. Most modules never need this — auto-resolution from the dependency's `lidl` output is the default. + ### 9.3 Exposing Prometheus Metrics Infra operators monitor logos.dev nodes with Prometheus. The diff --git a/outputs/tutorial-composing-modules.md b/outputs/tutorial-composing-modules.md index de9c000..2084b3b 100644 --- a/outputs/tutorial-composing-modules.md +++ b/outputs/tutorial-composing-modules.md @@ -58,7 +58,7 @@ Three small config files declare the module, its dependency on `calc_module`, an ### 2.1 `metadata.json` — declare the dependency -The one field that matters here is `dependencies`: listing `calc_module` tells the builder to fetch `calc_module`'s headers and event metadata and generate a typed wrapper for it. The dependency name **must match** `calc_module`'s own `metadata.json` `name`. +The one field that matters here is `dependencies`: listing `calc_module` tells the builder to read `calc_module`'s published LIDL interface contract and generate a typed wrapper for it — without building `calc_module` itself. The dependency name **must match** `calc_module`'s own `metadata.json` `name`. ```json { @@ -427,7 +427,7 @@ nix flake update --override-input calc_module path:../logos-calc-module git add flake.lock ``` -Now build the full package. For a universal module with a dependency, this is where `logos-cpp-generator` runs over both `src/calc_aggregator_impl.h` and `calc_module`'s exported interface, emitting the plugin glue **and** the typed `modules().calc_module` wrapper under `generated_code/`: +Now build the full package. For a universal module with a dependency, this is where `logos-cpp-generator` runs over both `src/calc_aggregator_impl.h` and `calc_module`'s published LIDL contract, emitting the plugin glue **and** the typed `modules().calc_module` wrapper under `generated_code/` — note `calc_module`'s own plugin is not built here, only its LIDL is read: ```bash nix build diff --git a/tests/tutorial-composing-modules.test.yaml b/tests/tutorial-composing-modules.test.yaml index d45d783..bbb2707 100644 --- a/tests/tutorial-composing-modules.test.yaml +++ b/tests/tutorial-composing-modules.test.yaml @@ -60,7 +60,7 @@ sections: steps: - title: "`metadata.json` — declare the dependency" text: | - The one field that matters here is `dependencies`: listing `calc_module` tells the builder to fetch `calc_module`'s headers and event metadata and generate a typed wrapper for it. The dependency name **must match** `calc_module`'s own `metadata.json` `name`. + The one field that matters here is `dependencies`: listing `calc_module` tells the builder to read `calc_module`'s published LIDL interface contract and generate a typed wrapper for it — without building `calc_module` itself. The dependency name **must match** `calc_module`'s own `metadata.json` `name`. file: path: metadata.json language: json @@ -425,7 +425,7 @@ sections: nix flake update --override-input calc_module path:../logos-calc-module - run: "git add flake.lock" post_text: | - Now build the full package. For a universal module with a dependency, this is where `logos-cpp-generator` runs over both `src/calc_aggregator_impl.h` and `calc_module`'s exported interface, emitting the plugin glue **and** the typed `modules().calc_module` wrapper under `generated_code/`: + Now build the full package. For a universal module with a dependency, this is where `logos-cpp-generator` runs over both `src/calc_aggregator_impl.h` and `calc_module`'s published LIDL contract, emitting the plugin glue **and** the typed `modules().calc_module` wrapper under `generated_code/` — note `calc_module`'s own plugin is not built here, only its LIDL is read: - run: "nix build" - title: "Check the output"