Skip to content

Added port consistency checks and wired them into CI and release preparation - #591

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:feature/port-consistency-checks
Aug 9, 2026
Merged

Added port consistency checks and wired them into CI and release preparation#591
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:feature/port-consistency-checks

Conversation

@fdesbiens

@fdesbiens fdesbiens commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Adds scripts/check_ports.sh, a local and CI check over the port trees, and wires it into ports_arch_check and prepare_release.sh.

Rebased onto dev now that #589 has merged; stacked on #590. The reproducibility check fails on dev as 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:

Check The defect it would have caught
Generated ports are reproducible from ports_arch Cortex-M fixes applied to the generated copies rather than the source for eight months. Running the copy scripts on dev changes 35 files, and would revert #523, #514 and the IAR comment syntax fix.
Preprocessor directives balance ports/cortex_m85/iar/inc/tx_port.h has carried one more #endif than #if since #523. That header cannot compile.
No code at file scope in a port header ports/cortex_m4/ac6/inc/tx_port.h carried 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

$ scripts/check_ports.sh

== Generated ports are reproducible from ports_arch ==
  ok: the copy scripts change nothing

== Preprocessor directives balance ==
  ok: every port header balances

== No code at file scope in port headers ==
  ok: no port header carries code at file scope

== Families with no copy script (report only) ==
  ports/cortex_m0: "dsb 0xF" present in gnu iar but absent in ac5 ac6 keil
  ports/cortex_m0: "isb 0xF" present in gnu iar but absent in ac5 ac6 keil

All port consistency checks passed.

Bash and awk, no dependencies. --no-regen skips the reproducibility check when the tree is dirty; --quiet prints 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_build are 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, ac6 and keil ports lack the barriers their gnu and iar siblings have.

Wiring

  • ports_arch_check.yml calls the script instead of inlining its own copy-and-diff, so CI and the command line check the same things by the same definition.
  • The workflow now triggers on pull requests to dev as well as master. Triggering on master alone is the direct reason the drift went unseen: every one of those fixes merged into dev.
  • prepare_release.sh runs the checks before it branches or rewrites anything, and stops if they fail. SKIP_PORT_CHECKS=1 overrides. 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:

##[error]Input required and not supplied: token

The workflow passed token: ${{ secrets.REPO_SCOPED_TOKEN }} to actions/checkout. Secrets are not exposed to pull requests from forks, and the recent run history shows every run failing the same way, on dev and master as well. So ports_arch_check has 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 to master only, and was dying before it ran.

Both jobs now use actions/checkout@v4 with no token input. The default GITHUB_TOKEN is sufficient to check out a public repository, and the repository has no submodules, so submodules: true was doing nothing either. With that fixed, the cortex-m job passes on this PR.

The cortex-a job now fails for a real reason

With checkout working, the cortex-a job runs its ARMv7-A and ARMv8-A update.ps1 scripts for the first time in a long while, and reports 63 drifted files: tx_thread_schedule.S across every Cortex-A port, tx_thread_smp_time_get.S across the SMP ports, and a tx_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.sh beside each update.ps1 so the A profile can be regenerated on Linux.

Correction. An earlier version of this description attributed the tx_thread_schedule.S drift 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 in ports_arch/ARMv7-A, and the drift in those 38 files is a trailing blank line. The real revert hazard is elsewhere, in tx_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 held MOV x0, #0 with a FIXME. 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:

Reintroduced Result
The #569 orphaned body in cortex_m4/ac6 FAIL ... statement(s) outside any function body / 602: *((volatile ULONG *) 0xE000ED04) = ...
The stray #endif in cortex_m85/iar FAIL ... #endif without a matching #if at line 633 (final depth -1)
A direct edit to a generated port 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_module and ports_smp.

@fdesbiens
fdesbiens force-pushed the feature/port-consistency-checks branch 2 times, most recently from 0ddf35a to ff0b93d Compare August 9, 2026 14:17
…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
fdesbiens force-pushed the feature/port-consistency-checks branch from ff0b93d to 0b8458f Compare August 9, 2026 14:45
@fdesbiens
fdesbiens merged commit 08b120d into eclipse-threadx:dev Aug 9, 2026
2 of 3 checks passed
@fdesbiens
fdesbiens deleted the feature/port-consistency-checks branch August 9, 2026 14:48
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.

1 participant