name: gcc_check # Builds the Arm ports with the Arm GNU 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. # # Why this exists: GCC 14 on Linux is the project's default compiler, it is # what the gnu ports exist for, and until this workflow landed, nothing in CI # compiled a line of any port with it. The only cross-compilation check that # ran was clang_check, so the LLVM path was better guarded than the GNU one, # on ports whose directory is literally named gnu. # # What it covers: 840 assembly sources across 40 port families, 469 of them # again behind feature macros, common/src for nine cores, 302 module manager C # files across the nine Arm module ports, 42 script-driven example links and # the five Cortex-R52 CMake images. Every skip is printed by name with a reason # -- run scripts/check_gcc.sh --help, or read its header. # # What it does not cover: it compiles and links and **executes nothing**. The # Cortex-R52 FVP ctest suite is not part of it. RISC-V, MIPS, RX and ARC are # outside it entirely -- RISC-V deliberately, and now for a stronger reason # than when this was written: regression_test.yml builds both its ports and # runs 955 tests on them under QEMU, which is more than a compile check could # say. Adding them here would widen this workflow's toolchain download by about # a gigabyte to re-prove a subset of that. # # It does not supersede cortex_m. That workflow builds four ports *through # CMake*, which is the only thing exercising cmake/cortex_m*.cmake and the # top-level CMakeLists for the M profile; this script's CMake stage covers # cortex_r52 only. The overlap is the assembly and the C sources, not the build # system. on: # push as well as pull_request, so dev's own history has a baseline and a bad # squash-merge is caught rather than waiting for the next PR to notice. dev is # named because it is the integration branch: a workflow that triggers only on # master does not gate any pull request anybody opens, which is the defect # ports_arch_check.yml carries a comment about and which cost cortex_m three # months of failing in seven seconds unnoticed. push: branches: [ master, dev ] paths: - ".github/workflows/gcc_check.yml" - "scripts/check_gcc.sh" - "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/**" - "ports_module/**" - "ports_smp/**" pull_request: branches: [ master, dev ] # The two lists are duplicated rather than shared through a YAML anchor. # GitHub Actions' workflow parser does not dependably honour anchors, and # the failure mode is the whole workflow refusing to parse -- which is the # cortex_m failure again, a job that dies before it does anything. Ten # duplicated lines are cheaper than that. **Edit both.** # # common_smp, CMakeLists.txt and cmake/ are here and are absent from # clang_check.yml's otherwise identical list, which is a gap in that file # and is fixed alongside this one: the ports_smp example builds compile # common_smp/src, and the CMake stage reads the toolchain file and the # top-level project. utility/ is deliberately absent -- the FreeRTOS and # POSIX layers under it are not enabled by any target this workflow builds. paths: - ".github/workflows/gcc_check.yml" - "scripts/check_gcc.sh" - "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/**" - "ports_module/**" - "ports_smp/**" jobs: gnu: runs-on: ubuntu-24.04 env: # Pinned deliberately, as the runner image is: a toolchain upgrade should # be a reviewable commit rather than something that changes underneath the # ports. 14.3.rel1 is the GCC 14 the project builds against, and the # version cortex_m already pins. # Releases: https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads GCC_VERSION: 14.3.rel1 steps: # Actions are pinned to a commit SHA, with the version in the trailing # comment. A tag can be moved; a SHA cannot, so this is what makes "which # code ran in CI" answerable from the repository. Dependabot moves these # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Two toolchains, because Arm ships AArch32 and AArch64 as separate # downloads and scripts/check_gcc.sh needs both -- every port maps to one of # exactly those two triples. One job with two cache steps rather than two # jobs, so the checks list stays short and a single script invocation sees # both compilers. # # The AArch32 path and key match cortex_m's exactly, so the two workflows # share one cache entry rather than each holding its own copy of the same # 500MB archive. Change them together or the sharing silently stops and the # only symptom is a slower run. - 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 - name: Cache the AArch64 Arm GNU toolchain id: cache-arm64 uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: toolchain64 key: arm-gnu-toolchain-${{ env.GCC_VERSION }}-x86_64-aarch64-none-elf # The checksum suffix is .sha256asc and not .sha256, and that is not a # stylistic choice. Arm publishes both for this release, and for # arm-none-eabi the .sha256 file contains a 32-character MD5 rather than a # SHA-256 -- verified 26 Aug 2026 -- so sha256sum -c on it fails with "no # properly formatted checksum lines found". .sha256asc is a plain # sha256sum-format line for both triples. Do not "simplify" the suffix. - 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" - name: Install the AArch64 Arm GNU toolchain if: steps.cache-arm64.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-aarch64-none-elf.tar.xz" mkdir -p toolchain64 && cd toolchain64 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, which # the CMake stage needs. 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 turn this into an unconditional install. - 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 script is told where both toolchains are rather than being left to # find them on PATH, so nothing about the runner image can decide which # compiler is used. The script prints both versions it resolved, which is # what makes "was this really 14.3.rel1?" answerable from the log. - name: Build the Arm ports with GCC run: | scripts/check_gcc.sh \ --arm-none-eabi "$GITHUB_WORKSPACE/toolchain/arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi/bin" \ --aarch64-none-elf "$GITHUB_WORKSPACE/toolchain64/arm-gnu-toolchain-${GCC_VERSION}-x86_64-aarch64-none-elf/bin"