Skip to content

feat(windows): publish an x86_64-windows target - #66

Open
dlipicar wants to merge 2 commits into
feat/bump-builder-typed-recordsfrom
feat/windows-target
Open

feat(windows): publish an x86_64-windows target#66
dlipicar wants to merge 2 commits into
feat/bump-builder-typed-recordsfrom
feat/windows-target

Conversation

@dlipicar

@dlipicar dlipicar commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Stacked on #65 (retarget to master once that merges). No longer blocked: logos-co/logos-module-builder#200 is merged and the pin here now points at builder master (d256a42).

chat_ui cannot cross-build without this. A consumer resolves a dependency's compiled headers through packages.<system>, so with no Windows entry here, chat_ui's own cross build has nothing to read. That is how this surfaced — as fatal error: chat_module_api.h: No such file or directory, three layers from its cause. logos-co/logos-module-builder#199 turns it into a named error instead of a silent fallback to this source tree.

The builder already understands x86_64-windows as a cross pseudo-system, so this is packages only. apps and devShells both do import nixpkgs { inherit system; }, which for that key is a native Windows instantiation and dies in cc-wrapper — and neither a dev shell nor the codegen runner means anything on a cross target.

Two things this needed beyond the fold

The delivery_module-lgx re-export is now conditional. The pinned delivery_module publishes only the native systems, and asking it for a target it does not build would fail the whole attrset over a convenience output. chat_module itself is unaffected: its delivery dependency resolves through the local .lidl in dependency_overrides, never through the dep's packages.

CMakeLists.txt loses its hand-rolled Rust-staticlib link block. Finding the archive, re-mentioning logos-protocol after it, and adding the native libraries Rust's std leaves undefined are all done by logos_module() now — and the local copy ran in addition to it, so the archive, the protocol archive and a set of natives each landed on the link line twice:

… libchat_module.a liblogos_protocol.a -lws2_32 -lbcrypt -lntdll -luserenv -lsynchronization -ladvapi32
  libchat_module.a liblogos_protocol.a -lpthread -ldl

Harmless while both copies agreed. They stopped agreeing on Windows, where the builder names the Win32 set mingw actually needs while this copy still said pthread dldl does not exist there and pthread is not on the sysroot search path.

Verification

packages.x86_64-windows.default builds to a 40 MB PE32+ x86-64 plugin exporting qt_plugin_instance / qt_plugin_query_metadata_v2, with aws-lc-rs-1.17.0, rustls-0.23.41, de-mls-4.0.0, hashgraph-like-consensus-0.6.0 and libchat really linked in, and its DLL closure (including libwinpthread-1.dll) staged alongside.

Exercised end to end on real Windows: installed into Basecamp alongside chat_ui and delivery_module, the Chat app loads and sends and receives messages over the network.

🤖 Generated with Claude Code


Update — CI for the target

Added .github/workflows/windows.yml: one with: block calling
logos-co/logos-windows-ci@v1.
A target with no CI is half a change — nothing currently notices when
packages.x86_64-windows stops building or stops being loadable.

The harness cross-builds on an ordinary Linux runner (nix does not run on
Windows) and gates the result. targets: default lgx-portabledefault is
the plugin DLL plus the libraries bundled beside it, which is what the
import-closure gate reads; lgx-portable is the packaged form that is actually
distributed (lgx links against the Nix store).

What it covers — the three things that have actually broken here:

What it does not cover, stated rather than implied. chat_module is a
plugin: its Windows artifacts are a DLL and a .lgx, and neither can be
executed. So this run is compile-only on the smoke axis, and the harness
reports that as a coverage gap rather than as a pass. Running the module needs
a host, which is not a target of this flake; that coverage belongs downstream,
next to a runtime.

logos-windows-ci is new and has not yet run on a GitHub runner anywhere, so
treat the first CI run here as its acceptance test.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown

Doc-test report

Headless chat_module instances built against this commit, driven through the 1:1 round-trip and the three-instance group conversation, rendered alongside the commands actually run and their output (updated each run, commit 43a1b80):

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

@dlipicar
dlipicar force-pushed the feat/windows-target branch from 98fa482 to a0a50be Compare August 14, 2026 22:08
@dlipicar
dlipicar marked this pull request as ready for review August 14, 2026 22:08
Copilot AI lite review requested due to automatic review settings August 14, 2026 22:08

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.

@dlipicar
dlipicar force-pushed the feat/bump-builder-typed-records branch from 29b8b80 to 451652e Compare August 23, 2026 01:28
dlipicar and others added 2 commits August 22, 2026 22:28
chat_ui cannot cross-build without this: a consumer resolves a
dependency's compiled headers through `packages.<system>`, so with no
Windows entry here chat_ui's own cross build has nothing to read.
(logos-module-builder#199 turns that into a named error instead of a
silent fallback to this source tree, which is how it first surfaced —
as `fatal error: chat_module_api.h: No such file or directory`.)

The builder already understands `x86_64-windows` as a cross
pseudo-system, so this is `packages` only. `apps` and `devShells` both do
`import nixpkgs { inherit system; }`, which for that key is a NATIVE
Windows instantiation and dies in cc-wrapper — and neither a dev shell
nor the codegen runner means anything on a cross target.

Two things this needed beyond the fold:

- The `delivery_module-lgx` re-export is now conditional. The pinned
  delivery_module publishes only the native systems, and asking it for a
  target it does not build would fail the whole attrset over a
  convenience output. chat_module itself is unaffected — its delivery
  dependency resolves through the local `.lidl` in dependency_overrides,
  never through the dep's packages.

- CMakeLists.txt loses its hand-rolled Rust-staticlib link block. Finding
  the archive, re-mentioning logos-protocol after it, and adding the
  native libraries Rust's `std` leaves undefined are all done by
  logos_module() now, and the local copy ran in ADDITION to it — the
  archive, the protocol archive and a set of natives each landed on the
  link line twice. Invisible while both agreed; they stopped agreeing on
  Windows, where the builder names the Win32 set mingw needs while this
  copy still said `pthread dl`.

Builder re-pinned to the rev carrying the Rust cross support
(logos-module-builder#197).

Verified: a 40MB PE32+ x86-64 plugin exporting qt_plugin_instance /
qt_plugin_query_metadata_v2, with aws-lc-rs, rustls, de-mls and libchat
really linked in, and its DLL closure staged alongside.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A target with no CI is half a change: the previous commit publishes
`packages.x86_64-windows`, and nothing yet notices when it stops building or
stops being loadable.

One file, calling logos-co/logos-windows-ci@v1. Everything else -- the Nix
install and cache, the target-existence guard, the cold-cache refusal, the
PE-format and import-closure gates, the .lgx payload gate, the artifact
round-trip check -- lives once in that repo.

WHAT IT COVERS
  * the Rust staticlib crossing to mingw at all. It needs
    ws2_32/bcrypt/ntdll/userenv/synchronization, which LogosModule.cmake's
    APPLE/else split used to deny it by putting `pthread dl` on the Windows
    line (logos-module-builder#197);
  * the import closure of the built plugin. `bcryptprimitives.dll` was absent
    from the bundler's system-DLL allowlist and the symptom was a module that
    loaded nowhere (nix-bundle-lgx#12);
  * the `.lgx` carrying a real `variants/windows-x86_64` payload whose own
    imports ship with it -- what an installed module actually resolves against.

WHAT IT DOES NOT COVER, DELIBERATELY STATED
  chat_module is a plugin. Its Windows artifacts are a DLL and a `.lgx`, and
  neither can be executed, so this run is COMPILE-ONLY on the smoke axis and
  the harness reports that as a coverage gap rather than as a pass. Running the
  module needs a host, which is not a target of this flake. That coverage
  belongs downstream, next to a runtime.

`lgx-portable` rather than `lgx`: the portable variant is the one that is
actually distributed, and `lgx` links against the Nix store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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