From 9a097d81d015ac43d9475993b0c533ebabc03087 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 24 Jun 2024 08:42:55 +0100 Subject: [PATCH] Add Host MacOS support (#2804) This PR adds support for the Host Emulator to MacOS. See #2773. **64-bit only** Standard compiler is 'Apple Clang', supports only 64-bit builds: no 32-bit compatibility. GCC can be installed via `brew install gcc` and compiles as usual with the `-m32` flag. The GNU linker is absent from brew's `coreutils` package (see https://github.com/Homebrew/homebrew-core/issues/17794) so the standard system linker must be used. This only supports 64-bit targets. Apple have removed 32-bit application support from their ecosystem. Advantages No need for 32-bit compatibibility libraries in GNU/Linux. For MacOS build and run host emulator using standard Apple tools, no GCC required. General improvements in portability, less tolerant of incorrect type usage. Disadvantages Types such as long, size_t now 64-bit, don't match target hardware Pointers are 64-bit so cannot be cast to 32-bit intrinsics. Code must use correct `intptr_t` types. Must use `ENABLE_STORAGE_SIZE64=1` as emulated flash addresses must be 64-bit. **Symbol wrapping** MacOS linker doesn't support symbol wrapping which is used by `malloc_count` Component to hook `malloc`, etc. Don't currently have a solution for this so malloc_count is disabled for MacOS. **CI builds** Added MacOS builds plus running tests. For esp32 only IDF 5.2 is tested. **Notes** MacOS identified in makefiles with `UNAME=Darwin`. In code, use `#ifdef __APPLE__` when running on apple toolchains. Also requires `#ifdef __aarch64__` for Apple Silicon. The `rbpf` library requires `bpf` target with clang. Not supported by apple clang - use brew clang. I managed to get MacOS Ventura running in Qemu via https://github.com/kholia/OSX-KVM. This runs in x86_64 mode, adequate for dev/testing. The github actions runner `macos-latest` uses arm64, so introduces a few extra quirks. **Tools** - Compiler. Standard compiler is 'Apple Clang', supports only 64-bit builds: no 32-bit compatibility. Doesn't support `alias` attribute so use linker to do that instead. - Archive. Standard `ar` does not support - Linker. GNU Linker not available. MacOS linker does not support symbol wrapping. - GDB. Can be installed with `brew` but requires some additional steps for security reasons. Separate `lldb` target added. - sed. GNU 'sed' tool has extensions which MacOS version does not support. Added `SED` build variable which should always point to GNU version `gsed`, but only for Darwin. --- .github/workflows/ci-esp32.yml | 27 ++- .github/workflows/ci.yml | 13 +- .github/workflows/library.yml | 22 ++- Sming/Arch/Esp32/Tools/install.sh | 33 +++- Sming/Arch/Esp8266/Tools/install.sh | 9 +- .../Arch/Host/Components/gdbstub/component.mk | 10 + Sming/Arch/Host/Components/gdbstub/lldbcmds | 5 + .../Arch/Host/Components/hostlib/component.mk | 2 +- Sming/Arch/Host/Components/hostlib/hostlib.c | 8 + .../Arch/Host/Components/hostlib/startup.cpp | 1 + .../Arch/Host/Components/hostlib/threads.cpp | 34 +++- Sming/Arch/Host/Components/hostlib/threads.h | 48 +++-- Sming/Arch/Host/README.rst | 1 + Sming/Arch/Host/Tools/ci/build.setup.sh | 27 ++- Sming/Arch/Host/Tools/macos/README.rst | 15 ++ .../Tools/macos/net.tunnelblick.tap.plist | 20 ++ .../macos/tap.kext/Contents/CodeResources | Bin 0 -> 1673 bytes .../Tools/macos/tap.kext/Contents/Info.plist | 35 ++++ .../Tools/macos/tap.kext/Contents/MacOS/tap | Bin 0 -> 182416 bytes .../Contents/_CodeSignature/CodeResources | 115 +++++++++++ Sming/Arch/Host/Tools/setup-network-macos.sh | 13 ++ Sming/Arch/Host/app.mk | 17 +- Sming/Arch/Host/build.mk | 5 + .../Components/rp2040/firmware/build.sh | 2 +- Sming/Arch/Rp2040/Tools/install.sh | 18 +- Sming/Components/IFS | 2 +- Sming/Components/crypto/src/sha2big.cpp | 15 +- Sming/Components/crypto/src/sha2small.cpp | 15 +- .../lwip/src/Arch/Host/Linux/CMakeLists.txt | 4 - .../lwip/src/Arch/Host/Linux/lwip_arch.cpp | 57 +++++- Sming/Components/malloc_count/component.mk | 5 + .../Components/malloc_count/malloc_count.cpp | 4 + Sming/Components/terminal/component.mk | 2 +- Sming/Core/DateTime.cpp | 2 +- Sming/Libraries/Arduino_TensorFlowLite | 2 +- Sming/Libraries/DiskStorage | 2 +- Sming/Libraries/FatIFS | 2 +- Sming/Libraries/SdStorage | 2 +- Sming/Libraries/Timezone | 2 +- Sming/System/include/gdb/gdb_hooks.h | 4 + Sming/build.mk | 10 +- Sming/component-wrapper.mk | 13 +- Tools/ci/install.sh | 5 +- Tools/export.sh | 16 +- Tools/install.sh | 186 ++++++++++-------- docs/Tools/install.sh | 4 +- docs/source/arch/host/debugging/index.rst | 18 +- docs/source/arch/host/index.rst | 18 +- docs/source/getting-started/macos/index.rst | 88 +++------ samples/SystemClock_NTP/app/NtpClientDemo.cpp | 6 +- 50 files changed, 725 insertions(+), 239 deletions(-) create mode 100644 Sming/Arch/Host/Components/gdbstub/lldbcmds create mode 100644 Sming/Arch/Host/Tools/macos/README.rst create mode 100644 Sming/Arch/Host/Tools/macos/net.tunnelblick.tap.plist create mode 100644 Sming/Arch/Host/Tools/macos/tap.kext/Contents/CodeResources create mode 100644 Sming/Arch/Host/Tools/macos/tap.kext/Contents/Info.plist create mode 100755 Sming/Arch/Host/Tools/macos/tap.kext/Contents/MacOS/tap create mode 100644 Sming/Arch/Host/Tools/macos/tap.kext/Contents/_CodeSignature/CodeResources create mode 100755 Sming/Arch/Host/Tools/setup-network-macos.sh diff --git a/.github/workflows/ci-esp32.yml b/.github/workflows/ci-esp32.yml index 37b7cf1db1..d0dda46259 100644 --- a/.github/workflows/ci-esp32.yml +++ b/.github/workflows/ci-esp32.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, macos-latest, windows-latest] variant: [esp32, esp32s2, esp32c3, esp32s3, esp32c2] idf_version: ["4.3", "4.4", "5.0", "5.2"] exclude: @@ -21,10 +21,16 @@ jobs: idf_version: "4.3" - variant: esp32c2 idf_version: "4.4" - - idf_version: "4.3" - os: windows-latest - - idf_version: "5.0" - os: windows-latest + - os: macos-latest + idf_version: "4.3" + - os: macos-latest + idf_version: "4.4" + - os: macos-latest + idf_version: "5.0" + - os: windows-latest + idf_version: "4.3" + - os: windows-latest + idf_version: "5.0" concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} @@ -61,6 +67,11 @@ jobs: run: | Tools/ci/install.sh + - name: Install build tools for MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + Tools/ci/install.sh + - name: Install build tools for Windows if: ${{ matrix.os == 'windows-latest' }} run: | @@ -73,6 +84,12 @@ jobs: source $SMING_HOME/../Tools/export.sh Tools/ci/build.sh + - name: Build and test for ${{matrix.variant}} on MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + source $SMING_HOME/../Tools/export.sh + Tools/ci/build.sh + - name: Build and test for ${{matrix.variant}} with IDF v${{matrix.idf_version}} on Windows if: ${{ matrix.os == 'windows-latest' }} run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 870f129e5f..fb5f09032e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, macos-latest, windows-latest] variant: [esp8266, host, rp2040] toolchain: [gcc] include: @@ -66,6 +66,11 @@ jobs: run: | Tools/ci/install.sh + - name: Install build tools for MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + Tools/ci/install.sh + - name: Install build tools for Windows if: ${{ matrix.os == 'windows-latest' }} run: | @@ -81,6 +86,12 @@ jobs: $CLANG_FORMAT --version Tools/ci/build.sh + - name: Build and test for ${{matrix.variant}} on MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + source $SMING_HOME/../Tools/export.sh + Tools/ci/build.sh + - name: Build and test for ${{matrix.variant}} on Windows if: ${{ matrix.os == 'windows-latest' }} run: | diff --git a/.github/workflows/library.yml b/.github/workflows/library.yml index 7ae69a023b..01c1a7b57c 100644 --- a/.github/workflows/library.yml +++ b/.github/workflows/library.yml @@ -1,4 +1,4 @@ -name: Continuous Integration (CI) +name: Continuous Integration (CI) for Library on: workflow_call: @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, macos-latest, windows-latest] variant: [esp8266, host, esp32, esp32s2, esp32c3, esp32s3, esp32c2, rp2040] idf_version: ["4.4", ""] # "" denotes default, currently 5.2 toolchain: [gcc] @@ -34,6 +34,10 @@ jobs: variant: host arch: Host toolchain: clang + - os: ubuntu-latest + variant: host + arch: Host + toolchain: gcc64 - variant: esp32 arch: Esp32 - variant: esp32s2 @@ -55,6 +59,8 @@ jobs: idf_version: "4.4" - variant: rp2040 idf_version: "4.4" + - os: macos-latest + idf_version: "4.4" concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} @@ -67,6 +73,7 @@ jobs: SMING_SOC: ${{ matrix.variant }} INSTALL_IDF_VER: ${{ matrix.idf_version }} CLANG_BUILD: ${{ matrix.toolchain == 'clang' && '15' || '0' }} + BUILD64: ${{ matrix.toolchain == 'gcc64' && 1 || 0 }} steps: - name: Fix autocrlf setting @@ -103,6 +110,11 @@ jobs: run: | $SMING_HOME/../Tools/ci/install.sh + - name: Install build tools for MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + $SMING_HOME/../Tools/ci/install.sh + - name: Install build tools for Windows if: ${{ matrix.os == 'windows-latest' }} run: | @@ -118,6 +130,12 @@ jobs: source $SMING_HOME/../Tools/export.sh make -j$(nproc) -f $CI_MAKEFILE + - name: Build and test for ${{matrix.variant}} on MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + source $SMING_HOME/../Tools/export.sh + make -j$(nproc) -f $CI_MAKEFILE + - name: Build and Test for ${{matrix.arch}} on Windows if: ${{ matrix.os == 'windows-latest' }} run: | diff --git a/Sming/Arch/Esp32/Tools/install.sh b/Sming/Arch/Esp32/Tools/install.sh index d82db93d02..20c1fae9ed 100755 --- a/Sming/Arch/Esp32/Tools/install.sh +++ b/Sming/Arch/Esp32/Tools/install.sh @@ -5,17 +5,16 @@ if [ -n "$IDF_PATH" ] && [ -n "$IDF_TOOLS_PATH" ]; then PACKAGES=(\ - bison \ - ccache \ - dfu-util \ - flex \ - gperf \ - ninja-build \ + dfu-util ) case $DIST in debian) PACKAGES+=(\ + bison \ + ccache \ + flex \ + gperf \ libffi-dev \ libssl-dev \ ) @@ -23,12 +22,20 @@ case $DIST in fedora) PACKAGES+=(\ + bison \ + ccache \ + flex \ + gperf \ libffi-devel \ ) ;; + + darwin) + ;; + esac -$PKG_INSTALL ${PACKAGES[*]} +$PKG_INSTALL "${PACKAGES[@]}" # If directory exists and isn't a symlink then rename it if [ ! -L "$IDF_PATH" ] && [ -d "$IDF_PATH" ]; then @@ -37,23 +44,29 @@ if [ ! -L "$IDF_PATH" ] && [ -d "$IDF_PATH" ]; then fi INSTALL_IDF_VER="${INSTALL_IDF_VER:=5.2}" -IDF_CLONE_PATH="$(readlink -m "$IDF_PATH/..")/esp-idf-${INSTALL_IDF_VER}" +IDF_CLONE_PATH="$IDF_PATH/../esp-idf-${INSTALL_IDF_VER}" IDF_REPO="${IDF_REPO:=https://github.com/mikee47/esp-idf.git}" IDF_BRANCH="sming/release/v${INSTALL_IDF_VER}" if [ -d "$IDF_CLONE_PATH" ]; then - printf "\n\n** Skipping ESP-IDF clone: '$IDF_CLONE_PATH' exists\n\n" + printf "\n\n** Skipping ESP-IDF clone: '%s' exists\n\n" "$IDF_CLONE_PATH" else echo "git clone -b $IDF_BRANCH $IDF_REPO $IDF_CLONE_PATH" git clone -b "$IDF_BRANCH" "$IDF_REPO" "$IDF_CLONE_PATH" fi +IDF_CLONE_PATH=$(realpath "$IDF_CLONE_PATH") # Create link to clone -rm -f "$IDF_PATH" +rm -rf "$IDF_PATH" ln -s "$IDF_CLONE_PATH" "$IDF_PATH" # Install IDF tools and packages python3 "$IDF_PATH/tools/idf_tools.py" --non-interactive install +if [ -n "$VIRTUAL_ENV" ]; then + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + export PATH="${PATH/$VIRTUAL_ENV\/bin:/}" +fi python3 "$IDF_PATH/tools/idf_tools.py" --non-interactive install-python-env if [ -z "$KEEP_DOWNLOADS" ]; then diff --git a/Sming/Arch/Esp8266/Tools/install.sh b/Sming/Arch/Esp8266/Tools/install.sh index 02ab45a130..057e406816 100755 --- a/Sming/Arch/Esp8266/Tools/install.sh +++ b/Sming/Arch/Esp8266/Tools/install.sh @@ -3,10 +3,15 @@ # Esp8266 install.sh EQT_REPO="https://github.com/earlephilhower/esp-quick-toolchain/releases/download/3.2.0-gcc10.3" -EQT_TOOLCHAIN="$(uname -m)-linux-gnu.xtensa-lx106-elf-c791b74.230224.tar.gz" +if [ "$DIST" = "darwin" ]; then +EQT_PLATFORM="x86_64-apple-darwin14" +else +EQT_PLATFORM="$(uname -m)-linux-gnu" +fi +EQT_TOOLCHAIN="$EQT_PLATFORM.xtensa-lx106-elf-c791b74.230224.tar.gz" if [ -d "$ESP_HOME" ]; then - printf "\n\n** Skipping Esp8266 tools installation: '$ESP_HOME' exists\n\n" + printf "\n\n** Skipping Esp8266 tools installation: '%s' exists\n\n" "$ESP_HOME" else $WGET "$EQT_REPO/$EQT_TOOLCHAIN" -O "$DOWNLOADS/$EQT_TOOLCHAIN" mkdir -p "$ESP_HOME" diff --git a/Sming/Arch/Host/Components/gdbstub/component.mk b/Sming/Arch/Host/Components/gdbstub/component.mk index 46fd3ee841..93950132ca 100644 --- a/Sming/Arch/Host/Components/gdbstub/component.mk +++ b/Sming/Arch/Host/Components/gdbstub/component.mk @@ -4,3 +4,13 @@ GDBSTUB_DIR := $(COMPONENT_PATH) CACHE_VARS += GDB_CMDLINE GDB_CMDLINE = trap '' INT; $(GDB) -x $(GDBSTUB_DIR)/gdbcmds --args $(TARGET_OUT_0) $(CLI_TARGET_OPTIONS) --pause -- $(HOST_PARAMETERS) + +# LLVM debugger +CACHE_VARS += LLDB_CMDLINE +LLDB_CMDLINE = lldb --source $(GDBSTUB_DIR)/lldbcmds $(TARGET_OUT_0) -- $(CLI_TARGET_OPTIONS) --pause $(HOST_PARAMETERS) + +##@Tools + +.PHONY: lldb +lldb: ##Run the LLVM debugger console + $(LLDB_CMDLINE) diff --git a/Sming/Arch/Host/Components/gdbstub/lldbcmds b/Sming/Arch/Host/Components/gdbstub/lldbcmds new file mode 100644 index 0000000000..346ff806c2 --- /dev/null +++ b/Sming/Arch/Host/Components/gdbstub/lldbcmds @@ -0,0 +1,5 @@ +# Used for interrupt emulation +process handle -p true -s false -n false SIGUSR1 SIGUSR2 + +# Display a welcome prompt +script print("\nWelcome to SMING!\nType 'r' to run application\n\n") diff --git a/Sming/Arch/Host/Components/hostlib/component.mk b/Sming/Arch/Host/Components/hostlib/component.mk index 4f6ce7af50..37afff2015 100644 --- a/Sming/Arch/Host/Components/hostlib/component.mk +++ b/Sming/Arch/Host/Components/hostlib/component.mk @@ -2,7 +2,7 @@ EXTRA_LIBS := pthread ifeq ($(UNAME),Windows) EXTRA_LIBS += wsock32 -else +else ifneq ($(UNAME),Darwin) EXTRA_LIBS += rt endif diff --git a/Sming/Arch/Host/Components/hostlib/hostlib.c b/Sming/Arch/Host/Components/hostlib/hostlib.c index 7e43603df9..0671b8bb79 100644 --- a/Sming/Arch/Host/Components/hostlib/hostlib.c +++ b/Sming/Arch/Host/Components/hostlib/hostlib.c @@ -21,6 +21,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + int msleep(unsigned ms) { struct timespec req, rem; @@ -38,6 +42,10 @@ size_t getHostAppDir(char* path, size_t bufSize) #ifdef __WIN32 size_t len = GetModuleFileName(NULL, path, bufSize); char sep = '\\'; +#elif defined(__APPLE__) + uint32_t size = bufSize; + size_t len = _NSGetExecutablePath(path, &size) ? 0 : size; + char sep = '/'; #else size_t len = readlink("/proc/self/exe", path, bufSize - 1); char sep = '/'; diff --git a/Sming/Arch/Host/Components/hostlib/startup.cpp b/Sming/Arch/Host/Components/hostlib/startup.cpp index f74fdf3405..760682841a 100644 --- a/Sming/Arch/Host/Components/hostlib/startup.cpp +++ b/Sming/Arch/Host/Components/hostlib/startup.cpp @@ -254,6 +254,7 @@ int main(int argc, char* argv[]) commandLine.parse(argc - i, &argv[i]); if(!host_flashmem_init(config.flash)) { + host_debug_e("Flash init failed\n"); return 1; } diff --git a/Sming/Arch/Host/Components/hostlib/threads.cpp b/Sming/Arch/Host/Components/hostlib/threads.cpp index 83d0da5e14..75303382e0 100644 --- a/Sming/Arch/Host/Components/hostlib/threads.cpp +++ b/Sming/Arch/Host/Components/hostlib/threads.cpp @@ -22,6 +22,7 @@ #include #include #include +#include unsigned CThread::interrupt_mask; @@ -44,10 +45,13 @@ HANDLE host_thread_semaphore; CSemaphore host_thread_semaphore; volatile bool mainThreadSignalled; -timer_t signalTimer; int pauseSignal; int resumeSignal; +#ifndef __APPLE__ +timer_t signalTimer; +#endif + void signal_handler(int sig) { if(sig == pauseSignal) { @@ -61,6 +65,11 @@ void signal_handler(int sig) * - timer_settime() as for alarm() but with smaller interval * */ +#ifdef __APPLE__ + while(mainThreadSignalled) { + sched_yield(); + } +#else struct timespec ts = {0, long(0.1e9)}; struct itimerspec its = {ts, ts}; timer_settime(signalTimer, 0, &its, nullptr); @@ -69,6 +78,7 @@ void signal_handler(int sig) } its = {}; timer_settime(signalTimer, 0, &its, nullptr); +#endif } else if(sig == resumeSignal) { mainThreadSignalled = false; } else if(sig == SIGALRM) { @@ -79,8 +89,7 @@ void signal_handler(int sig) #endif -bool isMainThread() __attribute__((unused)); -bool isMainThread() +[[maybe_unused]] bool isMainThread() { return pthread_equal(pthread_self(), mainThread); } @@ -136,17 +145,27 @@ void CMutex::unlock() bool CSemaphore::timedwait(unsigned us) { +#ifdef __APPLE__ + dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, us * 1000); + if(dispatch_semaphore_wait(m_sem, time) == 0) { + return true; + } + errno = ETIMEDOUT; + return false; +#else struct timespec ts { }; clock_gettime(CLOCK_REALTIME, &ts); uint64_t ns = ts.tv_nsec + uint64_t(us) * 1000; ts.tv_sec += ns / 1000000000; ts.tv_nsec = ns % 1000000000; - return timedwait(&ts); + return sem_timedwait(&m_sem, &ts) == 0; +#endif } void CThread::startup(unsigned cpulimit) { +#ifndef __APPLE__ if(cpulimit != 0) { cpu_set_t set; CPU_ZERO(&set); @@ -159,12 +178,19 @@ void CThread::startup(unsigned cpulimit) host_debug_e("ERROR! Failed to set CPU affinity"); } } +#endif mainThread = pthread_self(); interrupt = new CBasicMutex; #ifdef __WIN32 host_thread_semaphore = CreateSemaphore(nullptr, 0, 1024, nullptr); +#elif defined(__APPLE__) + pauseSignal = SIGUSR1; + resumeSignal = SIGUSR2; + signal(pauseSignal, signal_handler); + signal(resumeSignal, signal_handler); + signal(SIGALRM, signal_handler); #else pauseSignal = SIGRTMIN + 0; resumeSignal = SIGRTMIN + 1; diff --git a/Sming/Arch/Host/Components/hostlib/threads.h b/Sming/Arch/Host/Components/hostlib/threads.h index b4934c4940..82a651568c 100644 --- a/Sming/Arch/Host/Components/hostlib/threads.h +++ b/Sming/Arch/Host/Components/hostlib/threads.h @@ -22,7 +22,11 @@ #include "include/hostlib/hostlib.h" #include #include +#ifdef __APPLE__ +#include +#else #include +#endif #include #if defined(DEBUG_VERBOSE_LEVEL) && (DEBUG_VERBOSE_LEVEL == 3) @@ -39,6 +43,14 @@ class CBasicMutex { public: + CBasicMutex() + { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_priv, &attr); + } + ~CBasicMutex() { pthread_mutex_destroy(&m_priv); @@ -69,7 +81,7 @@ class CBasicMutex * This behaviour allows threads to lock the mutex multiple times whilst * blocking other threads. Avoids risk of deadlocks and simplifies code. */ - pthread_mutex_t m_priv = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + pthread_mutex_t m_priv; }; /** @@ -95,45 +107,55 @@ class CSemaphore public: CSemaphore() { +#ifdef __APPLE__ + m_sem = dispatch_semaphore_create(0); +#else sem_init(&m_sem, 0, 0); +#endif } ~CSemaphore() { +#ifndef __APPLE__ sem_destroy(&m_sem); +#endif } bool post() { +#ifdef __APPLE__ + return dispatch_semaphore_signal(m_sem) == 0; +#else return sem_post(&m_sem) == 0; +#endif } bool wait() { +#ifdef __APPLE__ + return dispatch_semaphore_wait(m_sem, DISPATCH_TIME_FOREVER) == 0; +#else return sem_wait(&m_sem) == 0; +#endif } bool trywait() { +#ifdef __APPLE__ + return dispatch_semaphore_wait(m_sem, DISPATCH_TIME_NOW) == 0; +#else return sem_trywait(&m_sem) == 0; - } - - bool timedwait(const struct timespec* abs_timeout) - { - return sem_timedwait(&m_sem, abs_timeout) == 0; +#endif } bool timedwait(unsigned us); - int value() const - { - int n{0}; - sem_getvalue(const_cast(&m_sem), &n); - return n; - } - private: +#ifdef __APPLE__ + dispatch_semaphore_t m_sem; +#else sem_t m_sem{}; +#endif }; /** diff --git a/Sming/Arch/Host/README.rst b/Sming/Arch/Host/README.rst index 9acb1ca446..e3a90e4fa1 100644 --- a/Sming/Arch/Host/README.rst +++ b/Sming/Arch/Host/README.rst @@ -76,6 +76,7 @@ Configuration default: undefined Set to 1 to build in native 64-bit mode. + On MacOS builds are 64-bit only. Default for other systems is 32-bit. Components diff --git a/Sming/Arch/Host/Tools/ci/build.setup.sh b/Sming/Arch/Host/Tools/ci/build.setup.sh index 8018890bf4..027c19d178 100755 --- a/Sming/Arch/Host/Tools/ci/build.setup.sh +++ b/Sming/Arch/Host/Tools/ci/build.setup.sh @@ -3,13 +3,15 @@ # Host build.setup.sh # Check coding style -make cs -DIFFS=$(git diff) -if [ -n "$DIFFS" ]; then - echo "!!! Coding Style issues Found!!!" - echo " Run: 'make cs' to fix them. " - echo "$DIFFS" - exit 1 +if [ "$(uname)" == "Linux" ]; then + make cs + DIFFS=$(git diff) + if [ -n "$DIFFS" ]; then + echo "!!! Coding Style issues Found!!!" + echo " Run: 'make cs' to fix them. " + echo "$DIFFS" + exit 1 + fi fi # Make deployment keys, etc. available @@ -22,8 +24,13 @@ fi set -x # Setup networking + set +e -sudo ip tuntap add dev tap0 mode tap user $(whoami) -sudo ip a a dev tap0 192.168.13.1/24 -sudo ip link set tap0 up +if [ "$(uname)" == "Darwin" ]; then + source "$SMING_HOME/Arch/Host/Tools/setup-network-macos.sh" +else + sudo ip tuntap add dev tap0 mode tap user $(whoami) + sudo ip a a dev tap0 192.168.13.1/24 + sudo ip link set tap0 up +fi set -e diff --git a/Sming/Arch/Host/Tools/macos/README.rst b/Sming/Arch/Host/Tools/macos/README.rst new file mode 100644 index 0000000000..cc6a115485 --- /dev/null +++ b/Sming/Arch/Host/Tools/macos/README.rst @@ -0,0 +1,15 @@ +MacOS Host Networking +===================== + +Create /dev/tapX devices:: + + sudo kextload /Library/Extensions/tap.kext + +You will need to confirm the security check then reboot. + +Devices are not auto-created, so after rebooting run the above command again. + + +.. note:: + + See https://github.com/ntop/n2n/issues/773. diff --git a/Sming/Arch/Host/Tools/macos/net.tunnelblick.tap.plist b/Sming/Arch/Host/Tools/macos/net.tunnelblick.tap.plist new file mode 100644 index 0000000000..c92c98e464 --- /dev/null +++ b/Sming/Arch/Host/Tools/macos/net.tunnelblick.tap.plist @@ -0,0 +1,20 @@ + #net.tunnelblick.tap.plist + + + + + Label + net.tunnelblick.tap + ProgramArguments + + /sbin/kextload + /Library/Extensions/tap.kext + + KeepAlive + + RunAtLoad + + UserName + root + + diff --git a/Sming/Arch/Host/Tools/macos/tap.kext/Contents/CodeResources b/Sming/Arch/Host/Tools/macos/tap.kext/Contents/CodeResources new file mode 100644 index 0000000000000000000000000000000000000000..1bdaac0064b872720dfce5b93c592acaa6d2b366 GIT binary patch literal 1673 zcmXT6NX}qnU|@L9%D~_Rqz#%_UmG+r{RQGB3z(T0nV2|&We#7As=1qCz{SR))#h=| zmW7$gpvX|oK!uGtl!ci`*0G=Y@V zwWuUBEi)OS#Idv_BfluKq|#8>KoDde7Y`T2JkPvjJwt8-PLLp*FjHu-ft)z6k%57! zfvKUHskwns6p(9ZU}j(f|lQ~F+x4e%*f8{#K6KkucF|_o&C<=>J-me&)wXzz;)`agz{-k3pB4UE6uF7 zk+XYsdG)bV*EJ8mI~zXvQhH2j%Q22(pEarLTTNQ-I#w)hVhk{7V)QZK0XkAvn33^6 z3zGqZfjo$(%pzeR)*w>lzRRLZRK-Kd?d-mODV1syX01#EM>Y;^Hbz!fc1A`PQv+iI zLm1zHu}w9jq@=(~Uq3&&xIixv6cKvK`MF@Ofw694F)*A>42%pKr-3X{U}@|#XzVs< z>|o;r`mpVLatbS>LA608%s?h4gIu2Mkc`Y?g=Ba%r78fqCHV?TsS2gVsVNGn70EfJ z#hGQPIh6`&`9%t8rFqGq=q^^s1jc<)USbYNH6#)PitZE=&qJZ|5^@X68RSZQ1K@+x5P6?nt=tmxasET_y0=)X=v- ze=sSOH9PRAvdre3?Ng`Q_xN{+F1y1?<&a?W^KrcE7RXy$02BW+AkKwm0At>FKlb}% z=pos~Y>;j!Z6FDB9WVn3L3|aIpI-t>^12G{#?(#qhQQPg2F6C9RBvo#U}R`v00vP5 zk`r;~5w`3lVfnT5)i0hi>zgDUb~eN;#p~phjG4bqD%3st8o__(QPyiocYVG0)=L<- zFbccWM5(P^Fh^6h>*+JLeE*uL#f{$$8owCugW?^WLs$)%fzgkWNp^3zw=lxEW7d+c znfLbXeZBtHX_eImZm={A%p_I@76xW8J}{GL;m;(XTvG&$yyV1mV*_)L&GIY;26_fM z3$zw!w5dTgCl}=)WiW77gK5$O$|0p>teF@kB{Q-ir(`BUw3N)uoX%j7!ek)Iv$F5l z`e~Wj%je&XxxyTovo7dL!m;kM2iuP>`p8-HVAkX8jgM;#kEmBI@9X@#x}3=%(OBW5 z=Kr7VM(Z?Bq}Y~K2QIn9q+hl#L22U0t5&6VwmdqfHSOOq&O2WIS5-dzIkhR>q9mJ% zL4<(`SoDKHgO6weh-O-@ul3CGU*9aI!!Qe^n|f$xag hRR_7=MpLFUS+dJk$j$Ouv(_L{da+uqeD4)W1^_H?3@ZQt literal 0 HcmV?d00001 diff --git a/Sming/Arch/Host/Tools/macos/tap.kext/Contents/Info.plist b/Sming/Arch/Host/Tools/macos/tap.kext/Contents/Info.plist new file mode 100644 index 0000000000..438b14cbc4 --- /dev/null +++ b/Sming/Arch/Host/Tools/macos/tap.kext/Contents/Info.plist @@ -0,0 +1,35 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + tap + CFBundleIdentifier + net.tunnelblick.tap + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tap + CFBundlePackageType + KEXT + CFBundleShortVersionString + 20141104 (Tunnelblick tap kext version 5.0; Tunnelblick build 5622) + CFBundleSignature + ???? + CFBundleVersion + 5.0 + OSBundleLibraries + + com.apple.kpi.mach + 8.0 + com.apple.kpi.bsd + 8.0 + com.apple.kpi.libkern + 8.0 + com.apple.kpi.unsupported + 8.0 + + + diff --git a/Sming/Arch/Host/Tools/macos/tap.kext/Contents/MacOS/tap b/Sming/Arch/Host/Tools/macos/tap.kext/Contents/MacOS/tap new file mode 100755 index 0000000000000000000000000000000000000000..e3630028f2d5fe1ef51a8c924cd1ab550a08cb33 GIT binary patch literal 182416 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 + + + + files + + files2 + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/Sming/Arch/Host/Tools/setup-network-macos.sh b/Sming/Arch/Host/Tools/setup-network-macos.sh new file mode 100755 index 0000000000..9ddfd0813a --- /dev/null +++ b/Sming/Arch/Host/Tools/setup-network-macos.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Helper script to setup tap0 networking interface under MacOS +# +# See https://github.com/ntop/n2n/issues/773 +# + +if [ ! -e /dev/tap0 ]; then + srcdir="$SMING_HOME/Arch/Host/Tools/macos" + sudo cp -r "$srcdir/tap.kext" /Library/Extensions + sudo cp -r "$srcdir/net.tunnelblick.tap.plist" /Library/LaunchDaemons +fi +sudo kmutil load -p /Library/Extensions/tap.kext diff --git a/Sming/Arch/Host/app.mk b/Sming/Arch/Host/app.mk index 940dc9a4d9..cf1d452e3d 100644 --- a/Sming/Arch/Host/app.mk +++ b/Sming/Arch/Host/app.mk @@ -24,12 +24,27 @@ endif .PHONY: application application: $(TARGET_OUT_0) +COMMA=, +WL=-Wl, + +ifeq ($(UNAME),Darwin) +LDFLAGS_FILTERED = $(filter-out $(addprefix $(WL),-EL --gc-sections -wrap%),$(LDFLAGS)) +LDFLAGS2 = $(patsubst $(WL)-Map=%,$(WL)-map$(COMMA)%,$(LDFLAGS_FILTERED)) \ + $(WL)-w \ + $(WL)-undefined,suppress \ + $(WL)-flat_namespace +else +LDSTARTGROUP := $(WL)--start-group +LDENDGROUP := $(WL)--end-group +LDFLAGS2 = $(LDFLAGS) +endif + $(TARGET_OUT_0): $(COMPONENTS_AR) ifdef CLANG_TIDY $(info Skipping link step for clang-tidy) else $(info $(notdir $(PROJECT_DIR)): Linking $@) - $(Q) $(LD) $(addprefix -L,$(LIBDIRS)) $(LDFLAGS) -Wl,--start-group $(COMPONENTS_AR) $(addprefix -l,$(LIBS)) -Wl,--end-group -o $@ + $(Q) $(LD) $(addprefix -L,$(LIBDIRS)) $(LDFLAGS2) $(LDSTARTGROUP) $(COMPONENTS_AR) $(addprefix -l,$(LIBS)) $(LDENDGROUP) -o $@ $(Q) $(call WriteFirmwareConfigFile,$@) $(Q) $(MEMANALYZER) $@ > $(FW_MEMINFO) $(Q) cat $(FW_MEMINFO) diff --git a/Sming/Arch/Host/build.mk b/Sming/Arch/Host/build.mk index f14bb481b5..885e6f22b2 100644 --- a/Sming/Arch/Host/build.mk +++ b/Sming/Arch/Host/build.mk @@ -41,6 +41,11 @@ GDB := $(TOOLSPEC)gdb GCC_UPGRADE_URL := https://sming.readthedocs.io/en/latest/arch/host/host-emulator.html\#c-c-32-bit-compiler-and-libraries +ifeq ($(UNAME),Darwin) +BUILD64 := 1 +CPPFLAGS += -D_DARWIN_C_SOURCE=1 +endif + ifneq ($(BUILD64),1) CPPFLAGS += -m32 endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/firmware/build.sh b/Sming/Arch/Rp2040/Components/rp2040/firmware/build.sh index 520ae4275c..00b1be548c 100755 --- a/Sming/Arch/Rp2040/Components/rp2040/firmware/build.sh +++ b/Sming/Arch/Rp2040/Components/rp2040/firmware/build.sh @@ -8,7 +8,7 @@ set -e write_chunk() { - sz=$(printf "%08x" $(du -b "$1" | cut -f1)) + sz=$(printf "%08x" $(wc -c "$1" | awk '{print $$1}')) # Output 8-byte header containing chunk tag plus length in little-endian format printf "CHNK\x${sz:6:2}\x${sz:4:2}\x${sz:2:2}\x${sz:0:2}" >> $2 # Append chunk data diff --git a/Sming/Arch/Rp2040/Tools/install.sh b/Sming/Arch/Rp2040/Tools/install.sh index 00cc633dab..f44851752e 100755 --- a/Sming/Arch/Rp2040/Tools/install.sh +++ b/Sming/Arch/Rp2040/Tools/install.sh @@ -2,17 +2,25 @@ # # Rp2040 install.sh -$PKG_INSTALL ninja-build - if [ -d "$PICO_TOOLCHAIN_PATH/arm-none-eabi" ]; then - printf "\n\n** Skipping Rp2040 tools installation: '$PICO_TOOLCHAIN_PATH' exists\n\n" + printf "\n\n** Skipping Rp2040 tools installation: '%s' exists\n\n" "$PICO_TOOLCHAIN_PATH" elif [ -n "$PICO_TOOLCHAIN_PATH" ]; then TOOLCHAIN_VERSION="13.2.rel1" TOOLCHAIN_BASE_URL="https://developer.arm.com/-/media/Files/downloads/gnu" - TOOLCHAIN_FILE="arm-gnu-toolchain-$TOOLCHAIN_VERSION-$(uname -m)-arm-none-eabi.tar.xz" + if [ "$DIST" = "darwin" ]; then + PLATFORM="darwin-" + else + PLATFORM="" + fi + TOOLCHAIN_FILE="arm-gnu-toolchain-$TOOLCHAIN_VERSION-$PLATFORM$(uname -m)-arm-none-eabi.tar.xz" TOOLCHAIN_URL="$TOOLCHAIN_BASE_URL/$TOOLCHAIN_VERSION/binrel/$TOOLCHAIN_FILE" $WGET "$TOOLCHAIN_URL" -O "$DOWNLOADS/$TOOLCHAIN_FILE" mkdir -p "$PICO_TOOLCHAIN_PATH" - tar -xf "$DOWNLOADS/$TOOLCHAIN_FILE" -C "$PICO_TOOLCHAIN_PATH" --totals --transform='s|^/*||' + tar -xf "$DOWNLOADS/$TOOLCHAIN_FILE" -C "$PICO_TOOLCHAIN_PATH" --totals #--transform='s|^/*||' mv "$PICO_TOOLCHAIN_PATH/"*/* "$PICO_TOOLCHAIN_PATH" fi + +# https://developer.arm.com/-/media/Files/downloads/gnu/ +# 13.2.rel1/ +# binrel/ +# arm-gnu-toolchain-13.2.rel1-darwin-x86_64-arm-none-eabi.tar.xz diff --git a/Sming/Components/IFS b/Sming/Components/IFS index 4d30df4bf9..cb876789d1 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit 4d30df4bf9e2bb155009595381d0822bdd81dbfa +Subproject commit cb876789d173ce574f4f2e0f32edaa74e64c07a0 diff --git a/Sming/Components/crypto/src/sha2big.cpp b/Sming/Components/crypto/src/sha2big.cpp index a58e25553c..0843fd73f8 100644 --- a/Sming/Components/crypto/src/sha2big.cpp +++ b/Sming/Components/crypto/src/sha2big.cpp @@ -103,13 +103,22 @@ CRYPTO_FUNC_INIT(sha512) ctx->count = 0; } -CRYPTO_FUNC_UPDATE(sha512) __attribute__((alias("crypto_sha384_update"))); +CRYPTO_FUNC_UPDATE(sha512) +{ + crypto_sha384_update(ctx, input, length); +} CRYPTO_FUNC_FINAL(sha512) { sha2big_final(ctx, digest, false); } -CRYPTO_FUNC_GET_STATE(sha512) __attribute__((alias("crypto_sha384_get_state"))); +CRYPTO_FUNC_GET_STATE(sha512) +{ + return crypto_sha384_get_state(ctx, state); +} -CRYPTO_FUNC_SET_STATE(sha512) __attribute__((alias("crypto_sha384_set_state"))); +CRYPTO_FUNC_SET_STATE(sha512) +{ + crypto_sha384_set_state(ctx, state, count); +} diff --git a/Sming/Components/crypto/src/sha2small.cpp b/Sming/Components/crypto/src/sha2small.cpp index 0e97b71444..68bbc73bb9 100644 --- a/Sming/Components/crypto/src/sha2small.cpp +++ b/Sming/Components/crypto/src/sha2small.cpp @@ -94,13 +94,22 @@ CRYPTO_FUNC_INIT(sha224) ctx->count = 0; } -CRYPTO_FUNC_UPDATE(sha224) __attribute__((alias("crypto_sha256_update"))); +CRYPTO_FUNC_UPDATE(sha224) +{ + crypto_sha256_update(ctx, input, length); +} CRYPTO_FUNC_FINAL(sha224) { sha2small_final(digest, ctx, true); } -CRYPTO_FUNC_GET_STATE(sha224) __attribute__((alias("crypto_sha256_get_state"))); +CRYPTO_FUNC_GET_STATE(sha224) +{ + return crypto_sha256_get_state(ctx, state); +} -CRYPTO_FUNC_SET_STATE(sha224) __attribute__((alias("crypto_sha256_set_state"))); +CRYPTO_FUNC_SET_STATE(sha224) +{ + crypto_sha256_set_state(ctx, state, count); +} diff --git a/Sming/Components/lwip/src/Arch/Host/Linux/CMakeLists.txt b/Sming/Components/lwip/src/Arch/Host/Linux/CMakeLists.txt index a4a9c4e6a7..6c091c9e5a 100644 --- a/Sming/Components/lwip/src/Arch/Host/Linux/CMakeLists.txt +++ b/Sming/Components/lwip/src/Arch/Host/Linux/CMakeLists.txt @@ -6,10 +6,6 @@ set (BUILD_SHARED_LIBS OFF) set (CMAKE_C_STANDARD 11) set (CMAKE_C_STANDARD_REQUIRED ON) -if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_SYSTEM_NAME STREQUAL "GNU") - message(FATAL_ERROR "Lwip shared library is only working on Linux or the Hurd") -endif() - set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DLWIP_DEBUG") include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) diff --git a/Sming/Components/lwip/src/Arch/Host/Linux/lwip_arch.cpp b/Sming/Components/lwip/src/Arch/Host/Linux/lwip_arch.cpp index a94d453f65..b01ae1af69 100644 --- a/Sming/Components/lwip/src/Arch/Host/Linux/lwip_arch.cpp +++ b/Sming/Components/lwip/src/Arch/Host/Linux/lwip_arch.cpp @@ -35,12 +35,22 @@ extern "C" { #include } +#ifdef __APPLE__ +#include +#include +// For some reason _ip_data from lwip/core/ip.c isn't found, so add it here. +#include +struct ip_globals ip_data; +#endif + namespace { struct netif net_if; void getMacAddress(const char* ifname, uint8_t hwaddr[6]) { + memset(hwaddr, 0, 6); + if(ifname == nullptr) { return; } @@ -51,17 +61,39 @@ void getMacAddress(const char* ifname, uint8_t hwaddr[6]) strncpy(ifr.ifr_name, ifname, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = '\0'; +#ifdef __APPLE__ + struct ifaddrs* list; + if(getifaddrs(&list)) { + return; + } + for(auto ifa = list; ifa != nullptr; ifa = ifa->ifa_next) { + if(ifa->ifa_addr == nullptr) { + continue; + } + if(ifa->ifa_addr->sa_family != AF_LINK) { + continue; + } + auto sdl = reinterpret_cast(ifa->ifa_addr); + host_debug_w("sdl_alen = %u", sdl->sdl_alen); + if(sdl->sdl_alen != 6) { + continue; + } + memcpy(hwaddr, LLADDR(sdl), 6); + break; + } + freeifaddrs(list); +#else int fd = socket(AF_INET, SOCK_DGRAM, 0); int res = ioctl(fd, SIOCGIFHWADDR, &ifr); close(fd); if(res == 0) { memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); - } else { - memset(hwaddr, 0, 6); } +#endif } +#ifndef __APPLE__ /** * @brief Fetch address and network mask for an interface * @param ifname nullptr to get first compatible interface @@ -103,11 +135,27 @@ bool getifaddr(struct lwip_net_config& netcfg) freeifaddrs(list); return res; } +#endif } // namespace struct netif* lwip_arch_init(struct lwip_net_config& netcfg) { +#ifdef __APPLE__ + + int fd = open("/dev/tap0", O_RDWR); + if(fd < 0) { + host_debug_e("/dev/tap0 not found"); + return nullptr; + } + close(fd); + + memcpy(netcfg.ifname, "tap0", 5); + IP4_ADDR(&netcfg.gw, 192, 168, 13, 1); + IP4_ADDR(&netcfg.netmask, 255, 255, 255, 0); + +#else + if(!getifaddr(netcfg)) { if(netcfg.ifname[0] == '\0') { host_debug_e("%s", "No compatible interface found"); @@ -117,13 +165,16 @@ struct netif* lwip_arch_init(struct lwip_net_config& netcfg) return nullptr; } + setenv("PRECONFIGURED_TAPIF", netcfg.ifname, true); + +#endif + if(ip_addr_isany(&netcfg.ipaddr)) { // Choose a default IP address IP4_ADDR(&netcfg.ipaddr, (uint32_t)ip4_addr1(&netcfg.gw), (uint32_t)ip4_addr2(&netcfg.gw), (uint32_t)ip4_addr3(&netcfg.gw), 10U); } - setenv("PRECONFIGURED_TAPIF", netcfg.ifname, true); lwip_init(); netif_add(&net_if, &netcfg.ipaddr, &netcfg.netmask, &netcfg.gw, nullptr, tapif_init, ethernet_input); getMacAddress(netcfg.ifname, net_if.hwaddr); diff --git a/Sming/Components/malloc_count/component.mk b/Sming/Components/malloc_count/component.mk index c37331ac6c..7089c0962f 100644 --- a/Sming/Components/malloc_count/component.mk +++ b/Sming/Components/malloc_count/component.mk @@ -1,7 +1,12 @@ COMPONENT_RELINK_VARS += ENABLE_MALLOC_COUNT COMPONENT_DOXYGEN_INPUT := include +# Not currently supported on MacOS +ifeq ($(UNAME),Darwin) +override ENABLE_MALLOC_COUNT=0 +else ENABLE_MALLOC_COUNT ?= 1 +endif ifeq ($(ENABLE_MALLOC_COUNT),1) diff --git a/Sming/Components/malloc_count/malloc_count.cpp b/Sming/Components/malloc_count/malloc_count.cpp index 357ba7dff0..6766a8e46b 100644 --- a/Sming/Components/malloc_count/malloc_count.cpp +++ b/Sming/Components/malloc_count/malloc_count.cpp @@ -75,6 +75,8 @@ namespace bool logEnabled{false}; size_t logThreshold{256}; +#ifdef ENABLE_MALLOC_COUNT + /* to each allocation additional data is added for bookkeeping. due to * alignment requirements, we can optionally add more than just one integer. */ constexpr size_t alignment{16}; /* bytes (>= 2*sizeof(size_t)) */ @@ -102,6 +104,8 @@ size_t* getSentinel(void* ptr) debug_i(PPREFIX fmt, ##__VA_ARGS__); \ } +#endif + /*****************************************/ /* run-time memory allocation statistics */ /*****************************************/ diff --git a/Sming/Components/terminal/component.mk b/Sming/Components/terminal/component.mk index 461fb425f1..c9fe169cac 100644 --- a/Sming/Components/terminal/component.mk +++ b/Sming/Components/terminal/component.mk @@ -4,7 +4,7 @@ COMPONENT_LIBNAME := CACHE_VARS += COM_PORT ifeq ($(UNAME),FreeBSD) COM_PORT ?= /dev/cuaU0 -else ifeq ($(UNAME),MacOS) +else ifeq ($(UNAME),Darwin) COM_PORT ?= /dev/tty.usbserial else ifeq ($(UNAME),Linux) COM_PORT ?= /dev/ttyUSB0 diff --git a/Sming/Core/DateTime.cpp b/Sming/Core/DateTime.cpp index 57b20d23d5..45c95243f7 100644 --- a/Sming/Core/DateTime.cpp +++ b/Sming/Core/DateTime.cpp @@ -17,7 +17,7 @@ #if defined(__WIN32) || (defined(ARCH_ESP32) && ESP_IDF_VERSION_MAJOR < 5) static_assert(sizeof(time_t) != 8, "Great! Now supports 64-bit - please update code"); #warning "**Y2038** time_t is only 32-bits in this build configuration" -#elif defined(ARCH_HOST) && __TIMESIZE != 64 && !defined(__USE_TIME_BITS64) +#elif defined(ARCH_HOST) && __TIMESIZE != 64 && !defined(__USE_TIME_BITS64) && !defined(__APPLE__) #warning "**Y2038** Expecting 64-bit time_t - please use GCC 10 or later" #else static_assert(sizeof(time_t) == 8, "Expecting 64-bit time_t - please use GCC 10 or later"); diff --git a/Sming/Libraries/Arduino_TensorFlowLite b/Sming/Libraries/Arduino_TensorFlowLite index ff5c36b3a9..65b59a7199 160000 --- a/Sming/Libraries/Arduino_TensorFlowLite +++ b/Sming/Libraries/Arduino_TensorFlowLite @@ -1 +1 @@ -Subproject commit ff5c36b3a9661852dc548ee8dd0efa7b679f5254 +Subproject commit 65b59a7199ce2c50b8c6e0a66750be45c5ec0760 diff --git a/Sming/Libraries/DiskStorage b/Sming/Libraries/DiskStorage index f545e91216..00759cf833 160000 --- a/Sming/Libraries/DiskStorage +++ b/Sming/Libraries/DiskStorage @@ -1 +1 @@ -Subproject commit f545e91216d2cc94153e29ef41de87bd1cde2e8c +Subproject commit 00759cf833a0c0e71abdbb1c0310a15abd52be9e diff --git a/Sming/Libraries/FatIFS b/Sming/Libraries/FatIFS index 33474a7d56..7840c7c4b1 160000 --- a/Sming/Libraries/FatIFS +++ b/Sming/Libraries/FatIFS @@ -1 +1 @@ -Subproject commit 33474a7d560b6b27bbb0b1effa4b06c96361ff88 +Subproject commit 7840c7c4b1afb978cd3ecde723f5c0451fb53c68 diff --git a/Sming/Libraries/SdStorage b/Sming/Libraries/SdStorage index 99826990a4..81deba25b1 160000 --- a/Sming/Libraries/SdStorage +++ b/Sming/Libraries/SdStorage @@ -1 +1 @@ -Subproject commit 99826990a46c3a509ec9c33bbe1572b3b50e663d +Subproject commit 81deba25b162ad3dd60829b471746c3b2f4f8226 diff --git a/Sming/Libraries/Timezone b/Sming/Libraries/Timezone index 92ceeaff61..1e3305df08 160000 --- a/Sming/Libraries/Timezone +++ b/Sming/Libraries/Timezone @@ -1 +1 @@ -Subproject commit 92ceeaff611f5df80143b5d3092e0a50f4859108 +Subproject commit 1e3305df084c414dacc0d959e32e354d1c38b166 diff --git a/Sming/System/include/gdb/gdb_hooks.h b/Sming/System/include/gdb/gdb_hooks.h index e89f213b6c..dec3309aa5 100644 --- a/Sming/System/include/gdb/gdb_hooks.h +++ b/Sming/System/include/gdb/gdb_hooks.h @@ -54,7 +54,11 @@ void gdb_enable(bool state); */ #ifdef ENABLE_GDB #ifdef ARCH_HOST +#if defined(__arm__) || defined(__aarch64__) +#define gdb_do_break() __builtin_debugtrap() +#else #define gdb_do_break() __asm__("int $0x03") +#endif #elif defined(ARCH_ESP8266) #define gdb_do_break() __asm__("break 0,0") #elif defined(ARCH_ESP32) diff --git a/Sming/build.mk b/Sming/build.mk index 0253b8dbb7..7e63828f84 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -234,7 +234,7 @@ ifeq (,$(findstring clang,$(COMPILER_NAME))) $(shell LANG=C $(CC) -v) $(error Compiler '$(COMPILER_VERSION_FULL)' not recognised. Please install GCC tools.) endif -COMPILER_VERSION_MIN := 15 +COMPILER_VERSION_MIN := 14 ifndef COMPILER_NOTICE_PRINTED $(info Note: Building with $(COMPILER_NAME) $(COMPILER_VERSION).) COMPILER_NOTICE_PRINTED := 1 @@ -294,9 +294,11 @@ CLIB_PREFIX := clib- # Use with LDFLAGS to define a symbol alias # $1 -> List of alias=name pairs -define DefSym -$(foreach n,$1,-Wl,--defsym=$n) -endef +ifeq ($(UNAME)$(SMING_ARCH),DarwinHost) +DefSym = $(foreach n,$1,-Wl,-alias,_$(word 2,$(subst =, ,$n)),_$(word 1,$(subst =, ,$n))) +else +DefSym = $(foreach n,$1,-Wl,--defsym=$n) +endif # Use with LDFLAGS to undefine a list of symbols # $1 -> List of symbols diff --git a/Sming/component-wrapper.mk b/Sming/component-wrapper.mk index ee82818afb..007beda4e0 100644 --- a/Sming/component-wrapper.mk +++ b/Sming/component-wrapper.mk @@ -195,8 +195,13 @@ $(COMPONENT_LIBPATH): build.ar ifndef CLANG_TIDY $(vecho) "AR $@" $(Q) test ! -f $@ || rm $@ +# Apple linker doesn't support scripting, everything must be on command line +ifeq ($(UNAME)$(SMING_ARCH),DarwinHost) + $(Q) $(AR) -q $(@F) $$( $@ +else @echo CREATE $(notdir $(COMPONENT_LIBPATH)) > $@ - $(foreach o,$(OBJ) $(EXTRA_OBJ),$(call addmod,$@,$o)) + $(foreach o,$^,$(call addmod,$@,$o)) @echo SAVE >> $@ @echo END >> $@ +endif endif # ifeq (,$(CUSTOM_BUILD)) endif # ifneq (,$(COMPONENT_LIBNAME)) diff --git a/Tools/ci/install.sh b/Tools/ci/install.sh index e95c2a6d45..a5a409deaf 100755 --- a/Tools/ci/install.sh +++ b/Tools/ci/install.sh @@ -21,9 +21,12 @@ fi if [ "$BUILD_DOCS" = "true" ]; then INSTALL_OPTS="doc" else - INSTALL_OPTS="fonts" + INSTALL_OPTS="fonts optional" fi +# Ensure default path is writeable +sudo chown "$USER" /opt + "$SMING_HOME/../Tools/install.sh" $SMING_ARCH $INSTALL_OPTS fi diff --git a/Tools/export.sh b/Tools/export.sh index 763f395023..602bc4423a 100755 --- a/Tools/export.sh +++ b/Tools/export.sh @@ -19,12 +19,14 @@ # if [ -z "$SMING_HOME" ]; then - if [ "$(basename $SHELL)" = "zsh" ]; then - _SOURCE=${(%):-%N} + if [ "$(basename "$SHELL")" = "zsh" ]; then + _SOURCEDIR=$(dirname "${0:a}") else - _SOURCE=$BASH_SOURCE + _SOURCEDIR=$(dirname "${BASH_SOURCE[0]}") fi - export SMING_HOME=$(readlink -m "$_SOURCE/../../Sming") + SMING_HOME=$(realpath "$_SOURCEDIR/../Sming") + export SMING_HOME + echo "SMING_HOME: $SMING_HOME" fi # Common @@ -39,3 +41,9 @@ export IDF_TOOLS_PATH=${IDF_TOOLS_PATH:=/opt/esp32} # Rp2040 export PICO_TOOLCHAIN_PATH=${PICO_TOOLCHAIN_PATH:=/opt/rp2040} + +# Provide non-apple CLANG (e.g. for rbpf library) +if [ -n "$GITHUB_ACTIONS" ] && [ "$(uname)" = "Darwin" ]; then +CLANG="$(brew --prefix llvm@15)/bin/clang" +export CLANG +fi diff --git a/Tools/install.sh b/Tools/install.sh index 4eb9635d28..05e13806c6 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -5,7 +5,7 @@ # . /opt/sming/Tools/install.sh # -[ "$0" = "$BASH_SOURCE" ]; sourced=$? +[ "$0" = "${BASH_SOURCE[0]}" ]; sourced=$? inst_host=0 inst_doc=0 @@ -14,7 +14,16 @@ inst_esp32=0 inst_rp2040=0 err=0 -FONT_PACKAGES="fonts-ubuntu fonts-noto-mono xfonts-base fonts-urw-base35 fonts-droid-fallback" +FONT_PACKAGES=(\ + fonts-ubuntu \ + fonts-noto-mono \ + xfonts-base \ + fonts-urw-base35 \ + fonts-droid-fallback \ + ) + +EXTRA_PACKAGES=() +OPTIONAL_PACKAGES=() for opt in "$@"; do opt=$(echo "$opt" | tr '[:upper:]' '[:lower:]') @@ -31,7 +40,15 @@ for opt in "$@"; do ;; fonts) - EXTRA_PACKAGES+=" $FONT_PACKAGES" + EXTRA_PACKAGES+=("${FONT_PACKAGES[@]}") + ;; + + optional) + OPTIONAL_PACKAGES+=(\ + clang-format-8 \ + "linux-modules-extra-$(uname -r)" \ + exfatprogs \ + ) ;; *) @@ -50,6 +67,7 @@ if [[ $err -eq 1 ]] || [ $# -eq 0 ]; then echo ' all Install all architectures' echo ' doc Tools required to build documentation' echo ' fonts Install fonts used by Graphics library (normally included with Ubuntu)' + echo ' optional Install optional development tools' echo if [ $sourced = 1 ]; then return 1 @@ -59,25 +77,22 @@ if [[ $err -eq 1 ]] || [ $# -eq 0 ]; then fi # Sming repository for binary archives -SMINGTOOLS=https://github.com/SmingHub/SmingTools/releases/download/1.0 +export SMINGTOOLS=https://github.com/SmingHub/SmingTools/releases/download/1.0 # Set default environment variables -if [ -z "$APPVEYOR" ]; then - source $(dirname "$BASH_SOURCE")/export.sh - - # Ensure default path is writeable - sudo mkdir -p /opt - sudo chown $USER:$USER /opt -fi +source "$(dirname "${BASH_SOURCE[0]}")/export.sh" -WGET="wget --no-verbose" +export WGET="wget --no-verbose" # Installers put downloaded archives here DOWNLOADS="downloads" mkdir -p $DOWNLOADS # Identify package installer for distribution -if [ -n "$(command -v apt)" ]; then +if [[ "$(uname)" = "Darwin" ]]; then + DIST=darwin + PKG_INSTALL="brew install" +elif [ -n "$(command -v apt)" ]; then DIST=debian PKG_INSTALL="sudo apt-get install -y" elif [ -n "$(command -v dnf)" ]; then @@ -94,78 +109,79 @@ fi # Common install -if [ -n "$APPVEYOR" ] || [ -n "$GITHUB_ACTION" ]; then - - # Provide repo. for clang-format-8 on Ubuntu 22.04 - sudo apt-add-repository -y 'deb http://mirrors.kernel.org/ubuntu focal main universe' - sudo apt-get -y update - $PKG_INSTALL \ - clang-format-8 \ - g++-multilib \ - python3-setuptools \ - ninja-build \ - linux-modules-extra-$(uname -r) \ - exfatprogs \ - $EXTRA_PACKAGES - -else - - MACHINE_PACKAGES="" - case $DIST in - debian) - case $(uname -m) in - arm | aarch64) - ;; - *) - MACHINE_PACKAGES="g++-multilib" - ;; - esac - sudo apt-get -y update || echo "Update failed... Try to install anyway..." - $PKG_INSTALL \ - cmake \ - curl \ - git \ - make \ - ninja-build \ - unzip \ - g++ \ - python3 \ - python3-pip \ - python3-setuptools \ - wget \ - $MACHINE_PACKAGES \ - $EXTRA_PACKAGES - - $PKG_INSTALL clang-format-8 || printf "\nWARNING: Failed to install optional clang-format-8.\n\n" - ;; - - fedora) - case $(uname -m) in - x86_64) - MACHINE_PACKAGES="glibc-devel.i686 libstdc++.i686" - ;; - esac - $PKG_INSTALL \ - cmake \ - gawk \ - gcc \ - gcc-c++ \ - gettext \ - git \ - make \ - ninja-build \ - python3 \ - python3-pip \ - sed \ - unzip \ - wget \ - $MACHINE_PACKAGES - ;; - - esac - +MACHINE_PACKAGES=() +case $DIST in + debian) + case $(uname -m) in + arm | aarch64) + ;; + *) + MACHINE_PACKAGES+=(g++-multilib) + ;; + esac + if [ ${#OPTIONAL_PACKAGES[@]} ]; then + # Provide repo. for clang-format-8 on Ubuntu 22.04 + sudo apt-add-repository -y 'deb http://mirrors.kernel.org/ubuntu focal main universe' + fi + sudo apt-get -y update || echo "Update failed... Try to install anyway..." + $PKG_INSTALL \ + cmake \ + curl \ + git \ + make \ + ninja-build \ + unzip \ + g++ \ + python3 \ + python3-pip \ + python3-setuptools \ + wget \ + "${MACHINE_PACKAGES[@]}" \ + "${EXTRA_PACKAGES[@]}" + + if [ -n "$OPTIONAL_PACKAGES" ]; then + $PKG_INSTALL "${OPTIONAL_PACKAGES[@]}" || printf "\nWARNING: Failed to install optional %s.\n\n" "$OPTIONAL_PACKAGES" + fi + ;; + + fedora) + case $(uname -m) in + x86_64) + MACHINE_PACKAGES=(\ + glibc-devel.i686 \ + libstdc++.i686 \ + ) + ;; + esac + $PKG_INSTALL \ + cmake \ + gawk \ + gcc \ + gcc-c++ \ + gettext \ + git \ + make \ + ninja-build \ + python3 \ + python3-pip \ + sed \ + unzip \ + wget \ + "${MACHINE_PACKAGES[@]}" + ;; + + darwin) + $PKG_INSTALL \ + binutils \ + coreutils \ + gnu-sed \ + ninja + ;; + +esac + +if [ "$DIST" != "darwin" ]; then sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 100 - fi set -e @@ -206,7 +222,7 @@ if [ $inst_rp2040 -eq 1 ]; then fi if [ -z "$KEEP_DOWNLOADS" ]; then - rm -rf "$DOWNLOADS/*" + rm -rf "${DOWNLOADS:?}/"* fi diff --git a/docs/Tools/install.sh b/docs/Tools/install.sh index e1137a71e7..a4ca7e4cf8 100755 --- a/docs/Tools/install.sh +++ b/docs/Tools/install.sh @@ -21,6 +21,6 @@ case $DIST in ;; esac -$PKG_INSTALL ${PACKAGES[*]} +$PKG_INSTALL "${PACKAGES[@]}" -python3 -m pip install -r $SMING_HOME/../docs/requirements.txt +python3 -m pip install -r "$SMING_HOME/../docs/requirements.txt" diff --git a/docs/source/arch/host/debugging/index.rst b/docs/source/arch/host/debugging/index.rst index 3e72fe8c44..4194439384 100644 --- a/docs/source/arch/host/debugging/index.rst +++ b/docs/source/arch/host/debugging/index.rst @@ -3,7 +3,12 @@ Debugging on Host Required tools and hardware --------------------------- -A GNU C/C++ debugger is the only requirement for the Host architecture. + +For ``MacOS``, GDB can be installed via ``brew`` but it requires code-signing. +This is not a trivial procedure and ``lldb`` is recommended. +This is installed with the standard xcode development tools. + +For other development platforms a GNU C/C++ debugger is required. Make sure that you have the following executable in your PATH:: gdb @@ -37,9 +42,8 @@ You can recompile Sming with the following directives to debug better Sming and Application ~~~~~~~~~~~ -To use, (re)compile your application with the ENABLE_GDB option and -flash it to the board. For this example we will use the :sample:`LiveDebug` -sample application:: +To use, (re)compile your application with the ENABLE_GDB option. +For this example we will use the :sample:`LiveDebug` sample application:: cd $SMING_HOME/../samples/LiveDebug make clean @@ -49,6 +53,10 @@ The next step is to start the debugger. This can be done with the command below: make gdb +For ``MacOS``, use lldb:: + + make lldb + After that a new interactive debugging session will be started:: Welcome to SMING! @@ -74,6 +82,8 @@ You can pause the program execution by pressing `Ctrl-C`. And work further usin GDB commands ------------ +For ``MacOS``, please refer to https://lldb.llvm.org/index.html for LLDB usage instructions. + There are multiple commands supported in GDB and we will mention only some of them. List current source code diff --git a/docs/source/arch/host/index.rst b/docs/source/arch/host/index.rst index 80ec806850..2c75d60fda 100644 --- a/docs/source/arch/host/index.rst +++ b/docs/source/arch/host/index.rst @@ -130,8 +130,9 @@ Networking Support is provided via TAP network interface (a virtual network layer operating at the ethernet frame level). A TAP interface must be created -first, and requires root privilege. You can use the -``Sming/Arch/Host/Tools/setup-network-linux.sh``. Here is the manual approach:: +first, and requires root privilege. + +For Linux, you can use ``Sming/Arch/Host/Tools/setup-network-linux.sh``. Here is the manual approach:: sudo ip tuntap add dev tap0 mode tap user `whoami` sudo ip a a dev tap0 192.168.13.1/24 @@ -156,6 +157,19 @@ You can list available network interfaces thus:: ip link + +For MacOS, networking support first requires installation of a kernel extension +using ``Sming/Arch/Host/Tools/setup-network-macos.sh``. +On first run, you will need to confirm security then reboot the system. +On rebooting, run the script again. + +The ``tap0`` network interface is created dynamically when ``/dev/tap0`` is opened. +At present, you must run the application with elevated permissions:: + + sudo out/Host/debug/firmware/app + + + Troubleshooting --------------- diff --git a/docs/source/getting-started/macos/index.rst b/docs/source/getting-started/macos/index.rst index 44acdf25a2..c475912c4c 100644 --- a/docs/source/getting-started/macos/index.rst +++ b/docs/source/getting-started/macos/index.rst @@ -3,90 +3,68 @@ Mac-OS Installation .. highlight:: bash -Pre-requisites --------------- -*(You might already have it)* +Quick Install +------------- -Xcode command line tools -~~~~~~~~~~~~~~~~~~~~~~~~ - -:: +1. Install command-line development tools:: xcode-select --install -Homebrew -~~~~~~~~ +2. Check if ``homebrew`` is installed:: -:: + brew - ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + If not, install it:: -Eclipse -~~~~~~~ + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -*(Optional)*:: + Check https://brew.sh/ if there's any issues here. - brew install Caskroom/cask/eclipse-cpp +3. Prepare installation directory -Build tools ------------ + Let's use /opt as the main directory for tools and Sming. -Required for the makefile build system:: + Regular users may not have access to */opt*, so do this:: - brew install binutils coreutils automake wget gawk libtool gettext gperf grep - export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH" + sudo chown $USER /opt -Install gnu-sed and make sure that it is the default ``sed`` command line application:: + (alternatively, use a different directory). - brew install gnu-sed --with-default-names +4. Fetch the Sming repository:: -If you have already installed ``gnu-sed`` but it is not the default one, -then make sure to uninstall it and install it again with the correct options:: + git clone https://github.com/SmingHub/Sming /opt/sming - brew uninstall gnu-sed - brew install gnu-sed --with-default-names + If using a directory other than ``/opt`` then you'll need to edit ``sming/Tools/export.sh`` before proceeding. -ESP8266 Toolchain ------------------ +5. Run the installer:: -We pull this in from the `SmingTools `__ repository:: + source /opt/sming/Tools/install.sh all - cd ~/ - export ESP_HOME=/opt/esp-quick-toolchain - curl -LO https://github.com/SmingHub/SmingTools/releases/download/1.0/x86_64-apple-darwin14.xtensa-lx106-elf-e6a192b.201211.tar.gz - sudo mkdir -p $ESP_HOME - sudo tar -zxf x86_64-apple-darwin14.xtensa-lx106-elf-e6a192b.201211.tar.gz -C $ESP_HOME - sudo chmod -R 775 $ESP_HOME + If you want to save disk space then you can select which tools to install. + Get a list of available options like this:: -You can also build it yourself -`with Homebrew `__ or -`with MacPorts `__. + /opt/sming/Tools/install.sh -Get Sming Core --------------- -Clone from the `Sming `__ repository:: +Vscode +------ - cd / - git clone https://github.com/SmingHub/Sming.git - cd Sming +See https://code.visualstudio.com/. -.. warning:: - Do NOT use the --recursive option for the command above. - Our build mechanism will take care to get the third-party sources and patch them, if needed. +Eclipse +------- + +*(Optional)*:: -You will get a copy of our `develop` branch which is intended for developers. -It is the one where all new cool (unstable) features are landing. + brew install Caskroom/cask/eclipse-cpp -If you want to use our stable branch then use the master branch:: - git checkout origin/master +.. note:: -Finally, set the :envvar:`SMING_HOME` environment variable to point to /Sming/Sming:: + The following information may be out of date. - export SMING_HOME=`pwd` Environment Variables --------------------- @@ -94,10 +72,8 @@ Environment Variables Open with a text editor the ``.profile`` file in your home directory, and add these lines:: export ESP_HOME=/opt/esp-quick-toolchain - export SMING_HOME=/Sming/Sming + export SMING_HOME=/opt/Sming/Sming -Make sure to replace ```` in the -command above with the actual directory on your local disk. (Optional step) ~~~~~~~~~~~~~~~ diff --git a/samples/SystemClock_NTP/app/NtpClientDemo.cpp b/samples/SystemClock_NTP/app/NtpClientDemo.cpp index aefa2bf30f..1ed73460b8 100644 --- a/samples/SystemClock_NTP/app/NtpClientDemo.cpp +++ b/samples/SystemClock_NTP/app/NtpClientDemo.cpp @@ -12,8 +12,8 @@ using namespace TZ; * For handling local/UTC time conversions * This is for the UK, amend as required */ -const Rule dstStart{"BST", Last, Sun, Mar, 1, 60}; -const Rule stdStart{"GMT", Last, Sun, Oct, 2, 0}; +const Rule dstStart{{"BST"}, Last, Sun, Mar, 1, 60}; +const Rule stdStart{{"GMT"}, Last, Sun, Oct, 2, 0}; // Posix rule string DEFINE_FSTR_LOCAL(tzstr, "GMT0BST,M3.5.0/1,M10.5.0") @@ -80,7 +80,7 @@ void NtpClientDemo::ntpResult(NtpClient& client, time_t ntpTime) SystemClock.setTime(ntpTime, eTZ_UTC); // Now we've set the clock, we can determine the initial active timezone and maintain the offset - SystemClock.onCheckTimeZoneOffset([this](time_t systemTime) { checkTimeZoneOffset(systemTime); }); + SystemClock.onCheckTimeZoneOffset([](time_t systemTime) { checkTimeZoneOffset(systemTime); }); /* * Display the new time