From b3a2f0992f256db39fb8e1ef3d58e2b73c398efe Mon Sep 17 00:00:00 2001 From: Yu-En Hsiao Date: Sat, 24 Jan 2026 22:39:18 +0800 Subject: [PATCH 1/3] Adjust rules for enabling native execution The original build system automatically uses qemu-arm to run the compiler when targeting Arm32 if the native environment is not armv7l. However, some machines with armv8 or newer architectures, such as Raspberry Pi 3 through Raspberry Pi 5, are also capable of performing native execution. Additionally, GitHub's Arm64 runners can also perform as well. Therefore, This commit updates the build system to detect the host machine and enable native execution when it is supported. --- Makefile | 2 +- mk/arm.mk | 43 +++++++++++++++++++++++++++++++++++++++++-- mk/common.mk | 2 +- mk/riscv.mk | 4 ++-- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 0c6c47ff..f79d6650 100644 --- a/Makefile +++ b/Makefile @@ -36,10 +36,10 @@ STAGE0 := shecc STAGE1 := shecc-stage1.elf STAGE2 := shecc-stage2.elf +USE_QEMU ?= 1 OUT ?= out ARCHS = arm riscv ARCH ?= $(firstword $(ARCHS)) -HOST_ARCH = $(shell arch 2>/dev/null) SRCDIR := $(shell find src -type d) LIBDIR := $(shell find lib -type d) diff --git a/mk/arm.mk b/mk/arm.mk index 3fcda4a9..53fe0899 100644 --- a/mk/arm.mk +++ b/mk/arm.mk @@ -1,4 +1,10 @@ -ARCH_NAME = armv7l +# Allow the following machines to use native execution +# +# - Beaglebone Black (Cortex-A8) +# - Raspberry Pi 3 (Cortex-A53) +# - Raspberry Pi 4 (Cortex-A72) +# - Raspberry Pi 5 (Cortex-A76) +ALLOW_MACHINES = BeagleBone-Black Raspberry-Pi-3 Raspberry-Pi-4 Raspberry-Pi-5 ARCH_RUNNER = qemu-arm ARCH_DEFS = \ "/* target: ARM */\n$\ @@ -14,6 +20,39 @@ ARCH_DEFS = \ \#define MAX_ARGS_IN_REG 4\n$\ " +# If the running machine has the "fastfetch" tool installed, the build +# system will verify whether native execution can be performed. +ifneq ($(shell which fastfetch),) + # 1. Replace whitespaces with hyphens after retrieving the host + # machine name via the "fastfetch" tool. + # + # 2. If at least one machine name in the allowlist is found in + # the host machine name, it can perform native execution. + # + # Therefore, set USE_QEMU to 0. + HOST_MACHINE = $(shell fastfetch --logo none --structure Host | sed 's/ /-/g') + USE_QEMU = $(if $(strip $(foreach MACHINE, $(ALLOW_MACHINES), $(findstring $(MACHINE),$(HOST_MACHINE)))),0,1) + + # Special case: GitHub workflows on Arm64 runners + # + # When an Arm-hosted runner executes "fastfetch --logo none --structure Host", + # it produces the following output: + # + # Host: Virtual Machine (Hyper-V UEFI Release v4.1) + # + # Arm-hosted runners are also capable of performing native execution. However, + # directly adding "Virtual-Machine" to the allowlist would be ambiguous. + # Therefore, the build system instead checks the CPU name using the + # "fastfetch --logo none --structure CPU" command. + # + # If the detected CPU is "Neoverse-N2", the build system treats the running + # machine as an Arm-hosted runner and enable native execution. + ifeq ($(USE_QEMU),1) + HOST_CPU = $(shell fastfetch --logo none --structure CPU | sed 's/ /-/g') + USE_QEMU = $(if $(strip $(findstring Neoverse-N2,$(HOST_CPU))),0,1) + endif +endif + # Find the sysroot of the ARM GNU toolchain if using dynamic linking. # # Since developers may install the toolchain manually instead of @@ -23,7 +62,7 @@ ARCH_DEFS = \ # Therefore, the following process first locates find the correct # sysroot of the toolchain, and then generate the ELF interpreter # prefix for later use. -ifneq ($(HOST_ARCH),$(ARCH_NAME)) +ifeq ($(USE_QEMU),1) ifeq ($(DYNLINK),1) CROSS_COMPILE = arm-none-linux-gnueabihf- ARM_CC = $(CROSS_COMPILE)gcc diff --git a/mk/common.mk b/mk/common.mk index 079ea803..ef47ee0f 100644 --- a/mk/common.mk +++ b/mk/common.mk @@ -25,7 +25,7 @@ pass = $(PRINTF) "$(PASS_COLOR)$1 Passed$(NO_COLOR)\n" # Check the prerequisites PREREQ_LIST := dot jq TARGET_EXEC ?= -ifneq ($(HOST_ARCH),$(ARCH_NAME)) +ifeq ($(USE_QEMU),1) # Add qemu to the list if the host and target architectures differ PREREQ_LIST += $(ARCH_RUNNER) ifeq ($(filter $(ARCH_RUNNER),$(notdir $(shell which $(ARCH_RUNNER)))),) diff --git a/mk/riscv.mk b/mk/riscv.mk index 445fcfa8..536d2c0e 100644 --- a/mk/riscv.mk +++ b/mk/riscv.mk @@ -1,5 +1,5 @@ -# Enforce the use qemu of by setting the ARCH_NAME variable to empty -ARCH_NAME = +# Enforce the use qemu of by setting the ALLOW_MACHINES variable to empty +ALLOW_MACHINES = ARCH_RUNNER = qemu-riscv32 ARCH_DEFS = \ "/* target: RISCV */\n$\ From 3391d793a277df510e8efe2c6cf400859b0c2925 Mon Sep 17 00:00:00 2001 From: Yu-En Hsiao Date: Sun, 8 Feb 2026 00:05:34 +0800 Subject: [PATCH 2/3] Add descriptions of native execution Since a previous commit modified the rules for determining when QEMU is used, this commit adds related descriptions to the README to explain how developers can make the build system verify whether native execution can be performed. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 5141c230..b9699b1f 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,11 @@ emulation on GNU/Linux: $ sudo apt-get install qemu-user ``` +The build system is able to verify whether the running machine can perform native +execution without QEMU. The host machine may install the prebuilt +[fastfetch](https://github.com/fastfetch-cli/fastfetch/), which allows the build +system to determine whether native execution can be enabled. + It is still possible to build `shecc` on macOS or Microsoft Windows. However, the second stage bootstrapping would fail due to `qemu-arm` absence. From fa62d30f3b106a0cf8ab5526c093cb05be38da67 Mon Sep 17 00:00:00 2001 From: Yu-En Hsiao Date: Sat, 24 Jan 2026 23:03:19 +0800 Subject: [PATCH 3/3] Use Arm64 runners to validate native bootstrapping and run test cases Since the build system has been updated to allow native execution on Arm-hosted runners, this commit improves the workflow definitions by running the "host-arm" job on Arm64 runners to perform validation. As a result of these changes, the "host-arm" job no longer uses "run-on-arch-action". --- .github/workflows/main.yml | 55 +++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7db6fe4a..a8e2ef9d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,37 +55,44 @@ jobs: make check DYNLINK=${{ steps.determine-mode.outputs.DYNLINK }} || exit 1 host-arm: - runs-on: ubuntu-24.04 + runs-on: ubuntu-24.04-arm strategy: matrix: link_mode: [static, dynamic] steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Determine static or dynamic linking mode - id: determine-mode - run: | - if [ "${{ matrix.link_mode }}" = "dynamic" ]; then - echo "Use dynamic linking mode" - echo "DYNLINK=1" >> "$GITHUB_OUTPUT" - else - echo "Use static linking mode" - echo "DYNLINK=0" >> "$GITHUB_OUTPUT" - fi - - name: Build artifacts - # The GitHub Action for non-x86 CPU - # https://github.com/uraimo/run-on-arch-action - uses: uraimo/run-on-arch-action@v3 - with: - arch: armv7 - distro: ubuntu24.04 - githubToken: ${{ github.token }} - install: | - apt-get update -qq -y - apt-get install -yqq build-essential + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download dependencies + run: | + sudo dpkg --add-architecture armhf + sudo apt-get update -q -y + sudo apt-get install -q -y graphviz jq + sudo apt-get install -q -y build-essential libc6:armhf + sudo wget https://github.com/fastfetch-cli/fastfetch/releases/download/2.58.0/fastfetch-linux-aarch64.deb + sudo dpkg -i fastfetch-linux-aarch64.deb + + - name: Determine static or dynamic linking mode + id: determine-mode + run: | + if [ "${{ matrix.link_mode }}" = "dynamic" ]; then + echo "Use dynamic linking mode" + echo "DYNLINK=1" >> "$GITHUB_OUTPUT" + else + echo "Use static linking mode" + echo "DYNLINK=0" >> "$GITHUB_OUTPUT" + fi + + - name: Build artifacts run: | make ARCH=arm DYNLINK=${{ steps.determine-mode.outputs.DYNLINK }} + + - name: Sanitizer-enabled stage 0 tests + run: | make check-sanitizer DYNLINK=${{ steps.determine-mode.outputs.DYNLINK }} || exit 1 + + - name: Unit tests + run: | make check DYNLINK=${{ steps.determine-mode.outputs.DYNLINK }} || exit 1 preprocessor-host: