mirror of
https://github.com/eclipse-threadx/threadx.git
synced 2026-10-06 06:59:08 +08:00
* 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>
562 lines
24 KiB
Bash
Executable File
562 lines
24 KiB
Bash
Executable File
#!/bin/bash
|
|
##############################################################################
|
|
# Copyright (c) 2026 Eclipse ThreadX contributors
|
|
#
|
|
# This program and the accompanying materials are made available under the
|
|
# terms of the MIT License which is available at
|
|
# https://opensource.org/licenses/MIT.
|
|
#
|
|
# AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
|
|
# The AI-generated portions may be considered public domain (CC0-1.0)
|
|
# and not subject to the project's licence. The human contributor has
|
|
# reviewed and verified that the code is correct.
|
|
#
|
|
# SPDX-License-Identifier: MIT and CC0-1.0
|
|
##############################################################################
|
|
|
|
# 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, 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
|
|
# CLANG=/path/to/clang scripts/check_clang.sh
|
|
#
|
|
# Options:
|
|
# --clang <path> Compiler to use; defaults to $CLANG then to clang.
|
|
# --asm-only Skip the C sources and the example builds.
|
|
# --no-examples Skip the example builds.
|
|
# --quiet Print only failures and the summary.
|
|
#
|
|
# Exit status is 0 when everything builds and 1 otherwise.
|
|
#
|
|
# Why this exists: the gnu ports are only ever built with GNU tooling, and GNU
|
|
# as accepts several non-canonical forms that LLVM's assembler rejects. Those
|
|
# forms accumulated unnoticed. This check also covers Arm Toolchain for
|
|
# Embedded, which is LLVM based and is the successor to Arm Compiler 6, so the
|
|
# ac6 code paths are exercised here as well.
|
|
#
|
|
# Arm Toolchain for Embedded releases:
|
|
# https://github.com/arm/arm-toolchain/releases
|
|
|
|
set -u
|
|
|
|
cd "$(dirname "$(realpath "$0")")/.."
|
|
|
|
CC="${CLANG:-clang}"
|
|
asm_only=0
|
|
no_examples=0
|
|
quiet=0
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--clang) [ "$#" -ge 2 ] || { echo "Error: --clang needs a path" >&2; exit 2; }; CC="$2"; shift 2 ;;
|
|
--asm-only) asm_only=1; no_examples=1; shift ;;
|
|
--no-examples) no_examples=1; shift ;;
|
|
--quiet) quiet=1; shift ;;
|
|
-h|--help) sed -n '17,33p' "$0"; exit 0 ;;
|
|
*) echo "Error: unknown option '$1'" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
say() { [ "$quiet" -eq 1 ] || echo "$@"; }
|
|
fail() { echo " FAIL: $*"; }
|
|
|
|
if ! command -v "$CC" >/dev/null 2>&1 && [ ! -x "$CC" ]; then
|
|
echo "Error: compiler '$CC' not found."
|
|
echo "Pass --clang <path>, set CLANG, or install Arm Toolchain for Embedded:"
|
|
echo " https://github.com/arm/arm-toolchain/releases"
|
|
exit 1
|
|
fi
|
|
|
|
# Resolve to an absolute path. The example stage runs the build scripts from
|
|
# inside their own directories, so a relative compiler path would stop
|
|
# resolving there.
|
|
if [ -e "$CC" ]; then
|
|
CC="$(realpath "$CC")"
|
|
else
|
|
CC="$(command -v "$CC")"
|
|
fi
|
|
|
|
say ""
|
|
say "Using: $CC"
|
|
say " $("$CC" --version | head -1)"
|
|
|
|
# Each port directory is mapped explicitly to a target triple and CPU. Do not
|
|
# replace this with prefix matching: cortex_a5* also matches cortex_a53 and
|
|
# cortex_a55, which are AArch64, and assembling those as ARM32 produces a flood
|
|
# of misleading errors.
|
|
declare -A PORT_TARGET=(
|
|
[cortex_m0]="arm-none-eabi cortex-m0 -mthumb"
|
|
[cortex_m0+]="arm-none-eabi cortex-m0plus -mthumb"
|
|
[cortex_m3]="arm-none-eabi cortex-m3 -mthumb"
|
|
[cortex_m4]="arm-none-eabi cortex-m4 -mthumb"
|
|
[cortex_m7]="arm-none-eabi cortex-m7 -mthumb"
|
|
[cortex_m23]="arm-none-eabi cortex-m23 -mthumb"
|
|
[cortex_m33]="arm-none-eabi cortex-m33 -mthumb"
|
|
[cortex_m52]="arm-none-eabi cortex-m52 -mthumb -mfloat-abi=hard"
|
|
[cortex_m55]="arm-none-eabi cortex-m55 -mthumb -mfloat-abi=hard"
|
|
[cortex_m85]="arm-none-eabi cortex-m85 -mthumb -mfloat-abi=hard"
|
|
[cortex_a5]="arm-none-eabi cortex-a5"
|
|
[cortex_a7]="arm-none-eabi cortex-a7"
|
|
[cortex_a8]="arm-none-eabi cortex-a8"
|
|
[cortex_a9]="arm-none-eabi cortex-a9"
|
|
[cortex_a12]="arm-none-eabi cortex-a12"
|
|
[cortex_a15]="arm-none-eabi cortex-a15"
|
|
[cortex_a17]="arm-none-eabi cortex-a17"
|
|
[cortex_a5_smp]="arm-none-eabi cortex-a5"
|
|
[cortex_a7_smp]="arm-none-eabi cortex-a7"
|
|
[cortex_a9_smp]="arm-none-eabi cortex-a9"
|
|
[cortex_r4]="arm-none-eabi cortex-r4"
|
|
[cortex_r5]="arm-none-eabi cortex-r5"
|
|
[cortex_r52]="arm-none-eabi cortex-r52"
|
|
[cortex_a34]="aarch64-none-elf cortex-a34"
|
|
[cortex_a35]="aarch64-none-elf cortex-a35"
|
|
[cortex_a53]="aarch64-none-elf cortex-a53"
|
|
[cortex_a55]="aarch64-none-elf cortex-a55"
|
|
[cortex_a57]="aarch64-none-elf cortex-a57"
|
|
[cortex_a65]="aarch64-none-elf cortex-a65"
|
|
[cortex_a65ae]="aarch64-none-elf cortex-a65ae"
|
|
[cortex_a72]="aarch64-none-elf cortex-a72"
|
|
[cortex_a73]="aarch64-none-elf cortex-a73"
|
|
[cortex_a75]="aarch64-none-elf cortex-a75"
|
|
[cortex_a76]="aarch64-none-elf cortex-a76"
|
|
[cortex_a76ae]="aarch64-none-elf cortex-a76ae"
|
|
[cortex_a77]="aarch64-none-elf cortex-a77"
|
|
[cortex_a34_smp]="aarch64-none-elf cortex-a34"
|
|
[cortex_a35_smp]="aarch64-none-elf cortex-a35"
|
|
[cortex_a53_smp]="aarch64-none-elf cortex-a53"
|
|
[cortex_a55_smp]="aarch64-none-elf cortex-a55"
|
|
[cortex_a57_smp]="aarch64-none-elf cortex-a57"
|
|
[cortex_a65_smp]="aarch64-none-elf cortex-a65"
|
|
[cortex_a65ae_smp]="aarch64-none-elf cortex-a65ae"
|
|
[cortex_a72_smp]="aarch64-none-elf cortex-a72"
|
|
[cortex_a73_smp]="aarch64-none-elf cortex-a73"
|
|
[cortex_a75_smp]="aarch64-none-elf cortex-a75"
|
|
[cortex_a76_smp]="aarch64-none-elf cortex-a76"
|
|
[cortex_a76ae_smp]="aarch64-none-elf cortex-a76ae"
|
|
[cortex_a77_smp]="aarch64-none-elf cortex-a77"
|
|
[cortex_a78_smp]="aarch64-none-elf cortex-a78"
|
|
)
|
|
|
|
# Assembly guarded by a feature macro is invisible to the stage above, which
|
|
# assembles with default flags and so lets the preprocessor discard every #ifdef
|
|
# block before the assembler sees it. These are the macros a user can turn on;
|
|
# each file carrying one is assembled again with it defined.
|
|
#
|
|
# This is not hypothetical. It is where "POP {r0, lr}" was found in the Cortex-M0
|
|
# and Cortex-M23 execution-profile paths: invalid on Armv6-M and Armv8-M
|
|
# Baseline, where the 16-bit POP takes r0-r7 and pc only, and rejected by GNU as
|
|
# well as by LLVM. Turning the feature on had never once been tried.
|
|
FEATURE_MACROS="TX_ENABLE_VFP_SUPPORT TX_ENABLE_FIQ_SUPPORT TX_LOW_POWER
|
|
TX_ENABLE_EXECUTION_CHANGE_NOTIFY"
|
|
|
|
# TX_ENABLE_IRQ_NESTING and TX_ENABLE_FIQ_NESTING are deliberately not here.
|
|
# They guard no assembly in the trees this script walks: the nesting start and end
|
|
# routines are separate files compiled unconditionally, and the macros only feed
|
|
# the TX_PORT_SPECIFIC_BUILD_OPTIONS bitfield in tx_port.h. Adding them would
|
|
# assemble nothing new and imply coverage that does not exist.
|
|
|
|
# Extra flags for the VFP paths, per core, needed only where -mcpu alone cannot
|
|
# assemble them. Cortex-R4's FPU is an option rather than part of the core, so
|
|
# both toolchains reject its VFP code without an -mfpu.
|
|
#
|
|
# Do not extend this to the A profile ports. They save D16-D31, which exists only
|
|
# on a 32-register FPU, so naming a -d16 FPU takes those registers away and turns
|
|
# 28 working files into "register expected". Their defaults are already correct.
|
|
declare -A VFP_EXTRA=(
|
|
[cortex_r4]="-mfpu=vfpv3-d16 -mfloat-abi=softfp"
|
|
)
|
|
|
|
# One core per architecture profile for the C sources. Compiling all of them
|
|
# for every core would multiply the run time without adding coverage, since the
|
|
# port headers differ by profile rather than by core.
|
|
#
|
|
# cortex_r52 earns a slot of its own next to cortex_r5 because Armv8-R AArch32
|
|
# is a separate profile rather than a variant of Armv7-R. That port is written
|
|
# by hand instead of generated from ports_arch, and its tx_port.h differs
|
|
# accordingly, so cortex_r5 does not stand in for it.
|
|
C_CORES="cortex_m0 cortex_m4 cortex_m23 cortex_m33 cortex_m55 cortex_a7 cortex_a53 cortex_r5 cortex_r52"
|
|
|
|
# Example builds driven by CMake rather than by a build_threadx.sh pair. These
|
|
# are covered by their own stage below, so the script-driven loop passes over
|
|
# them without reporting them as a gap.
|
|
CMAKE_EXAMPLE_CORES="cortex_r52"
|
|
|
|
# Example builds that are not expected to link, with the reason. Named by
|
|
# their port directory, which covers both ports/ and ports_smp/. Listed
|
|
# explicitly rather than silently skipped, so the gaps stay visible.
|
|
#
|
|
# These fail with the GNU toolchain too, so they are not LLVM problems. All four
|
|
# fail the same way, for the same reason:
|
|
#
|
|
# their linker scripts define the .init and .fini sections but not the _init
|
|
# and _fini symbols. Those come from crti.o and crtn.o, which -nostartfiles
|
|
# leaves out, so newlib's fini.c cannot resolve them and the link ends with
|
|
# "undefined reference to `_fini'". Reproduced with arm-none-eabi-gcc 13.2.1.
|
|
#
|
|
# Until 6.1.10 the four linked libc.a and libgcc.a checked in beside them, which
|
|
# supplied those symbols. That sweep removed the archives without updating the
|
|
# link lines, so for years the examples failed earlier still, on the missing
|
|
# files themselves. Fixing the link lines exposed the _fini gap underneath.
|
|
EXAMPLES_EXPECTED_TO_FAIL="arm9 arm11 cortex_r4 cortex_r5"
|
|
|
|
failures=0
|
|
skipped=""
|
|
|
|
# --------------------------------------------------------------------------
|
|
say ""
|
|
say "== Assembly sources of every Arm gnu port =="
|
|
|
|
total=0
|
|
# The module ports keep their assembly in module_manager/src, not src. This
|
|
# glob read ports_module/*/gnu/src until 26 Aug 2026; that directory does not
|
|
# exist, the [ -d ] guard below skipped it in silence, and 116 files across
|
|
# nine Arm module ports were assembled by no check with either compiler. The
|
|
# count went from 724 to 840 when the path was corrected, and three of the new
|
|
# files did not assemble.
|
|
for dir in ports/*/gnu/src ports_smp/*/gnu/src ports_module/*/gnu/module_manager/src; do
|
|
[ -d "$dir" ] || continue
|
|
core="$(echo "$dir" | cut -d/ -f2)"
|
|
spec="${PORT_TARGET[$core]:-}"
|
|
if [ -z "$spec" ]; then
|
|
skipped="$skipped $core"
|
|
continue
|
|
fi
|
|
# shellcheck disable=SC2086
|
|
set -- $spec
|
|
target="$1"; cpu="$2"; shift 2; extra="$*"
|
|
|
|
for src in "$dir"/*.S "$dir"/*.s; do
|
|
[ -f "$src" ] || continue
|
|
total=$((total + 1))
|
|
output="$("$CC" --target="$target" -mcpu="$cpu" $extra -c "$src" -o /dev/null 2>&1)"
|
|
if [ -n "$output" ]; then
|
|
fail "$src"
|
|
echo "$output" | sed 's/^/ /'
|
|
failures=$((failures + 1))
|
|
fi
|
|
done
|
|
done
|
|
say " $((total - failures)) of $total assembled"
|
|
if [ -n "$skipped" ]; then
|
|
say " not Arm, skipped:$(echo $skipped | tr ' ' '\n' | sort -u | tr '\n' ' ')"
|
|
fi
|
|
|
|
# --------------------------------------------------------------------------
|
|
say ""
|
|
say "== Assembly behind feature macros =="
|
|
|
|
for macro in $FEATURE_MACROS; do
|
|
macro_total=0
|
|
macro_bad=0
|
|
# The module ports are named here for the same reason as in the stage
|
|
# above: they were absent from this list until 26 Aug 2026 and so read as
|
|
# covered. Adding them found the Cortex-M23 module manager carrying the
|
|
# very POP {r0, lr} this comment describes, six months after the same fix
|
|
# landed in its non-module sibling.
|
|
for src in $(grep -rl "$macro" ports/*/gnu/src/*.S ports_smp/*/gnu/src/*.S \
|
|
ports_module/*/gnu/module_manager/src/*.S \
|
|
2>/dev/null | sort); do
|
|
core="$(echo "$src" | cut -d/ -f2)"
|
|
spec="${PORT_TARGET[$core]:-}"
|
|
[ -n "$spec" ] || continue
|
|
# shellcheck disable=SC2086
|
|
set -- $spec
|
|
target="$1"; cpu="$2"; shift 2; extra="$*"
|
|
|
|
# The FPU flags apply to the VFP paths only; the other macros guard no
|
|
# floating-point code and do not need them.
|
|
fpu=""
|
|
if [ "$macro" = "TX_ENABLE_VFP_SUPPORT" ]; then
|
|
fpu="${VFP_EXTRA[$core]:-}"
|
|
fi
|
|
|
|
macro_total=$((macro_total + 1))
|
|
output="$("$CC" --target="$target" -mcpu="$cpu" $extra $fpu \
|
|
-D"$macro" -c "$src" -o /dev/null 2>&1)"
|
|
if [ -n "$output" ]; then
|
|
fail "$src with -D$macro"
|
|
echo "$output" | grep "error:" | head -3 | sed 's/^/ /'
|
|
macro_bad=$((macro_bad + 1))
|
|
failures=$((failures + 1))
|
|
fi
|
|
done
|
|
if [ "$macro_total" -eq 0 ]; then
|
|
say " $macro: no assembly is guarded by it"
|
|
else
|
|
say " $macro: $((macro_total - macro_bad)) of $macro_total assembled"
|
|
fi
|
|
done
|
|
|
|
# --------------------------------------------------------------------------
|
|
if [ "$asm_only" -eq 0 ]; then
|
|
say ""
|
|
say "== Common C sources, one core per architecture profile =="
|
|
|
|
for core in $C_CORES; do
|
|
spec="${PORT_TARGET[$core]:-}"
|
|
[ -n "$spec" ] || continue
|
|
# shellcheck disable=SC2086
|
|
set -- $spec
|
|
target="$1"; cpu="$2"; shift 2; extra="$*"
|
|
|
|
count=0; bad=0
|
|
for src in common/src/*.c; do
|
|
count=$((count + 1))
|
|
output="$("$CC" --target="$target" -mcpu="$cpu" $extra \
|
|
-Iports/"$core"/gnu/inc -Icommon/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
|
|
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 ""
|
|
say "== Example builds, linked with lld =="
|
|
|
|
example_ok=0
|
|
example_total=0
|
|
example_known=""
|
|
example_nodriver=""
|
|
example_nosample=""
|
|
for dir in ports/*/gnu/example_build ports_smp/*/gnu/example_build; do
|
|
[ -d "$dir" ] || continue
|
|
core="$(echo "$dir" | cut -d/ -f2)"
|
|
|
|
# Anything on the expected-to-fail list is reported before any other
|
|
# filter is applied, so a name placed there can never drop out of the
|
|
# output. arm9 and arm11 are the cases that matter: they are Arm ports
|
|
# with example drivers, but they carry no PORT_TARGET entry, so the
|
|
# Arm test below would discard them.
|
|
case " $EXAMPLES_EXPECTED_TO_FAIL " in
|
|
*" $core "*) example_known="$example_known $core"; continue ;;
|
|
esac
|
|
|
|
# Arm ports only, the same rule the assembly stage applies. Naming
|
|
# linux or mips32 as a gap here would be noise, not information.
|
|
[ -n "${PORT_TARGET[$core]:-}" ] || continue
|
|
|
|
# Covered by the CMake stage below rather than here.
|
|
case " $CMAKE_EXAMPLE_CORES " in
|
|
*" $core "*) continue ;;
|
|
esac
|
|
|
|
# A driverless example is not covered by this stage, so say so rather
|
|
# than dropping out in silence. A port that is simply absent from the
|
|
# count reads as covered.
|
|
if [ ! -f "$dir/build_threadx.sh" ]; then
|
|
example_nodriver="$example_nodriver $core"
|
|
continue
|
|
fi
|
|
if [ ! -f "$dir/build_threadx_sample.sh" ]; then
|
|
example_nosample="$example_nosample $core"
|
|
continue
|
|
fi
|
|
example_total=$((example_total + 1))
|
|
|
|
rm -f "$dir"/*.o "$dir"/*.a "$dir"/*.out "$dir"/*.map 2>/dev/null || true
|
|
log="$(cd "$dir" && TOOLCHAIN=atfe ATFE_CLANG="$CC" ./build_threadx.sh 2>&1 && \
|
|
TOOLCHAIN=atfe ATFE_CLANG="$CC" ./build_threadx_sample.sh 2>&1)" || true
|
|
|
|
if [ -f "$dir/sample_threadx.out" ]; then
|
|
example_ok=$((example_ok + 1))
|
|
else
|
|
fail "$core: example build produced no image"
|
|
# Not filtered on "error": a missing tool reports "command not
|
|
# found" or "Permission denied", and filtering hid exactly that.
|
|
echo "$log" | tail -6 | sed 's/^/ /'
|
|
failures=$((failures + 1))
|
|
fi
|
|
rm -f "$dir"/*.o "$dir"/*.a "$dir"/*.out "$dir"/*.map 2>/dev/null || true
|
|
done
|
|
say " $example_ok of $example_total example builds linked"
|
|
if [ -n "$example_known" ]; then
|
|
say " known not to link, see the list at the top of this script:$example_known"
|
|
fi
|
|
if [ -n "$example_nosample" ]; then
|
|
say " has build_threadx.sh but no build_threadx_sample.sh, so not linked:$example_nosample"
|
|
fi
|
|
if [ -n "$example_nodriver" ]; then
|
|
say " no script driver, so outside this stage:$example_nodriver"
|
|
fi
|
|
fi
|
|
# --------------------------------------------------------------------------
|
|
# The Cortex-R52 examples are built by CMake, so they need a toolchain file
|
|
# rather than TOOLCHAIN=atfe. Same compiler, same linker, same purpose as the
|
|
# stage above: confirm the images still link when the toolchain is not GNU.
|
|
if [ "$no_examples" -eq 0 ]; then
|
|
say ""
|
|
say "== CMake example builds, linked with lld =="
|
|
|
|
if ! command -v cmake >/dev/null 2>&1 || ! command -v ninja >/dev/null 2>&1; then
|
|
say " skipped: cmake and ninja are both required"
|
|
else
|
|
for core in $CMAKE_EXAMPLE_CORES; do
|
|
build_dir="$(mktemp -d)"
|
|
# ATFE_TOOLCHAIN_PATH follows --clang, so the stage uses the same
|
|
# compiler as every other stage rather than whatever is on PATH.
|
|
if cmake -S . -B "$build_dir" -G Ninja \
|
|
-DCMAKE_TOOLCHAIN_FILE="cmake/${core}_clang.cmake" \
|
|
-DATFE_TOOLCHAIN_PATH="$(cd "$(dirname "$CC")" && pwd)" \
|
|
-DTX_R52_BUILD_FVP_EXAMPLE=ON \
|
|
-DTX_R52_ENABLE_MPU=ON >"$build_dir/configure.log" 2>&1; then
|
|
# Read the image list from the generated graph instead of
|
|
# repeating it here, so adding a target cannot silently escape
|
|
# this check. The images are EXCLUDE_FROM_ALL, so "ninja" alone
|
|
# would build none of them.
|
|
#
|
|
# The cmake_object_order_depends_target_* entries are CMake's
|
|
# own ordering phonies, one per real image and named after it.
|
|
# Counting those doubled the total and reported ten images built
|
|
# where there are five.
|
|
images="$(ninja -C "$build_dir" -t targets all 2>/dev/null \
|
|
| grep -oE '^[A-Za-z0-9_]+\.elf' \
|
|
| grep -v '^cmake_' | sort -u)"
|
|
if [ -z "$images" ]; then
|
|
fail "$core: no .elf targets found in the CMake graph"
|
|
failures=$((failures + 1))
|
|
else
|
|
built=0; total=0
|
|
for image in $images; do
|
|
total=$((total + 1))
|
|
if ninja -C "$build_dir" "$image" \
|
|
>"$build_dir/$image.log" 2>&1; then
|
|
built=$((built + 1))
|
|
else
|
|
fail "$core: $image did not build"
|
|
tail -6 "$build_dir/$image.log" | sed 's/^/ /'
|
|
failures=$((failures + 1))
|
|
fi
|
|
done
|
|
say " $core: $built of $total images linked"
|
|
fi
|
|
else
|
|
fail "$core: CMake configure failed"
|
|
tail -6 "$build_dir/configure.log" | sed 's/^/ /'
|
|
failures=$((failures + 1))
|
|
fi
|
|
rm -rf "$build_dir"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# --------------------------------------------------------------------------
|
|
say ""
|
|
if [ "$failures" -eq 0 ]; then
|
|
say "All LLVM toolchain checks passed."
|
|
exit 0
|
|
fi
|
|
|
|
echo "$failures LLVM toolchain check(s) failed."
|
|
exit 1
|