From d4f490f1ad437f805627d005f06a9eebf20178d4 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 12 Jun 2024 10:44:11 +0100 Subject: [PATCH] Support host builds using clang toolchain (#2798) This PR adds the `CLANG_BUILD` for host builds. The toolchain detection logic is in the main build.mk file as there might be future support for clang toolchains for actual devices. It's also a revision to the existing logic which checks GCC compiler version. Try it out using `make SMING_SOC=host CLANG_BUILD=1`. To build with a specific (installed) version of clang, for example clang-15, use `CLANG_BUILD=15` . Further customisation can be made by editing `Sming/Arch/Host/build.mk`. Clang-tidy support (#2648) is also improved as there are some compiler flag differences between GCC and clang which are now shared between CLANG_TIDY and CLANG_BUILD operation. An extra CI build has been added using clang. Further to #2773, the default toolchain for macos is a version of clang (Apple Clang). This PR doesn't quite support that because there are other issues to address, but it's a step in the right direction. --- .github/workflows/ci.yml | 6 +++ .github/workflows/library.yml | 6 +++ Sming/Arch/Host/README.rst | 13 ++++++ Sming/Arch/Host/build.mk | 21 +++++++++ Sming/Libraries/DiskStorage | 2 +- Sming/Libraries/FlashIP | 2 +- Sming/Libraries/GoogleCast | 2 +- Sming/Libraries/Graphics | 2 +- Sming/Libraries/HueEmulator | 2 +- Sming/Libraries/RingTone | 2 +- Sming/Libraries/USB | 2 +- Sming/Libraries/jerryscript | 2 +- Sming/build.mk | 61 ++++++++++++++++++--------- Sming/component-wrapper.mk | 8 +--- Sming/project.mk | 1 + samples/Basic_Ota/app/application.cpp | 4 +- samples/LiveDebug/app/application.cpp | 4 +- 17 files changed, 102 insertions(+), 38 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f565d8a942..9d9fb17b35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,11 +13,16 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] variant: [esp8266, host, rp2040] + toolchain: [gcc] include: - variant: esp8266 arch: Esp8266 - variant: host arch: Host + - os: ubuntu-latest + variant: host + arch: Host + toolchain: clang - variant: rp2040 arch: Rp2040 @@ -30,6 +35,7 @@ jobs: env: SMING_ARCH: ${{ matrix.arch }} SMING_SOC: ${{ matrix.variant }} + CLANG_BUILD: ${{ matrix.toolchain == 'clang' && '15' || '0' }} steps: - name: Fix autocrlf setting diff --git a/.github/workflows/library.yml b/.github/workflows/library.yml index 44c6f6c4f8..7ae69a023b 100644 --- a/.github/workflows/library.yml +++ b/.github/workflows/library.yml @@ -24,11 +24,16 @@ jobs: os: [ubuntu-latest, windows-latest] variant: [esp8266, host, esp32, esp32s2, esp32c3, esp32s3, esp32c2, rp2040] idf_version: ["4.4", ""] # "" denotes default, currently 5.2 + toolchain: [gcc] include: - variant: esp8266 arch: Esp8266 - variant: host arch: Host + - os: ubuntu-latest + variant: host + arch: Host + toolchain: clang - variant: esp32 arch: Esp32 - variant: esp32s2 @@ -61,6 +66,7 @@ jobs: SMING_ARCH: ${{ matrix.arch }} SMING_SOC: ${{ matrix.variant }} INSTALL_IDF_VER: ${{ matrix.idf_version }} + CLANG_BUILD: ${{ matrix.toolchain == 'clang' && '15' || '0' }} steps: - name: Fix autocrlf setting diff --git a/Sming/Arch/Host/README.rst b/Sming/Arch/Host/README.rst index d4fc206122..92718875e0 100644 --- a/Sming/Arch/Host/README.rst +++ b/Sming/Arch/Host/README.rst @@ -25,6 +25,9 @@ Ensure you are using relatively recent compilers, with 32-bit libraries availabl For Linux, you may require the ``gcc-multilib`` and ``g++-multilib`` packages to build 32-bit executables on a 64-bit OS. +MacOS comes pre-installed with ``Apple Clang`` as the standard toolchain. +This should be sufficient to build Sming in Host mode. + For Windows, make sure your ``MinGW`` distro is up to date. See :doc:`/getting-started/windows/index` for further details. @@ -58,6 +61,16 @@ Configuration Note: These settings are not 'sticky' + +.. envvar:: CLANG_BUILD + + 0: Use GCC (default) + 1: Use standard ``clang`` + N: Use specific installed version, ``clang-N`` + + Note: This setting is not 'sticky' + + Components ---------- diff --git a/Sming/Arch/Host/build.mk b/Sming/Arch/Host/build.mk index ba2380bae1..2129b2e506 100644 --- a/Sming/Arch/Host/build.mk +++ b/Sming/Arch/Host/build.mk @@ -8,6 +8,25 @@ CPPFLAGS += -DARCH_HOST TOOLSPEC := +ifndef CLANG_BUILD +override CLANG_BUILD := 0 +endif + +ifneq ($(CLANG_BUILD),0) +ifeq ($(CLANG_BUILD),1) +CLANG_VER := +else +CLANG_VER := -$(CLANG_BUILD) +endif +AS := $(TOOLSPEC)clang$(CLANG_VER) +CC := $(TOOLSPEC)clang$(CLANG_VER) +CXX := $(TOOLSPEC)clang++$(CLANG_VER) +AR := $(TOOLSPEC)ar +LD := $(TOOLSPEC)clang++$(CLANG_VER) +NM := $(TOOLSPEC)nm +OBJCOPY := $(TOOLSPEC)objcopy +OBJDUMP := $(TOOLSPEC)objdump +else AS := $(TOOLSPEC)gcc CC := $(TOOLSPEC)gcc CXX := $(TOOLSPEC)g++ @@ -16,6 +35,8 @@ LD := $(TOOLSPEC)g++ NM := $(TOOLSPEC)nm OBJCOPY := $(TOOLSPEC)objcopy OBJDUMP := $(TOOLSPEC)objdump +endif + GDB := $(TOOLSPEC)gdb GCC_UPGRADE_URL := https://sming.readthedocs.io/en/latest/arch/host/host-emulator.html\#c-c-32-bit-compiler-and-libraries diff --git a/Sming/Libraries/DiskStorage b/Sming/Libraries/DiskStorage index 6bfcd80140..f545e91216 160000 --- a/Sming/Libraries/DiskStorage +++ b/Sming/Libraries/DiskStorage @@ -1 +1 @@ -Subproject commit 6bfcd80140f1436f6da90d6ab6a438903f8fa752 +Subproject commit f545e91216d2cc94153e29ef41de87bd1cde2e8c diff --git a/Sming/Libraries/FlashIP b/Sming/Libraries/FlashIP index 820d08aab8..1e67f9a47d 160000 --- a/Sming/Libraries/FlashIP +++ b/Sming/Libraries/FlashIP @@ -1 +1 @@ -Subproject commit 820d08aab817dde262d5d5f9fb453dca88b374e9 +Subproject commit 1e67f9a47d9e9f479c1b2c34d36800994515c8c2 diff --git a/Sming/Libraries/GoogleCast b/Sming/Libraries/GoogleCast index 83ad9974fd..4a95b75612 160000 --- a/Sming/Libraries/GoogleCast +++ b/Sming/Libraries/GoogleCast @@ -1 +1 @@ -Subproject commit 83ad9974fd80b048aec88bcc84a939f4cb0500bf +Subproject commit 4a95b756127799ef25697fa6bca28c35094eec52 diff --git a/Sming/Libraries/Graphics b/Sming/Libraries/Graphics index 1809db3740..89d315bdaf 160000 --- a/Sming/Libraries/Graphics +++ b/Sming/Libraries/Graphics @@ -1 +1 @@ -Subproject commit 1809db3740086700d895e1c0b3c5a7b632c4e210 +Subproject commit 89d315bdaf45ea9b75692a8f21e07376fa6d72ba diff --git a/Sming/Libraries/HueEmulator b/Sming/Libraries/HueEmulator index 9c275794b9..af80123b02 160000 --- a/Sming/Libraries/HueEmulator +++ b/Sming/Libraries/HueEmulator @@ -1 +1 @@ -Subproject commit 9c275794b958e68ea67ebfd974f9189dfd36b695 +Subproject commit af80123b02937df710fd515b989ea688c0ef2c7f diff --git a/Sming/Libraries/RingTone b/Sming/Libraries/RingTone index 27abfdae6e..12b438adb4 160000 --- a/Sming/Libraries/RingTone +++ b/Sming/Libraries/RingTone @@ -1 +1 @@ -Subproject commit 27abfdae6ea684646be347cbfbf757d9882cc0bb +Subproject commit 12b438adb417983263425dc2895e9cb0a8f96e69 diff --git a/Sming/Libraries/USB b/Sming/Libraries/USB index 2e3e524172..52424de587 160000 --- a/Sming/Libraries/USB +++ b/Sming/Libraries/USB @@ -1 +1 @@ -Subproject commit 2e3e524172505835bca270dc7f198034bab01a10 +Subproject commit 52424de587e636f36b2cdaa345e88de37075cddc diff --git a/Sming/Libraries/jerryscript b/Sming/Libraries/jerryscript index c8f24895a5..21ac3e053d 160000 --- a/Sming/Libraries/jerryscript +++ b/Sming/Libraries/jerryscript @@ -1 +1 @@ -Subproject commit c8f24895a59ff64e9bba212946dcf2dad504b27a +Subproject commit 21ac3e053d2a63ebc1955f2a62c2978c7447e119 diff --git a/Sming/build.mk b/Sming/build.mk index 8d482cceae..99b31cba90 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -30,6 +30,7 @@ ifdef CLANG_TIDY ifneq (Host,$(SMING_ARCH)) $(error CLANG_TIDY supported only for Host architecture.) endif +USE_CLANG := 1 endif export SMING_ARCH @@ -157,18 +158,10 @@ endif # Common C/C++ flags passed to user libraries CPPFLAGS = \ - -Wl,-EL \ -finline-functions \ -fdata-sections \ -ffunction-sections \ - -D_POSIX_C_SOURCE=200809L - -# Required to access peripheral registers using structs -# e.g. `uint32_t value: 8` sitting at a byte or word boundary will be 'optimised' to -# an 8-bit fetch/store instruction which will not work; it must be a full 32-bit access. -CPPFLAGS += -fstrict-volatile-bitfields - -CPPFLAGS += \ + -D_POSIX_C_SOURCE=200809L \ -Wall \ -Wpointer-arith \ -Wno-comment \ @@ -216,9 +209,41 @@ include $(ARCH_BASE)/build.mk ifndef MAKE_CLEAN -# Detect compiler version -DEBUG_VARS += GCC_VERSION -GCC_VERSION := $(shell $(CC) -dumpversion) +# Detect compiler version and name +DEBUG_VARS += COMPILER_VERSION_FULL COMPILER_VERSION COMPILER_NAME +COMPILER_VERSION_FULL := $(shell $(CC) -v 2>&1 | $(AWK) -F " version " '/ version /{ a=$$1; gsub(/ +/, "-", a); print a, $$2}') +COMPILER_NAME := $(word 1,$(COMPILER_VERSION_FULL)) +COMPILER_VERSION := $(word 2,$(COMPILER_VERSION_FULL)) + +ifndef USE_CLANG +# Required to access peripheral registers using structs +# e.g. `uint32_t value: 8` sitting at a byte or word boundary will be 'optimised' to +# an 8-bit fetch/store instruction which will not work; it must be a full 32-bit access. +ifeq ($(COMPILER_NAME),gcc) +CPPFLAGS += -fstrict-volatile-bitfields +COMPILER_VERSION_MIN := 8 +else +ifeq (,$(findstring clang,$(COMPILER_NAME))) +$(error Compiler '$(COMPILER_VERSION_FULL)' not recognised. Please install GCC tools.) +endif +COMPILER_VERSION_MIN := 15 +ifndef COMPILER_NOTICE_PRINTED +$(info Note: Building with $(COMPILER_NAME) $(COMPILER_VERSION).) +COMPILER_NOTICE_PRINTED := 1 +endif +USE_CLANG := 1 +endif +endif + +ifdef USE_CLANG +CPPFLAGS += \ + -Wno-vla-extension \ + -Wno-unused-private-field \ + -Wno-bitfield-constant-conversion \ + -Wno-unknown-pragmas \ + -Wno-initializer-overrides +endif + # Use c11 by default. Every architecture can override it DEBUG_VARS += SMING_C_STD @@ -227,21 +252,17 @@ CFLAGS += -std=$(SMING_C_STD) # Select C++17 if supported, defaulting to C++11 otherwise DEBUG_VARS += SMING_CXX_STD -ifeq ($(GCC_VERSION),4.8.5) -SMING_CXX_STD ?= c++11 -else SMING_CXX_STD ?= c++17 -endif CXXFLAGS += -std=$(SMING_CXX_STD) -GCC_MIN_MAJOR_VERSION := 8 -GCC_VERSION_COMPATIBLE := $(shell expr $$(echo $(GCC_VERSION) | cut -f1 -d.) \>= $(GCC_MIN_MAJOR_VERSION)) +COMPILER_VERSION_MAJOR := $(firstword $(subst ., ,$(COMPILER_VERSION))) +COMPILER_VERSION_COMPATIBLE := $(shell expr $(COMPILER_VERSION_MAJOR) \>= $(COMPILER_VERSION_MIN)) -ifeq ($(GCC_VERSION_COMPATIBLE),0) +ifeq ($(COMPILER_VERSION_COMPATIBLE),0) ifneq ($(GCC_UPGRADE_URL),) $(info Instructions for upgrading your compiler can be found here: $(GCC_UPGRADE_URL)) endif -$(error Please, upgrade your GCC compiler to version $(GCC_MIN_MAJOR_VERSION) or newer.) +$(error Please upgrade your compiler to $(COMPILER_NAME) $(COMPILER_VERSION_MIN) or newer) endif endif diff --git a/Sming/component-wrapper.mk b/Sming/component-wrapper.mk index 320399dda5..88aca58d41 100644 --- a/Sming/component-wrapper.mk +++ b/Sming/component-wrapper.mk @@ -120,10 +120,6 @@ endif # Additional flags to pass to clang CLANG_FLAG_EXTRA ?= -# Flags which clang doesn't recognise -CLANG_FLAG_UNKNOWN := \ - -fstrict-volatile-bitfields - # $1 -> absolute source directory, no trailing path separator # $2 -> relative output build directory, with trailing path separator define GenerateCompileTargets @@ -142,7 +138,7 @@ ifneq (,$(filter $1/%.c,$(SOURCE_FILES))) ifdef CLANG_TIDY $2%.o: $1/%.c $(vecho) "TIDY $$<" - $(Q) $(CLANG_TIDY) $$< -- $(addprefix -I,$(INCDIR)) $$(filter-out $(CLANG_FLAG_UNKNOWN),$(CPPFLAGS) $(CFLAGS)) $(CLANG_FLAG_EXTRA) + $(Q) $(CLANG_TIDY) $$< -- $(addprefix -I,$(INCDIR)) $(CPPFLAGS) $(CFLAGS) $(CLANG_FLAG_EXTRA) else $2%.o: $1/%.c $2%.c.d $(vecho) "CC $$<" @@ -156,7 +152,7 @@ ifneq (,$(filter $1/%.cpp,$(SOURCE_FILES))) ifdef CLANG_TIDY $2%.o: $1/%.cpp $(vecho) "TIDY $$<" - $(Q) $(CLANG_TIDY) $$< -- $(addprefix -I,$(INCDIR)) $$(filter-out $(CLANG_FLAG_UNKNOWN),$(CPPFLAGS) $(CXXFLAGS)) $(CLANG_FLAG_EXTRA) + $(Q) $(CLANG_TIDY) $$< -- $(addprefix -I,$(INCDIR)) $(CPPFLAGS) $(CXXFLAGS) $(CLANG_FLAG_EXTRA) else $2%.o: $1/%.cpp $2%.cpp.d $(vecho) "C+ $$<" diff --git a/Sming/project.mk b/Sming/project.mk index 412a56ff07..cf928ea1b0 100644 --- a/Sming/project.mk +++ b/Sming/project.mk @@ -100,6 +100,7 @@ LIBS := $(EXTRA_LIBS) # Common linker flags LDFLAGS = \ + -Wl,-EL \ -Wl,--gc-sections \ -Wl,-Map=$(basename $@).map diff --git a/samples/Basic_Ota/app/application.cpp b/samples/Basic_Ota/app/application.cpp index 51770d421c..c0a8bc3515 100644 --- a/samples/Basic_Ota/app/application.cpp +++ b/samples/Basic_Ota/app/application.cpp @@ -218,14 +218,14 @@ void handleCommand(const String& str) void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCharsCount) { switch(commandBuffer.process(stream, Serial)) { - case commandBuffer.Action::submit: + case LineBufferBase::Action::submit: if(commandBuffer) { handleCommand(String(commandBuffer)); commandBuffer.clear(); } showPrompt(); break; - case commandBuffer.Action::clear: + case LineBufferBase::Action::clear: showPrompt(); break; default:; diff --git a/samples/LiveDebug/app/application.cpp b/samples/LiveDebug/app/application.cpp index 146ec9affc..918b849ca0 100644 --- a/samples/LiveDebug/app/application.cpp +++ b/samples/LiveDebug/app/application.cpp @@ -123,10 +123,10 @@ void onDataReceived(Stream& source, char arrivedChar, unsigned short availableCh } switch(commandBuffer.process(source, Serial)) { - case commandBuffer.Action::clear: + case LineBufferBase::Action::clear: showPrompt(); break; - case commandBuffer.Action::submit: { + case LineBufferBase::Action::submit: { if(commandBuffer) { handleCommand(String(commandBuffer)); commandBuffer.clear();