mirror of
https://github.com/logos-co/logos-module-builder.git
synced 2026-08-27 10:11:10 +00:00
The source-level checks that just landed (logos-cpp-sdk#144,
logos-rust-sdk#46) validate each GENERATOR against the protocol header.
Three things they structurally cannot see, all of which end as the same
"undefined symbol" at dlopen:
* THE CARRIER. lib/mkLogosModule.nix:383 derives protocolVersion by
regexing the protocol header and :483 passes it through
lib.optionalString (protocolVersion != null). A regex miss does not
make the flag wrong, it makes it VANISH — logos-lidl-gen then defaults
to "0.1.0" and every Rust module in the workspace regenerates with only
the seven founding exports. Each backend's own check still passes,
because each passes the version correctly.
* EMITTED BUT NOT COMPILED IN — cfg-gated out, gc-sectioned, lost to link
order. Present in the generator's output, absent from the artifact.
* A LANGUAGE BACKEND NOBODY WIRED A CHECK INTO (the Nim path in #202).
So build a module per backend and read its symbol table:
(1) every export logos-protocol DECLARES is DEFINED in the plugin;
(2) NO logos_module_* symbol is UNDEFINED — literally "will this dlopen".
Both fire independently on the same real defect, which is why both are here.
The part that makes this worth its build time: nm sees an undefined symbol
on BOTH platforms, while the runtime failure is Linux-only (nixpkgs hardens
with -Wl,-z,now; macOS links plugins -undefined dynamic_lookup and never
binds). So a defect that is fatal in CI and invisible on a developer's Mac
becomes catchable on that Mac.
Proven non-redundant, not merely proven to fail. Driving protocolVersion to
null leaves all seven existing checks GREEN — six of them produce
byte-identical store paths, never reaching the affected code, and the
seventh, rust-native-dep, rebuilds the very same broken plugin and still
passes, because its only assertion is that the output directory exists.
This check goes red naming the three missing exports.
Anti-vacuity is the bulk of the file, since a check that cannot fail is
worse than none: the plugin is located by a glob that must match EXACTLY
one; zero defined logos_module_* symbols is a hard failure printing the raw
table; the undefined side cannot self-check (empty IS the pass) so the raw
table is asserted non-empty first; and grep's "no match" is distinguished
from a real error. Each was demonstrated to fire.
Also lists rust-native-dep in CI. It was excluded over a protocol pin that
has since moved, and this step already compiles the same fixture.
The logos-protocol pin moves 0d2a3c0 -> 480f40f because
packages.<sys>.module-impl-abi did not exist before it. flake.nix throws a
named error if a future pin ever predates that output.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
79 lines
3.6 KiB
YAML
79 lines
3.6 KiB
YAML
name: CI
|
|
|
|
# pull_request is unfiltered: stacked PRs (based on other feature branches)
|
|
# must run CI too.
|
|
on:
|
|
push:
|
|
branches: [master]
|
|
pull_request:
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
test:
|
|
# ATTIC_TOKEN_PUBLIC only exists in the public-cache environment; master
|
|
# jobs must opt into it to publish to the public cache.
|
|
environment: ${{ github.ref == 'refs/heads/master' && 'public-cache' || '' }}
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: logos-co/setup-nix-cache-action@v1
|
|
with:
|
|
attic-token-ci: ${{ secrets.ATTIC_TOKEN_CI }}
|
|
attic-token-public: ${{ secrets.ATTIC_TOKEN_PUBLIC }}
|
|
extra-nix-config: |
|
|
experimental-features = nix-command flakes
|
|
|
|
- name: Run unit tests
|
|
run: nix build '.#checks.x86_64-linux.default'
|
|
|
|
- name: Run QML integration tests
|
|
run: nix build '.#checks.x86_64-linux.qml-integration'
|
|
|
|
- name: Run static external library tests
|
|
run: nix build '.#checks.x86_64-linux.static-extlib'
|
|
|
|
- name: Run test-framework integration tests
|
|
run: nix build '.#checks.x86_64-linux.test-framework-integration'
|
|
|
|
# Hermetic (empty scaffold roots, no Qt, no store deps) and it existed
|
|
# without ever being listed here — the same gap that left the view
|
|
# templates with no CI coverage at all.
|
|
- name: Check which Qt host runtime logos_module() links
|
|
run: nix build '.#checks.x86_64-linux.qt-host-repoint'
|
|
|
|
# The view plugin interfaces are declared twice — module side in
|
|
# logos-view-module's templates, host side in logos-view-module-runtime —
|
|
# and bound only by an IID string, where a mismatch is silent. This repo
|
|
# is the only one that can see both, so the comparison runs here.
|
|
#
|
|
# It depends on packages.<sys>.logos-view-templates from the pinned
|
|
# logos-view-module (the templates moved there out of logos-plugin-qt).
|
|
# If that pin ever predates the output, this step EVAL-fails rather than
|
|
# reporting a divergence; the error message from
|
|
# tests/test-view-interface-abi.nix names the input to bump.
|
|
- name: Check view interface ABI agreement
|
|
run: nix build '.#checks.x86_64-linux.view-interface-abi'
|
|
|
|
# Ground truth for the module-impl C ABI: builds a module per language
|
|
# backend and reads the plugin's symbol table. It has to run HERE, on
|
|
# Linux, for the reason the test file explains — but it is the Darwin
|
|
# runs that make it worth having, because the failure it catches is
|
|
# invisible at runtime on macOS and fatal at dlopen() on Linux.
|
|
#
|
|
# Note this step is what makes every check in this file discovered ON
|
|
# PURPOSE rather than by accident: `checks` is never evaluated as a whole
|
|
# here, so anything not named on a line like this one simply never runs.
|
|
- name: Check module-impl C ABI against built plugins
|
|
run: nix build '.#checks.x86_64-linux.module-impl-abi-nm'
|
|
|
|
# Previously unlisted, on the grounds that this and
|
|
# test-framework-integration were both red because logos-qt-host would not
|
|
# compile against the pinned logos-protocol, whose TokenManager lacked
|
|
# forIdentity/isolateIdentity. That no longer holds — the pin declares
|
|
# both (cpp/token_manager.h), test-framework-integration is listed above,
|
|
# and the step above already compiles this very fixture, so listing it
|
|
# costs nothing and the assertion it adds (the module BUILDS) is real.
|
|
- name: Check Rust module with a native build dependency
|
|
run: nix build '.#checks.x86_64-linux.rust-native-dep'
|