Skip to content

Commit

Permalink
Support host builds using clang toolchain (#2798)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mikee47 authored Jun 12, 2024
1 parent fa58a70 commit d4f490f
Show file tree
Hide file tree
Showing 17 changed files with 102 additions and 38 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/library.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions Sming/Arch/Host/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
----------

Expand Down
21 changes: 21 additions & 0 deletions Sming/Arch/Host/build.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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++
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Sming/Libraries/DiskStorage
Submodule DiskStorage updated 1 files
+1 −1 src/MBR.cpp
2 changes: 1 addition & 1 deletion Sming/Libraries/FlashIP
2 changes: 1 addition & 1 deletion Sming/Libraries/GoogleCast
2 changes: 1 addition & 1 deletion Sming/Libraries/Graphics
2 changes: 1 addition & 1 deletion Sming/Libraries/HueEmulator
Submodule HueEmulator updated 1 files
+1 −1 src/Bridge.cpp
2 changes: 1 addition & 1 deletion Sming/Libraries/RingTone
2 changes: 1 addition & 1 deletion Sming/Libraries/USB
2 changes: 1 addition & 1 deletion Sming/Libraries/jerryscript
Submodule jerryscript updated 1 files
+13 −0 jerryscript.patch
61 changes: 41 additions & 20 deletions Sming/build.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 \
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down
8 changes: 2 additions & 6 deletions Sming/component-wrapper.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 $$<"
Expand All @@ -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+ $$<"
Expand Down
1 change: 1 addition & 0 deletions Sming/project.mk
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ LIBS := $(EXTRA_LIBS)

# Common linker flags
LDFLAGS = \
-Wl,-EL \
-Wl,--gc-sections \
-Wl,-Map=$(basename $@).map

Expand Down
4 changes: 2 additions & 2 deletions samples/Basic_Ota/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:;
Expand Down
4 changes: 2 additions & 2 deletions samples/LiveDebug/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit d4f490f

Please sign in to comment.