Compiled the module manager C sources, which no check had ever built (#689)

* Compiled the module manager C sources, which no check had ever built

#672 corrected this script's assembly glob and brought the module ports into
the count, but only their assembly. Their C stayed outside every check: 27
files of portable module manager under common_modules, plus the per-port code
under ports_module/<core>/gnu/module_manager/src. By this script's own standard
-- a port simply absent from the count reads as covered -- 293 files across
nine Arm module ports were compiled by nothing, with either compiler.

Each module port ships its own tx_port.h and txm_module_port.h carrying the
control-block extensions the dispatch code needs, so a port is compiled against
its own headers rather than the base port's. Two details the ports themselves
dictate:

  An SMP port's control blocks come from common_smp. Pairing cortex_a35_smp
  with the single-core headers hid _tx_thread_smp_protect and
  _tx_thread_smp_unprotect behind implicit declarations and lost
  tx_thread_smp_core_executing from TX_THREAD, so fourteen files reported
  errors for a port that builds correctly.

  The TrustZone ports carry cmse_nonsecure_entry, which needs -mcmse to be
  honoured rather than ignored. tx_thread_secure_stack.c also carries GCC's
  optimize attribute, which clang does not implement; that divergence is
  suppressed by name, for a file GCC builds cleanly.

All nine ports compile: 293 of 293. Verified that the stage fails as intended
by injecting a defect into a throwaway worktree -- a defect in common_modules
is reported under every port, one in a port's own source only under that port.

Assisted-by: Claude Code (Opus 5)

* Ran the module manager stage against the sources that reach it

Three corrections to the new stage, all found by running it against dev
rather than against the tree it was written on.

The workflows did not trigger on common_modules. Both check_clang.yml and
check_gcc.yml list ports_module but not common_modules, and the portable
module manager under it is the larger half of what the stage compiles --
28 of the 31 to 37 files each port builds, plus two include directories.
A change there left the stage unrun, which is the same "absent from the
count reads as covered" that the stage exists to close. Both lists gain
common_modules, and they stay identical to each other as the comment in
each asks.

A deliberate deprecation notice read as a build failure. Since this PR
was opened, txm_module_manager_absolute_load.c gained a #pragma message
steering callers to the extended entry point. The stage treats any
compiler output as a failure, so that one notice failed every port: nine
failures on a tree where nothing is wrong. Pragma messages are now
waived for the stage, because a notice to callers is not a defect in the
file that carries it.

That failure also printed nothing. Both C stages report by grepping the
output for "error:", so a diagnostic that is not an error produced a bare
FAIL line with no reason under it, and the only way to learn the reason
was to reproduce the compile by hand. Both stages now fall back to
showing what the compiler actually said.

The TrustZone attribute waiver is narrowed to the one file that needs it.
tx_thread_secure_stack.c carries GCC's optimize attribute, which clang
does not implement; it is the only file among the 300-odd this stage
compiles that does. Waiving the warning for the whole port would have
swallowed a stray unknown attribute anywhere else in it.

Verified with the same toolchain CI uses, ATfE 22.1.0: the full script
passes, and every port compiles every file.

  cortex_a35 31/31   cortex_a35_smp 31/31   cortex_a7 34/34
  cortex_m0+ 33/33   cortex_m23 37/37       cortex_m3 33/33
  cortex_m33 37/37   cortex_m4 33/33        cortex_m7 33/33

The counts are each one higher than this PR first reported, because
txm_module_manager_absolute_load_extended.c has landed since. The stage
picked it up with no edit, which is what globbing the directories was for.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>

---------

Co-authored-by: r <r@r>
This commit is contained in:
Frédéric Desbiens
2026-09-09 14:39:30 -04:00
committed by GitHub
co-authored by r
parent 6ce8d5cc76
commit 8be4c45cce
3 changed files with 122 additions and 4 deletions
+6
View File
@@ -20,6 +20,12 @@ on:
- "CMakeLists.txt"
- "cmake/**"
- "common/**"
# common_modules/ holds the portable module manager that the module
# manager stage compiles once per Arm module port -- the larger half of
# what that stage builds. Without it a change there leaves the stage
# unrun, which is the same "absent from the count reads as covered" the
# stage exists to close.
- "common_modules/**"
- "common_smp/**"
- "ports/**"
- "ports_arch/**"
+12
View File
@@ -42,6 +42,12 @@ on:
- "CMakeLists.txt"
- "cmake/**"
- "common/**"
# common_modules/ holds the portable module manager that the module
# manager stage compiles once per Arm module port -- the larger half of
# what that stage builds. Without it a change there leaves the stage
# unrun, which is the same "absent from the count reads as covered" the
# stage exists to close.
- "common_modules/**"
- "common_smp/**"
- "ports/**"
- "ports_arch/**"
@@ -67,6 +73,12 @@ on:
- "CMakeLists.txt"
- "cmake/**"
- "common/**"
# common_modules/ holds the portable module manager that the module
# manager stage compiles once per Arm module port -- the larger half of
# what that stage builds. Without it a change there leaves the stage
# unrun, which is the same "absent from the count reads as covered" the
# stage exists to close.
- "common_modules/**"
- "common_smp/**"
- "ports/**"
- "ports_arch/**"
+104 -4
View File
@@ -14,11 +14,12 @@
# SPDX-License-Identifier: MIT and CC0-1.0
##############################################################################
# Builds the Arm ports with an LLVM based toolchain, in five stages: assemble
# Builds the Arm ports with an LLVM based toolchain, in six stages: assemble
# every assembly source of every Arm gnu port, assemble again the parts guarded
# by feature macros, compile the common C sources for one core per architecture
# profile, then link the example builds, both the script-driven ones and those
# driven by CMake. Only the linking stages need a target C library.
# profile, compile the module manager C sources once per Arm module port, then
# link the example builds, both the script-driven ones and those driven by
# CMake. Only the linking stages need a target C library.
#
# scripts/check_clang.sh # clang from PATH
# scripts/check_clang.sh --clang /path/to/clang
@@ -310,7 +311,14 @@ if [ "$asm_only" -eq 0 ]; then
-Iports/"$core"/gnu/inc -Icommon/inc -c "$src" -o /dev/null 2>&1)"
if [ -n "$output" ]; then
fail "$core: $src"
echo "$output" | grep "error:" | head -3 | sed 's/^/ /'
# Show the error lines when there are any, and otherwise
# whatever the compiler did say -- a FAIL with nothing under it
# sends the reader off to reproduce the command by hand.
if echo "$output" | grep -q "error:"; then
echo "$output" | grep "error:" | head -3 | sed 's/^/ /'
else
echo "$output" | head -3 | sed 's/^/ /'
fi
bad=$((bad + 1)); failures=$((failures + 1))
fi
done
@@ -319,6 +327,98 @@ if [ "$asm_only" -eq 0 ]; then
fi
# --------------------------------------------------------------------------
if [ "$asm_only" -eq 0 ]; then
say ""
say "== Module manager C sources, one per Arm module port =="
# Correcting the assembly glob above brought the module ports into the count,
# but only their assembly. Their C stayed outside every check: 27 files of
# portable module manager under common_modules, plus the per-port code under
# ports_module/<core>/gnu/module_manager/src. Nothing compiled either one, so
# by this script's own standard they read as covered while being unbuilt.
#
# Each module port ships its own tx_port.h and txm_module_port.h, carrying the
# control-block extensions the dispatch code needs, so a port is compiled
# against its own headers rather than the base port's.
module_skipped=""
for dir in ports_module/*/gnu/module_manager/src; do
[ -d "$dir" ] || continue
core="$(echo "$dir" | cut -d/ -f2)"
spec="${PORT_TARGET[$core]:-}"
if [ -z "$spec" ]; then
module_skipped="$module_skipped $core"
continue
fi
inc="ports_module/$core/gnu/inc"
if [ ! -f "$inc/tx_port.h" ] || [ ! -f "$inc/txm_module_port.h" ]; then
module_skipped="$module_skipped $core(headers)"
continue
fi
# shellcheck disable=SC2086
set -- $spec
target="$1"; cpu="$2"; shift 2; extra="$*"
# An SMP port's control blocks come from common_smp; pairing it with the
# single-core headers hides _tx_thread_smp_protect behind an implicit
# declaration instead of compiling the port that is actually shipped.
case "$core" in
*_smp) kernel_inc="common_smp/inc" ;;
*) kernel_inc="common/inc" ;;
esac
# The TrustZone ports carry cmse_nonsecure_entry, which needs -mcmse to
# be honoured rather than ignored.
port_extra=""
if [ -f "$inc/tx_secure_interface.h" ]; then
port_extra="-mcmse"
fi
count=0; bad=0
for src in common_modules/module_manager/src/*.c "$dir"/*.c; do
[ -f "$src" ] || continue
count=$((count + 1))
# tx_thread_secure_stack.c carries GCC's optimize attribute, which
# clang does not implement and warns about. That is a toolchain
# divergence in a file GCC builds cleanly, so it is waived for that
# file alone -- a stray unknown attribute anywhere else in the port
# must still be reported.
src_extra=""
case "$src" in
*/tx_thread_secure_stack.c) src_extra="-Wno-unknown-attributes" ;;
esac
# A #pragma message is a deliberate notice to callers, not a defect
# in the file that carries it. txm_module_manager_absolute_load.c
# deprecates itself in favour of the extended entry point, and this
# stage compiles it once per port.
output="$("$CC" --target="$target" -mcpu="$cpu" $extra $port_extra \
$src_extra "-Wno-#pragma-messages" \
-I"$inc" -I"$kernel_inc" -Icommon_modules/inc \
-Icommon_modules/module_manager/inc -c "$src" -o /dev/null 2>&1)"
if [ -n "$output" ]; then
fail "$core: $src"
# Show the error lines when there are any, and otherwise
# whatever the compiler did say -- a FAIL with nothing under it
# sends the reader off to reproduce the command by hand.
if echo "$output" | grep -q "error:"; then
echo "$output" | grep "error:" | head -3 | sed 's/^/ /'
else
echo "$output" | head -3 | sed 's/^/ /'
fi
bad=$((bad + 1)); failures=$((failures + 1))
fi
done
say " $core: $((count - bad)) of $count compiled"
done
if [ -n "$module_skipped" ]; then
say " no target mapping, skipped:$module_skipped"
fi
fi
# --------------------------------------------------------------------------
if [ "$no_examples" -eq 0 ]; then
say ""