Added port consistency checks and wired them into CI and release preparation - #591
Merged
fdesbiens merged 1 commit intoAug 9, 2026
Conversation
fdesbiens
force-pushed
the
feature/port-consistency-checks
branch
2 times, most recently
from
August 9, 2026 14:17
0ddf35a to
ff0b93d
Compare
…aration Three defects reached the repository through the port trees recently, and each of them is mechanically detectable without a cross compiler. Add scripts/check_ports.sh, which looks for exactly those three, and give CI and the release process the same command a contributor can run locally. The generated Cortex-M ports must be reproducible from ports_arch. Fixes were applied to the generated copies instead of the source for eight months, and the next run of the copy scripts would have reverted them. Preprocessor directives must balance. A fix left the Cortex-M85 IAR tx_port.h with one more #endif than #if, so that header could not compile. No port header may carry a statement outside a function body. A fix left a second, headerless copy of a function body in the Cortex-M4 AC6 tx_port.h, which is issue 569. The check tracks brace depth while skipping preprocessor lines, multi-line macro bodies and comments, and reports assignments, dereferences and control statements that land at file scope. Headers under example_build are excluded, since those trees vendor third party SDK code. A fourth section reports, without failing the run, on port families that have no copy script and so cannot be checked for reproducibility. It currently observes that the Cortex-M0 ac5, ac6 and keil ports lack the barriers their gnu and iar siblings have. ports_arch_check now calls the script rather than inlining a copy and diff, so CI and the command line check the same things by the same definition, and the workflow now triggers on pull requests to dev as well as master. Triggering on master alone is why the drift went unseen. prepare_release.sh runs the checks before it branches or rewrites anything, and stops if they fail, with SKIP_PORT_CHECKS=1 as the escape hatch. Each check was verified by reintroducing the defect it exists to catch and confirming that the script fails, then confirming it passes on a clean tree. Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
fdesbiens
force-pushed
the
feature/port-consistency-checks
branch
from
August 9, 2026 14:45
ff0b93d to
0b8458f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
scripts/check_ports.sh, a local and CI check over the port trees, and wires it intoports_arch_checkandprepare_release.sh.Rebased onto
devnow that #589 has merged; stacked on #590. The reproducibility check fails ondevas it stands, by design: that is the drift #590 corrects. Merge #590 first.Why these three checks
Each one exists because a real defect reached the repository through it, and none of the three needs a cross compiler to detect:
ports_archdevchanges 35 files, and would revert #523, #514 and the IAR comment syntax fix.ports/cortex_m85/iar/inc/tx_port.hhas carried one more#endifthan#ifsince #523. That header cannot compile.ports/cortex_m4/ac6/inc/tx_port.hcarried a second, headerless copy of a function body, placing statements outside any function. That is #569.Two of those three shipped in headers that no CI job builds, which is why they survived. A syntactic check costs nothing and does not care whether a toolchain is available.
What the script does
Bash and awk, no dependencies.
--no-regenskips the reproducibility check when the tree is dirty;--quietprints failures only. Exit status is 0 or 1, so the same command serves a laptop and a runner.The file scope check tracks brace depth while skipping preprocessor lines, multi-line macro bodies and comments, and reports assignments, dereferences and control statements landing at depth zero. Headers under
example_buildare excluded, since those trees vendor third party SDK code that is not ours to hold to these rules.The fourth section never fails the run. Families with no copy script are maintained by hand, so a fix applied to one toolchain can silently miss the others; the report makes that visible rather than enforcing a rule that does not apply. It currently rediscovers, on its own, that the Cortex-M0
ac5,ac6andkeilports lack the barriers theirgnuandiarsiblings have.Wiring
ports_arch_check.ymlcalls the script instead of inlining its own copy-and-diff, so CI and the command line check the same things by the same definition.devas well asmaster. Triggering onmasteralone is the direct reason the drift went unseen: every one of those fixes merged intodev.prepare_release.shruns the checks before it branches or rewrites anything, and stops if they fail.SKIP_PORT_CHECKS=1overrides. Hard stop rather than a warning, on the grounds that a release is exactly when an unnoticed revert is most expensive.The check had not been running at all
While validating this PR, its own CI run failed at the checkout step:
The workflow passed
token: ${{ secrets.REPO_SCOPED_TOKEN }}toactions/checkout. Secrets are not exposed to pull requests from forks, and the recent run history shows every run failing the same way, ondevandmasteras well. Soports_arch_checkhas not been evaluating anything for a long time. That is the missing half of the explanation for the drift in #590: the gate existed, was scoped tomasteronly, and was dying before it ran.Both jobs now use
actions/checkout@v4with notokeninput. The defaultGITHUB_TOKENis sufficient to check out a public repository, and the repository has no submodules, sosubmodules: truewas doing nothing either. With that fixed, thecortex-mjob passes on this PR.The cortex-a job now fails for a real reason
With checkout working, the
cortex-ajob runs its ARMv7-A and ARMv8-Aupdate.ps1scripts for the first time in a long while, and reports 63 drifted files:tx_thread_schedule.Sacross every Cortex-A port,tx_thread_smp_time_get.Sacross the SMP ports, and atx_port.h.That is the same defect this PR is about, in a different port family. It is fixed in a follow-up, which also adds
update.shbeside eachupdate.ps1so the A profile can be regenerated on Linux.Correction. An earlier version of this description attributed the
tx_thread_schedule.Sdrift to the Cortex-A VFP fix in a7961fe and said regenerating would revert it. That was wrong, and measuring it showed why: the VFP fix is already present inports_arch/ARMv7-A, and the drift in those 38 files is a trailing blank line. The real revert hazard is elsewhere, intx_thread_smp_time_get.S, where the generic timer implementation from #555 went into the 24 generated SMP ports but never into the source, which still heldMOV x0, #0with aFIXME. Regenerating would have replaced a working timer read with a stub.Note that this job was already failing before this PR, at checkout, for every run. Nothing regresses; the failure simply becomes truthful.
Verification
Each check was verified by reintroducing the defect it exists to catch, not just by passing on a clean tree:
cortex_m4/ac6FAIL ... statement(s) outside any function body / 602: *((volatile ULONG *) 0xE000ED04) = ...#endifincortex_m85/iarFAIL ... #endif without a matching #if at line 633 (final depth -1)FAIL: running the copy scripts changed 1 file(s)The script passes on the tree as of #590, with no false positives across
ports,ports_arch,ports_moduleandports_smp.