Skip to content

fix(cross): fail loudly when a dep publishes nothing for the target system - #199

Merged
dlipicar merged 2 commits into
masterfrom
fix/cross-dep-resolution
Aug 14, 2026
Merged

fix(cross): fail loudly when a dep publishes nothing for the target system#199
dlipicar merged 2 commits into
masterfrom
fix/cross-dep-resolution

Conversation

@dlipicar

@dlipicar dlipicar commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Three fixes, all the same shape, all found while chasing why chat_ui's Windows build died on fatal error: chat_module_api.h: No such file or directory.

The silent fallback

Resolving a transitional header-copy dependency did input.packages.${system} or null, and on null fell back to input itself. For a flake input that is the dependency's source tree — so the plugin build gets a header root with no generated headers in it, and fails far away inside a generated TU. Or, worse, succeeds against whatever stale headers happen to be checked in.

chat_module 0.2.2 publishes only the four native systems, so every x86_64-windows consumer silently resolved its headers to the chat_module checkout. The symptom pointed at an include path; the cause was three layers up.

A flake that publishes packages but nothing for this system is now an error:

error: logos-module-builder: dependency 'chat_module' publishes no packages for x86_64-windows.

It exposes: aarch64-darwin, aarch64-linux, x86_64-darwin, x86_64-linux

'chat_module' is taking the transitional header-copy path (it publishes no
`lidl` output), so this build needs its compiled headers for x86_64-windows
and there are none.

Fix: give 'chat_module' a x86_64-windows target and re-pin it. ...

The fallback survives only for a genuinely bare-derivation input (no packages attr at all), which is the pre-refactor shape it exists for.

The same hole in collectAllModuleDeps

One level out, collectAllModuleDeps fell through to input when a dependency published no usable package for the target — putting the dep's source tree where an LGX package belongs. mkStandaloneApp then ships a directory of .cpp files in place of a module, and it only shows up at runtime as a module that never loads.

The two autoBundleLgx throws immediately above already guard the adjacent case, with the comment "a silent fallback would cause mkStandaloneApp to silently omit the dependency at runtime". This closes the remaining hole in the same function.

One resolver, not two

The header-copy logic was copy-pasted into mkLogosModule.nix (core modules) and buildCppPlugin.nix (ui_qml view modules). It now lives once in common.nix and both call it.

This is not tidying. chat_ui is a view module, so the first version of this fix — applied only to mkLogosModule.nix — left the exact case that motivated it untouched, and the verification run caught it still resolving happily. Two copies of a resolver is how that happens.

Single-sourced Windows build platform

"x86_64-linux" was repeated as a literal in two places in common.nix; it now comes from logos-nix's windowsBuildSystems, which is where the decision and its reasoning already live.

Pinning it rather than using the evaluating system is deliberate, and worth stating since it can read as a limitation: it keeps packages.x86_64-windows.* one well-defined derivation no matter who evaluates it, so a Darwin and a Linux checkout agree and share a cache. A Darwin dev realises it through a Linux remote builder — which is what nixpkgs' own mingw cross assumes too. Widening it is now a one-line change in logos-nix rather than an edit here.

Verification

Before/after evaluation with both trees exported the same way (git archive), so the only variable is the change:

subject before after
chat_ui apps.x86_64-linux (the collectAllModuleDeps path) s0mxf9yz… s0mxf9yz… — byte-identical
chat_ui packages.x86_64-linux 4ip9ygq… 4ip9ygq… — byte-identical
capability_module x86_64-linux / x86_64-windows drv only LOGOS_MODULE_BUILDER_ROOT differs
chat_ui packages.x86_64-windows resolved to the source tree throws the message above

chat_ui's apps output is the one that matters for the second fix — it is a real UI module with dependencies, and it exercises collectAllModuleDeps end to end.

For capability_module I diffed the derivations rather than just the hashes: inputDrvs, inputSrcs and every other env key are identical, and the sole delta is the builder's own source path, which necessarily moves whenever any file in this repo changes.

Follow-up

chat_module gains its x86_64-windows target in logos-co/logos-chat-module#65 and its follow-on, which is what makes the first error above stop firing for chat_ui.

🤖 Generated with Claude Code

…ystem

Two fixes, both found while chasing why chat_ui's Windows build died on
`fatal error: chat_module_api.h: No such file or directory`.

**The silent fallback.** Resolving a transitional header-copy dependency
did `input.packages.${system} or null`, and on null fell back to `input`
itself. For a flake input that is the dependency's SOURCE TREE, so the
plugin build gets a header root with no generated headers in it and fails
far away inside a generated TU — or, worse, succeeds against whatever
stale headers happen to be checked in. chat_module v0.2.2 publishes only
the four native systems, so every x86_64-windows consumer of it resolved
its headers to the chat_module checkout.

A flake that publishes `packages` but nothing for this system is now an
error naming the dep, the system, and what it does publish. The fallback
survives only for a genuinely bare-derivation input (no `packages` attr
at all), which is the pre-refactor shape it exists for.

**One resolver, not two.** That logic was copy-pasted into
mkLogosModule.nix (core modules) and buildCppPlugin.nix (ui_qml view
modules). It now lives once in common.nix and both call it. This is not
tidying: chat_ui is a view module, so a fix applied only to
mkLogosModule.nix left the case that motivated it untouched — which is
exactly what happened on the first attempt here.

Also single-sources the Windows build platform from
logos-nix's `windowsBuildSystems` instead of repeating "x86_64-linux" as
a literal in two places. Pinning it (rather than using the evaluating
system) is deliberate: it keeps packages.x86_64-windows.* one
well-defined derivation whoever evaluates it, so a Darwin and a Linux
checkout agree and share a cache. Widening it is now a change in
logos-nix, not here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 14, 2026 17:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Same silent-fallback shape as the header-copy resolver, one level out:
when a dependency published no usable package for the target system,
`collectAllModuleDeps` fell through to `input` -- putting the dep's
SOURCE TREE where an LGX package belongs. mkStandaloneApp then ships a
directory of .cpp files in place of a module, and the failure only shows
up at runtime as a module that never loads.

The two autoBundleLgx throws right above it already guard the adjacent
case ("a silent fallback would cause mkStandaloneApp to silently omit
the dependency at runtime"), so this closes the remaining hole in the
same function.

A bare-derivation input (no `packages` attr at all) still takes the
fallback -- that is the shape it exists for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown

📊 Doc-test reports

The four ways to wrap a C library plus the two cross-language composition tours — each scaffolded into real modules, built against this commit, loaded in logoscore, and driven — rendered alongside the commands actually run and their output (updated each run, commit 7f48956):

Pages can take a minute to update after the run finishes.

@dlipicar
dlipicar merged commit ea3b393 into master Aug 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants