#!/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 ############################################################################## set -e # POSIX compatibility layer regression test build/test runner. # Usage: run.sh [all| ...] # arch: riscv32 # # Only riscv32 is available: the layer cannot carry a 64-bit message pointer # without TX_64_BIT, and TX_64_BIT needs a port that declares # tx_thread_extension_ptr. See the comment in ../CMakeLists.txt. function help() { echo "Usage: $0 [all| ...]" echo "" echo " arch: riscv32" echo " command: build | test" echo "" echo "Available build configurations:" for build in ${build_configurations[*]}; do echo " $build" done exit 1 } function validate() { for build in ${build_configurations[*]}; do if [ "$1" == "$build" ]; then return fi done help } function generate() { local arch=$1 local build=$2 local toolchain_file local build_dir toolchain_file="${REPO_ROOT}/cmake/riscv32_gnu.cmake" build_dir="build/${arch}_${build}" cmake -B"$build_dir" -GNinja \ -DCMAKE_TOOLCHAIN_FILE="$toolchain_file" \ -DCMAKE_BUILD_TYPE="$build" \ . } function build() { local arch=$1 local build=$2 # -k 0 keeps Ninja going after a target fails, so one broken target no # longer decides whether the targets after it exist. ctest reports a # missing binary as a failing test, which turned a single link error into # a failure count that varied with build scheduling order. cmake --build "build/${arch}_${build}" -- -k 0 } function run_test() { local arch=$1 local build=$2 local parallel_jobs=$3 # Guard the pushd: with the caller capturing this function's status, set -e # no longer aborts here, so a missing build directory would otherwise let # ctest run in the source tree and report "no tests" as success. pushd "build/${arch}_${build}" || return 1 [ -z "${CTEST_PARALLEL_LEVEL}" ] && parallel="-j${parallel_jobs}" if [ -z "${CTEST_REPEAT_FAIL}" ]; then repeat_fail=2 else repeat_fail=${CTEST_REPEAT_FAIL} fi # ctest's status is captured and returned past the popd and the summary # steps, which all succeed. Without this the function would return 0 and a # failing configuration would be reported as a pass. local status=0 ctest $parallel --timeout 1000 \ -O "${arch}_${build}.txt" \ -T test --no-compress-output \ --test-output-size-passed 4194304 \ --test-output-size-failed 4194304 \ --output-on-failure \ --repeat until-pass:${repeat_fail} \ --output-junit "${arch}_${build}.xml" || status=$? popd return $status } # Determine repo root and script directory SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" cd "$SCRIPT_DIR" # Parse build configurations from CMakeLists.txt result=$(sed -n "/(BUILD_CONFIGURATIONS/,/)/p" CMakeLists.txt | sed ':label;N;s/\n/ /;b label' | grep -Pzo "[a-zA-Z0-9_]*build[a-zA-Z0-9_]*\s*" | tr -d '\0') IFS=' ' read -ra build_configurations <<< "$result" if [ $# -lt 2 ]; then help fi arch=$1 shift if [ "$arch" != "riscv32" ]; then echo "Error: arch must be 'riscv32'" help fi command=$1 shift if [ "$#" == "0" ]; then builds=${build_configurations[0]} elif [ "$*" == "all" ]; then builds=${build_configurations[@]} else for item in $*; do validate "$item" done builds=$* fi if [ "$command" == "build" ]; then for item in $builds; do generate "$arch" "$item" echo "" done # A failing configuration must not stop the ones after it: under set -e # the loop would abort and leave them unbuilt, which then reads as a wall # of missing-binary test failures. The status is accumulated and returned. build_status=0 for item in $builds; do echo "Building ${arch} ${item}" build "$arch" "$item" || build_status=$? echo "" done [ $build_status -eq 0 ] || exit $build_status elif [ "$command" == "test" ]; then cores=$(nproc) if [ -z "${CTEST_PARALLEL_LEVEL}" ]; then build_counts=$(echo $builds | wc -w) parallel_jobs=$(($cores / $build_counts)) parallel_jobs=$(($parallel_jobs + 2)) pids="" for item in $builds; do echo "Testing ${arch} ${item}" run_test "$arch" "$item" "$parallel_jobs" & pids+=" $!" done exit_code=0 for p in $pids; do wait $p || exit_code=$? done exit $exit_code else # ctest's status is accumulated rather than allowed to abort the loop. # set -e would otherwise stop at the first failing configuration and # leave every configuration after it untested. This mirrors what the # parallel branch above already does with wait. exit_code=0 for item in $builds; do echo "Testing ${arch} ${item}" run_test "$arch" "$item" "$parallel_jobs" || exit_code=$? done exit $exit_code fi else help fi