mirror of
https://github.com/eclipse-threadx/threadx.git
synced 2026-10-06 06:59:08 +08:00
* Stated the compiler and coverage requirements instead of citing a file no contributor can open
Seven comments across five files cited a maintainer-local document as the
source for two project requirements: that GCC 14 on Linux is the default
compiler, and that the coverage target is 100%. That document is not part of
this repository and is not published anywhere, so the citation gave a reader
nothing to follow -- it named a source they cannot open, in place of simply
stating the requirement.
Both requirements are real and both stay. Only the pointer goes: each comment
now states the requirement on its own terms, which is what the surrounding
prose was already doing everywhere else.
cmake/cortex_r52.cmake the pinned reference toolchain
scripts/check_gcc.sh why the script exists
.github/workflows/gcc_check.yml why the workflow exists, and the
GCC_VERSION pin
.github/workflows/r52_fvp.yml the GCC_VERSION pin
.github/workflows/regression_template.yml the coverage floor, twice
Comments only; no behaviour changes. Two paragraphs are rewrapped where the
shorter text left a ragged line. Verified that scripts/check_gcc.sh still
parses and prints its help from the header range it slices, and that
cmake/cortex_r52.cmake still configures the Cortex-R52 build.
Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
* Said who the pinned toolchain default in the CMake toolchain files serves
Both cmake/cortex_r52.cmake and cmake/cortex_m52.cmake default
ARM_TOOLCHAIN_PATH to a toolchains directory under the user's home, guarded by
an EXISTS check. Nothing said whether CI relies on that, and the natural
reading is that it does.
It does not. The three workflows that install a toolchain unpack it into the
workspace and cache it there, and r52_fvp.yml puts that directory on PATH
before configuring; scripts/check_gcc.sh passes -DARM_TOOLCHAIN_PATH at each of
its three CMake call sites. On a runner the guarded directory is absent, the
EXISTS check falls through, and the compiler comes from PATH. The default only
ever fires on a developer machine, where it is what makes a no-flag build work.
Both comments now say that, so the default is not mistaken for a CI dependency
and not removed as dead code. cortex_r52.cmake carries the explanation and
cortex_m52.cmake refers to it, matching the cross-reference already there.
The r52 comment also claimed absolute paths mean "the build does not depend on
PATH ordering", which is only true where the pinned directory exists -- in CI
the build depends on PATH and nothing else. Qualified accordingly.
Comments only; no behaviour changes. Verified that both toolchain files still
configure, and that the fall-through is real: with HOME pointed at a directory
holding no toolchains, cortex_r52.cmake configures against the arm-none-eabi-gcc
found on PATH.
Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
336 lines
14 KiB
YAML
336 lines
14 KiB
YAML
name: r52_fvp
|
|
|
|
# Builds every Cortex-R52 CMake image in both supported configurations and
|
|
# EXECUTES them on the Armv8-R AEM FVP, asserting each image's self-reported
|
|
# result.
|
|
#
|
|
# Why this exists: until this workflow landed, nothing in CI ran a single
|
|
# instruction of any ThreadX port. gcc_check compiles and links -- its own
|
|
# header says so, "it compiles and links and **executes nothing**" -- and its
|
|
# CMake stage covers exactly one R52 configuration, the base FVP example with
|
|
# -DTX_R52_ENABLE_MPU=ON. So a change that assembles cleanly and links cleanly
|
|
# and then hangs on the first context switch passes every required check.
|
|
#
|
|
# That gap matters more for cortex_r52 than for the other ports, because the
|
|
# R52 is the foundation the partitioning work is sequenced behind: the EL2 boot
|
|
# path in entry.S, the MPU programming, and the generic-timer plumbing are all
|
|
# things later work attaches to rather than replaces. A regression in any of
|
|
# them has to be caught by an execution test; there is no static check for
|
|
# "the scheduler still schedules".
|
|
#
|
|
# What it covers:
|
|
#
|
|
# - the default configuration -- the images gcc_check's CMake stage builds,
|
|
# but run rather than merely linked;
|
|
# - the feature configuration -- VFP with the hard float ABI, FIQ, IRQ
|
|
# nesting and FIQ nesting. Those four options gate whole assembly blocks
|
|
# (the VMRS/VSTMDB/VLDMIA sequences, the FIQ context paths, the nesting
|
|
# start/end pairs) that the default configuration never assembles, let
|
|
# alone runs.
|
|
#
|
|
# What it does not cover: the module manager port and the S32Z280 targets are
|
|
# not on dev yet -- they are PR #639. When that merges, add their lanes here
|
|
# rather than starting a second workflow; the matrix already has the shape.
|
|
#
|
|
# The S32Z280 targets will be build-only in CI regardless. They need silicon,
|
|
# and a hosted runner has none.
|
|
|
|
on:
|
|
# push as well as pull_request, for the reason gcc_check.yml states at
|
|
# length: dev needs its own baseline so a bad squash-merge is caught then
|
|
# rather than by whoever opens the next pull request.
|
|
push:
|
|
branches: [ master, dev ]
|
|
paths:
|
|
- ".github/workflows/r52_fvp.yml"
|
|
- "CMakeLists.txt"
|
|
- "cmake/cortex_r52*.cmake"
|
|
- "common/**"
|
|
- "ports/cortex_r52/**"
|
|
- "ports_module/cortex_r52/**"
|
|
pull_request:
|
|
branches: [ master, dev ]
|
|
# Duplicated rather than shared through a YAML anchor. GitHub Actions'
|
|
# parser does not dependably honour anchors and the failure mode is the
|
|
# whole workflow refusing to parse -- a job that dies before it does
|
|
# anything, which is the exact defect gcc_check.yml carries a comment
|
|
# about. **Edit both.**
|
|
paths:
|
|
- ".github/workflows/r52_fvp.yml"
|
|
- "CMakeLists.txt"
|
|
- "cmake/cortex_r52*.cmake"
|
|
- "common/**"
|
|
- "ports/cortex_r52/**"
|
|
- "ports_module/cortex_r52/**"
|
|
|
|
jobs:
|
|
# One job rather than one per configuration, for the reason gcc_check.yml
|
|
# gives for folding its two toolchains together: the checks list stays short,
|
|
# and a single run sees every configuration so a cross-configuration
|
|
# regression shows up in one log instead of two.
|
|
r52:
|
|
runs-on: ubuntu-24.04
|
|
|
|
env:
|
|
# Pinned deliberately. Matches gcc_check.yml and ci_cortex_m.yml so all
|
|
# three share one cache entry rather than each holding its own copy of
|
|
# the same archive; change them together or the sharing silently stops.
|
|
# 14.3.rel1 is the project's GCC 14 default.
|
|
GCC_VERSION: 14.3.rel1
|
|
|
|
# Where the Armv8-R AEM FVP comes from.
|
|
#
|
|
# Arm distributes it free of charge but behind a click-through licence,
|
|
# with no stable unauthenticated download URL we can hard-code -- the
|
|
# permalink forms under developer.arm.com/-/cdn-downloads all 404 for
|
|
# this model. So the URL is a repository variable rather than a literal
|
|
# here, and the maintainer sets it once to a location the runner can
|
|
# reach (an Eclipse-hosted mirror, a release asset, or Arm's own URL if
|
|
# a durable one appears).
|
|
#
|
|
# Set FVP_AEMV8R_URL to a .tgz/.tar.gz of the model, and optionally
|
|
# FVP_AEMV8R_SHA256 to its checksum. With the checksum set the download
|
|
# is verified; without it the run says so rather than pretending.
|
|
#
|
|
# When the variable is unset the build lanes still run and still gate the
|
|
# pull request -- only execution is skipped, loudly, in the log and in
|
|
# the job summary. A silent green here would recreate the exact hole this
|
|
# workflow exists to close.
|
|
FVP_URL: ${{ vars.FVP_AEMV8R_URL }}
|
|
FVP_SHA256: ${{ vars.FVP_AEMV8R_SHA256 }}
|
|
|
|
steps:
|
|
# Actions are pinned to a commit SHA with the version in the trailing
|
|
# comment. A tag can be moved; a SHA cannot. Dependabot moves these pins
|
|
# and rewrites the comments -- see .github/dependabot.yml.
|
|
- name: Check out the repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
# Path and key match gcc_check.yml's AArch32 entry exactly, so the two
|
|
# workflows share one cache entry. Only the AArch32 toolchain is needed
|
|
# here: cortex_r52 is Armv8-R AArch32, and nothing this workflow builds
|
|
# targets aarch64.
|
|
- name: Cache the AArch32 Arm GNU toolchain
|
|
id: cache-arm32
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: toolchain
|
|
key: arm-gnu-toolchain-${{ env.GCC_VERSION }}-x86_64-arm-none-eabi
|
|
|
|
# The checksum suffix is .sha256asc and not .sha256. Arm publishes both,
|
|
# and for arm-none-eabi the .sha256 file contains a 32-character MD5, so
|
|
# sha256sum -c on it fails with "no properly formatted checksum lines
|
|
# found". Do not "simplify" the suffix. (Same note as gcc_check.yml, which
|
|
# is where it was first paid for.)
|
|
- name: Install the AArch32 Arm GNU toolchain
|
|
if: steps.cache-arm32.outputs.cache-hit != 'true'
|
|
run: |
|
|
set -eu
|
|
base="https://developer.arm.com/-/media/Files/downloads/gnu/${GCC_VERSION}/binrel"
|
|
archive="arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi.tar.xz"
|
|
mkdir -p toolchain && cd toolchain
|
|
curl -fsSLO "$base/$archive"
|
|
curl -fsSLO "$base/$archive.sha256asc"
|
|
sha256sum -c "$archive.sha256asc"
|
|
tar xf "$archive"
|
|
rm -f "$archive"
|
|
|
|
# Only reaches apt if the runner image has stopped shipping ninja. This
|
|
# repository has already paid for unguarded apt calls -- scripts/install.sh
|
|
# carries a long comment about apt-get update stalling for over two hours
|
|
# and taking whole regression runs with it. Do not make this
|
|
# unconditional.
|
|
- name: Ensure ninja is available
|
|
run: |
|
|
set -eu
|
|
if command -v ninja >/dev/null 2>&1; then
|
|
ninja --version
|
|
else
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends ninja-build
|
|
fi
|
|
|
|
# The cache key has to move when the model does, and stay put when it does
|
|
# not. hashFiles() reads files, so it cannot hash a variable: pointing it
|
|
# at this workflow keyed the cache on the file's own contents, which is
|
|
# wrong twice over -- repointing FVP_AEMV8R_URL kept serving the old model,
|
|
# and editing anything here forced a needless refetch of a large archive.
|
|
# The URL is hashed here instead, so the key tracks exactly what it names.
|
|
- name: Key the FVP cache on the download URL
|
|
id: fvp-key
|
|
if: env.FVP_URL != ''
|
|
run: |
|
|
set -eu
|
|
printf 'hash=%s\n' "$(printf '%s' "$FVP_URL" | sha256sum | cut -d' ' -f1)" >>"$GITHUB_OUTPUT"
|
|
|
|
- name: Cache the Armv8-R AEM FVP
|
|
id: cache-fvp
|
|
if: env.FVP_URL != ''
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: fvp
|
|
key: fvp-aemv8r-${{ steps.fvp-key.outputs.hash }}-${{ env.FVP_SHA256 || 'nosum' }}
|
|
|
|
- name: Install the Armv8-R AEM FVP
|
|
if: env.FVP_URL != '' && steps.cache-fvp.outputs.cache-hit != 'true'
|
|
run: |
|
|
set -eu
|
|
mkdir -p fvp && cd fvp
|
|
curl -fsSL -o fvp.tgz "$FVP_URL"
|
|
if [ -n "${FVP_SHA256:-}" ]; then
|
|
echo "$FVP_SHA256 fvp.tgz" | sha256sum -c -
|
|
else
|
|
echo "::warning::FVP_AEMV8R_SHA256 is not set; the download was not verified."
|
|
fi
|
|
tar xf fvp.tgz
|
|
rm -f fvp.tgz
|
|
|
|
# The model links against libatomic. Everything else it needs
|
|
# (libstdc++, libgcc_s, librt, libpthread) is already on the runner image,
|
|
# and its own libscxframework/libsystemc ship inside the tarball. The
|
|
# runner usually has libatomic1 by way of gcc, so this is guarded for the
|
|
# same reason the ninja step is.
|
|
- name: Ensure the FVP's runtime dependencies are present
|
|
if: env.FVP_URL != ''
|
|
run: |
|
|
set -eu
|
|
if ldconfig -p | grep -q 'libatomic\.so\.1'; then
|
|
echo "libatomic1 present"
|
|
else
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends libatomic1
|
|
fi
|
|
|
|
# Resolve the model once and hand its absolute path to CMake below.
|
|
#
|
|
# ports/cortex_r52/gnu/example_build/fvp_baser_aemv8r/CMakeLists.txt finds
|
|
# it with find_program(... HINTS $ENV{HOME}/FVP_Base_AEMv8R_11.32_19/bin),
|
|
# a hint that is right on a developer's machine and meaningless here, so
|
|
# the path is passed explicitly. find_program caches into FVP_BASER_AEMV8R,
|
|
# which means -DFVP_BASER_AEMV8R=<path> overrides it with no change to the
|
|
# CMake files.
|
|
#
|
|
# FVP_PRESENT, not a bare "did the variable exist", so that a URL which
|
|
# downloads something that is not the model fails here rather than
|
|
# silently skipping every test later.
|
|
- name: Locate the FVP
|
|
id: fvp
|
|
run: |
|
|
set -eu
|
|
if [ -z "${FVP_URL:-}" ]; then
|
|
echo "present=false" >>"$GITHUB_OUTPUT"
|
|
echo "::warning::FVP_AEMV8R_URL is not set for this repository, so the Cortex-R52 images were built but NOT executed. Set the repository variable to enable the execution lanes."
|
|
{
|
|
echo "### Cortex-R52 FVP execution: SKIPPED"
|
|
echo ""
|
|
echo "\`FVP_AEMV8R_URL\` is not set, so this run built the images but executed none of them."
|
|
echo "Set the repository variable (Settings -> Secrets and variables -> Actions -> Variables)"
|
|
echo "to a download URL for the Armv8-R AEM FVP to turn the execution lanes on."
|
|
} >>"$GITHUB_STEP_SUMMARY"
|
|
exit 0
|
|
fi
|
|
binary="$(find fvp -type f -name FVP_BaseR_AEMv8R -perm -u+x | head -1)"
|
|
if [ -z "$binary" ]; then
|
|
echo "FVP_AEMV8R_URL was set, but no FVP_BaseR_AEMv8R binary was found in the archive." >&2
|
|
find fvp -maxdepth 3 -type d | sed 's/^/ /' >&2
|
|
exit 1
|
|
fi
|
|
binary="$(cd "$(dirname "$binary")" && pwd)/$(basename "$binary")"
|
|
echo "present=true" >>"$GITHUB_OUTPUT"
|
|
echo "binary=$binary" >>"$GITHUB_OUTPUT"
|
|
"$binary" --version
|
|
|
|
# Both configurations are configured, built and (when the model is here)
|
|
# run by one script, so that adding a configuration is one line rather
|
|
# than three near-identical blocks of YAML.
|
|
#
|
|
# Every image is named explicitly from the generated ninja graph rather
|
|
# than from a list kept here. The images are EXCLUDE_FROM_ALL -- a bare
|
|
# "cmake --build" reports "no work to do" and would compare nothing --
|
|
# and reading the graph means a target added to CMakeLists.txt cannot
|
|
# escape this check by nobody remembering to list it. This is the same
|
|
# technique, and the same reasoning, as scripts/check_gcc.sh's CMake stage.
|
|
#
|
|
# TX_R52_FLOAT_ABI=hard is not optional alongside TX_R52_ENABLE_VFP: the
|
|
# port's CMakeLists.txt refuses the combination outright (#686), because
|
|
# TX_ENABLE_VFP_SUPPORT enables VMRS/VSTMDB/VLDMIA blocks that a soft
|
|
# float ABI leaves the assembler unable to accept.
|
|
- name: Build and run the Cortex-R52 images
|
|
run: |
|
|
set -eu
|
|
export PATH="$GITHUB_WORKSPACE/toolchain/arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi/bin:$PATH"
|
|
arm-none-eabi-gcc --version | head -1
|
|
|
|
fvp_present='${{ steps.fvp.outputs.present }}'
|
|
fvp_binary='${{ steps.fvp.outputs.binary }}'
|
|
|
|
fvp_arg=""
|
|
if [ "$fvp_present" = "true" ]; then
|
|
fvp_arg="-DFVP_BASER_AEMV8R=$fvp_binary"
|
|
fi
|
|
|
|
status=0
|
|
|
|
run_configuration() {
|
|
name="$1"; shift
|
|
build="build/$name"
|
|
|
|
echo ""
|
|
echo "=============================================================="
|
|
echo "== $name"
|
|
echo "=============================================================="
|
|
|
|
if ! cmake -S . -B "$build" -G Ninja \
|
|
-DCMAKE_TOOLCHAIN_FILE=cmake/cortex_r52.cmake \
|
|
$fvp_arg "$@"; then
|
|
echo "::error::$name: CMake configure failed"
|
|
status=1
|
|
return
|
|
fi
|
|
|
|
images="$(ninja -C "$build" -t targets all 2>/dev/null \
|
|
| grep -oE '^[A-Za-z0-9_]+\.elf' \
|
|
| grep -v '^cmake_' | sort -u)"
|
|
if [ -z "$images" ]; then
|
|
echo "::error::$name: no .elf targets found in the CMake graph"
|
|
status=1
|
|
return
|
|
fi
|
|
|
|
echo "$name: building $(echo "$images" | wc -l) images"
|
|
# shellcheck disable=SC2086
|
|
if ! cmake --build "$build" --target $images; then
|
|
echo "::error::$name: one or more images did not build"
|
|
status=1
|
|
return
|
|
fi
|
|
|
|
if [ "$fvp_present" != "true" ]; then
|
|
echo "$name: built, not executed (no FVP configured)"
|
|
return
|
|
fi
|
|
|
|
# --no-tests=error, because ctest's default is to report success
|
|
# when it finds nothing to run. The example registers its tests
|
|
# inside if(FVP found) and if(Python3_FOUND), so either one going
|
|
# unmet would leave this stage green having executed nothing -- the
|
|
# very hole this workflow exists to close.
|
|
if ! ctest --test-dir "$build" --output-on-failure --no-tests=error; then
|
|
echo "::error::$name: one or more images failed on the FVP, or no tests were registered"
|
|
status=1
|
|
fi
|
|
}
|
|
|
|
run_configuration default \
|
|
-DTX_R52_BUILD_FVP_EXAMPLE=ON
|
|
|
|
run_configuration feature \
|
|
-DTX_R52_BUILD_FVP_EXAMPLE=ON \
|
|
-DTX_R52_ENABLE_VFP=ON \
|
|
-DTX_R52_FLOAT_ABI=hard \
|
|
-DTX_R52_ENABLE_FIQ=ON \
|
|
-DTX_R52_ENABLE_IRQ_NESTING=ON \
|
|
-DTX_R52_ENABLE_FIQ_NESTING=ON
|
|
|
|
exit $status
|