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: 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/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. 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$\