diff --git a/.config b/.config index ca9fcb2..4964e5b 100644 --- a/.config +++ b/.config @@ -236,7 +236,7 @@ CONFIG_RT_USING_SERIAL=y CONFIG_RT_USING_SERIAL_V1=y # CONFIG_RT_USING_SERIAL_V2 is not set CONFIG_RT_SERIAL_USING_DMA=y -CONFIG_RT_SERIAL_RB_BUFSZ=128 +CONFIG_RT_SERIAL_RB_BUFSZ=1024 # CONFIG_RT_USING_SERIAL_BYPASS is not set # CONFIG_RT_USING_CAN is not set # CONFIG_RT_USING_CPUTIME is not set @@ -1437,30 +1437,28 @@ CONFIG_SOC_STM32H750XB=y # # On-chip Peripheral Drivers # +CONFIG_BSP_SCB_ENABLE_I_CACHE=y +# CONFIG_BSP_SCB_ENABLE_D_CACHE is not set +CONFIG_BSP_ENABLE_FPU=y CONFIG_BSP_USING_GPIO=y CONFIG_BSP_USING_UART=y -CONFIG_BSP_STM32_UART_V1_TX_TIMEOUT=2000 +CONFIG_BSP_STM32_UART_V1_TX_TIMEOUT=6000 CONFIG_BSP_USING_UART1=y # CONFIG_BSP_UART1_RX_USING_DMA is not set # CONFIG_BSP_UART1_TX_USING_DMA is not set CONFIG_BSP_USING_UART2=y -# CONFIG_BSP_UART2_RX_USING_DMA is not set +CONFIG_BSP_UART2_RX_USING_DMA=y # CONFIG_BSP_UART2_TX_USING_DMA is not set CONFIG_BSP_UART2_RX_BUFSIZE=1024 -CONFIG_BSP_UART2_TX_BUFSIZE=0 +CONFIG_BSP_UART2_TX_BUFSIZE=512 CONFIG_BSP_USING_UART3=y -# CONFIG_BSP_UART3_RX_USING_DMA is not set +CONFIG_BSP_UART3_RX_USING_DMA=y # CONFIG_BSP_UART3_TX_USING_DMA is not set -CONFIG_BSP_UART3_RX_BUFSIZE=256 -CONFIG_BSP_UART3_TX_BUFSIZE=0 +CONFIG_BSP_UART3_RX_BUFSIZE=1024 +CONFIG_BSP_UART3_TX_BUFSIZE=512 # CONFIG_BSP_USING_PWM is not set # CONFIG_BSP_USING_QSPI is not set -CONFIG_BSP_USING_SPI=y -# CONFIG_BSP_USING_SPI1 is not set -CONFIG_BSP_USING_SPI5=y -CONFIG_BSP_SPI5_TX_USING_DMA=y -# CONFIG_BSP_SPI5_RX_USING_DMA is not set -# CONFIG_BSP_USING_SPI6 is not set +# CONFIG_BSP_USING_SPI is not set # CONFIG_BSP_USING_CRC is not set # CONFIG_BSP_USING_RNG is not set # CONFIG_BSP_USING_UDID is not set diff --git a/.gitignore b/.gitignore index 7221bde..a2ffc94 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ build Debug documentation/html -packages/ +#packages/ *~ *.o *.obj diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..7fa58b3 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,8 @@ + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 321b930..ef9453f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ INCLUDE_DIRECTORIES( applications/erpc applications/erpc/service applications/erpc/client + applications/erpc/common applications/erpc/proto/generated board board/CubeMX_Config/Inc @@ -82,12 +83,13 @@ ADD_DEFINITIONS( # Library source files SET(RT_APP_ERPC_SOURCES - applications/erpc/client/src/erpc_client_main.cpp - applications/erpc/proto/generated/head_service_server.cpp - applications/erpc/proto/generated/head_service_client.cpp - applications/erpc/service/src/head_service_impl.cpp applications/erpc/service/src/erpc_server_main.cpp + applications/erpc/common/src/erpc_error_handler.cpp + applications/erpc/service/src/head_service_impl.cpp + applications/erpc/proto/generated/head_service_server.cpp + applications/erpc/client/src/erpc_client_main.cpp applications/erpc/proto/generated/head_service_interface.cpp + applications/erpc/proto/generated/head_service_client.cpp ) SET(RT_APPLICATIONS_SOURCES @@ -106,8 +108,8 @@ SET(RT_COMPILER_SOURCES ) SET(RT_CPP_SOURCES - rt-thread/components/libc/cplusplus/cxx_crt_init.c rt-thread/components/libc/cplusplus/cxx_crt.cpp + rt-thread/components/libc/cplusplus/cxx_crt_init.c ) SET(RT_DEVICEDRIVERS_SOURCES @@ -139,33 +141,33 @@ SET(RT_DRIVERS_SOURCES ) SET(RT_ERPC_SOURCES - packages/erpc-1.14.0/erpc_c/setup/erpc_client_setup.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_pre_post_action.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_crc16.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_server.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_message_buffer.cpp - packages/erpc-1.14.0/erpc_c/setup/erpc_arbitrated_client_setup.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_transport_arbitrator.cpp - packages/erpc-1.14.0/erpc_c/setup/erpc_server_setup.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_message_loggers.cpp - packages/erpc-1.14.0/erpc_c/setup/erpc_setup_mbf_static.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_basic_codec.cpp - packages/erpc-1.14.0/erpc_c/infra/erpc_arbitrated_client_manager.cpp - packages/erpc-1.14.0/erpc_c/setup/erpc_setup_uart_cmsis.cpp packages/erpc-1.14.0/erpc_c/setup/erpc_setup_mbf_dynamic.cpp - packages/erpc-1.14.0/erpc_c/transports/erpc_uart_cmsis_transport.cpp - packages/erpc-1.14.0/erpc_c/port/erpc_threading_pthreads.cpp + packages/erpc-1.14.0/erpc_c/setup/erpc_server_setup.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_server.cpp + packages/erpc-1.14.0/erpc_c/setup/erpc_setup_mbf_static.cpp packages/erpc-1.14.0/erpc_c/infra/erpc_simple_server.cpp - packages/erpc-1.14.0/erpc_c/transports/erpc_inter_thread_buffer_transport.cpp + packages/erpc-1.14.0/erpc_c/setup/erpc_setup_serial.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_pre_post_action.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_message_buffer.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_basic_codec.cpp packages/erpc-1.14.0/erpc_c/infra/erpc_framed_transport.cpp packages/erpc-1.14.0/erpc_c/infra/erpc_client_manager.cpp + packages/erpc-1.14.0/erpc_c/transports/erpc_serial_transport.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_message_loggers.cpp + packages/erpc-1.14.0/erpc_c/port/erpc_threading_pthreads.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_transport_arbitrator.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_arbitrated_client_manager.cpp + packages/erpc-1.14.0/erpc_c/transports/erpc_inter_thread_buffer_transport.cpp + packages/erpc-1.14.0/erpc_c/infra/erpc_crc16.cpp + packages/erpc-1.14.0/erpc_c/setup/erpc_arbitrated_client_setup.cpp + packages/erpc-1.14.0/erpc_c/setup/erpc_client_setup.cpp ) SET(RT_FINSH_SOURCES - rt-thread/components/finsh/shell.c rt-thread/components/finsh/cmd.c rt-thread/components/finsh/msh.c rt-thread/components/finsh/msh_parse.c + rt-thread/components/finsh/shell.c ) SET(RT_KERNEL_SOURCES @@ -187,17 +189,17 @@ SET(RT_KERNEL_SOURCES ) SET(RT_KLIBC_SOURCES - rt-thread/src/klibc/kerrno.c - rt-thread/src/klibc/rt_vsnprintf_tiny.c rt-thread/src/klibc/rt_vsscanf.c + rt-thread/src/klibc/rt_vsnprintf_tiny.c + rt-thread/src/klibc/kerrno.c rt-thread/src/klibc/kstdio.c rt-thread/src/klibc/kstring.c ) SET(RT_KTIME_SOURCES - rt-thread/components/drivers/ktime/src/cputimer.c rt-thread/components/drivers/ktime/src/hrtimer.c rt-thread/components/drivers/ktime/src/boottime.c + rt-thread/components/drivers/ktime/src/cputimer.c ) SET(RT_LIBCPU_SOURCES @@ -210,30 +212,30 @@ SET(RT_LIBCPU_SOURCES ) SET(RT_LIBRARIES_SOURCES - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cortex.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_sram.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rng.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_comp.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cryp.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_qspi.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cryp_ex.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c - libraries/STM32H7xx_HAL/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cec.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cec.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_comp.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c - libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cryp.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_usart.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cryp_ex.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c + libraries/STM32H7xx_HAL/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_sram.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_qspi.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c + libraries/STM32H7xx_HAL/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rng.c ) SET(RT_POSIX_SOURCES diff --git a/applications/erpc/SConscript b/applications/erpc/SConscript index 3e1dfc1..09c5199 100644 --- a/applications/erpc/SConscript +++ b/applications/erpc/SConscript @@ -23,7 +23,7 @@ gen_dir = p('proto', 'generated') # interface 建议始终编译(两端都可能需要) src += [p('proto', 'generated', 'head_service_interface.cpp')] - +src += [p('common', 'src', 'erpc_error_handler.cpp')] if GetDepend(['ERPC_MODE_SERVER']): src += [p('proto', 'generated', 'head_service_server.cpp')] @@ -34,6 +34,7 @@ CPPPATH = [ cwd, p('service'), p('client'), + p('common'), gen_dir, ] diff --git a/applications/erpc/client/src/erpc_client_main.cpp b/applications/erpc/client/src/erpc_client_main.cpp index 07c4d64..23a06c4 100644 --- a/applications/erpc/client/src/erpc_client_main.cpp +++ b/applications/erpc/client/src/erpc_client_main.cpp @@ -10,15 +10,16 @@ #include "erpc_client_setup.h" // generated (C++ stub) +#include "drv_gpio.h" #include "erpc/proto/generated/head_service_client.hpp" #include "head_service_common.hpp" // 若有用到类型 -#ifndef ERPC_UART_NAME -#define ERPC_UART_NAME "uart3" +#ifndef ERPC_CLIENT_UART_NAME +#define ERPC_CLIENT_UART_NAME "uart3" #endif #ifndef ERPC_UART_BAUD -#define ERPC_UART_BAUD (115200) +#define ERPC_UART_BAUD (921600 ) #endif #ifndef ERPC_CLIENT_STACK @@ -26,20 +27,21 @@ #endif #ifndef ERPC_CLIENT_PRIO -#define ERPC_CLIENT_PRIO (20) +#define ERPC_CLIENT_PRIO (5) #endif #ifndef ERPC_CLIENT_TICK -#define ERPC_CLIENT_TICK (10) +#define ERPC_CLIENT_TICK (5) #endif static void erpc_client_entry(void *parameter) { (void)parameter; - rt_kprintf("[erpc] client init on %s, %d\r\n", ERPC_UART_NAME, ERPC_UART_BAUD); + rt_kprintf("[erpc] client init on %s, %d\r\n", ERPC_CLIENT_UART_NAME, ERPC_UART_BAUD); - erpc_transport_t transport = erpc_transport_cmsis_uart_init(ERPC_UART_NAME); + erpc_transport_t transport = erpc_transport_serial_init(ERPC_CLIENT_UART_NAME,ERPC_UART_BAUD); + // erpc_transport_t transport = erpc_transport_cmsis_uart_init(ERPC_CLIENT_UART_NAME); if (!transport) { rt_kprintf("[erpc] transport init failed!\r\n"); @@ -63,17 +65,31 @@ static void erpc_client_entry(void *parameter) auto *mgr = reinterpret_cast(client); erpcShim::demo_client stub(mgr); + int32_t a = 7; + int32_t b = 8; + + while (1) { - int32_t r = stub.add(7, 8); - rt_kprintf("[erpc] add(1,2)=%d\r\n", (int)r); + + rt_tick_t now = rt_tick_get(); + rt_uint32_t ms = (rt_uint32_t)((rt_uint64_t)now * 1000 / RT_TICK_PER_SECOND); + rt_kprintf("start:[%lu ms] [erpc client] \r\n",(unsigned long)ms); + // rt_pin_write(GET_PIN(D, 0), PIN_HIGH); + int32_t r = stub.add(a, b); + // rt_pin_write(GET_PIN(D, 0), PIN_LOW); + + now = rt_tick_get(); + ms = (rt_uint32_t)((rt_uint64_t)now * 1000 / RT_TICK_PER_SECOND); + rt_kprintf("end:[%lu ms] [erpc client] \r\n",(unsigned long)ms); + rt_thread_mdelay(1000); } - // 如果你未来要退出线程: - // erpc_client_deinit(client); + // 退出线程: + erpc_client_deinit(client); } extern "C" int erpc_client_start(void) diff --git a/applications/erpc/common/include/erpc_error_handler.h b/applications/erpc/common/include/erpc_error_handler.h new file mode 100644 index 0000000..d6d8d6a --- /dev/null +++ b/applications/erpc/common/include/erpc_error_handler.h @@ -0,0 +1,48 @@ +/* +* Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__ERROR_HANDLER_H_ +#define _EMBEDDED_RPC__ERROR_HANDLER_H_ + +#include + +#include "erpc_common.h" + +/*! + * @addtogroup error_handler + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// API +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif + + //! @name Error handler + //@{ + + /*! + * @brief This function handles eRPC errors. + * + * This function prints a description of occurred error and sets bool variable g_erpc_error_occurred which is used for + * determining if error occurred in user application on client side. + */ + void erpc_error_handler(erpc_status_t err, uint32_t functionID); + + //@} + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif // _EMBEDDED_RPC__ERROR_HANDLER_H_ \ No newline at end of file diff --git a/applications/erpc/common/src/erpc_error_handler.cpp b/applications/erpc/common/src/erpc_error_handler.cpp new file mode 100644 index 0000000..a4ea7d7 --- /dev/null +++ b/applications/erpc/common/src/erpc_error_handler.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "erpc/common/include/erpc_error_handler.h" + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +extern bool g_erpc_error_occurred; +bool g_erpc_error_occurred = false; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +void erpc_error_handler(erpc_status_t err, uint32_t functionID) +{ + switch (err) + { + case kErpcStatus_Fail: + printf("\r\nGeneric failure."); + break; + + case kErpcStatus_InvalidArgument: + printf("\r\nArgument is an invalid value."); + break; + + case kErpcStatus_Timeout: + printf("\r\nOperated timed out."); + break; + + case kErpcStatus_InvalidMessageVersion: + printf("\r\nMessage header contains an unknown version."); + break; + + case kErpcStatus_ExpectedReply: + printf("\r\nExpected a reply message but got another message type."); + break; + + case kErpcStatus_CrcCheckFailed: + printf("\r\nMessage is corrupted."); + break; + + case kErpcStatus_BufferOverrun: + printf("\r\nAttempt to read or write past the end of a buffer."); + break; + + case kErpcStatus_UnknownName: + printf("\r\nCould not find host with given name."); + break; + + case kErpcStatus_ConnectionFailure: + printf("\r\nFailed to connect to host."); + break; + + case kErpcStatus_ConnectionClosed: + printf("\r\nConnected closed by peer."); + break; + + case kErpcStatus_MemoryError: + printf("\r\nMemory allocation error."); + break; + + case kErpcStatus_ServerIsDown: + printf("\r\nServer is stopped."); + break; + + case kErpcStatus_InitFailed: + printf("\r\nTransport layer initialization failed."); + break; + + case kErpcStatus_ReceiveFailed: + printf("\r\nFailed to receive data."); + break; + + case kErpcStatus_SendFailed: + printf("\r\nFailed to send data."); + break; + + /* no error occurred */ + case kErpcStatus_Success: + return; + + /* unhandled error */ + default: + printf("\r\nUnhandled error occurred."); + break; + } + + /* When error occurred on client side. */ + if (functionID != 0) + { + printf("Function id '%u'.", (unsigned int)functionID); + } + printf("\r\n"); + + /* error occurred */ + g_erpc_error_occurred = true; +} diff --git a/applications/erpc/service/src/erpc_server_main.cpp b/applications/erpc/service/src/erpc_server_main.cpp index 6361500..7972447 100644 --- a/applications/erpc/service/src/erpc_server_main.cpp +++ b/applications/erpc/service/src/erpc_server_main.cpp @@ -6,6 +6,7 @@ #include // eRPC setup + #include "erpc_server_setup.h" #include "erpc_transport_setup.h" #include "erpc_mbf_setup.h" @@ -15,36 +16,40 @@ #include "erpc/proto/generated/head_service_interface.hpp" #include "erpc/service/include/head_service_impl.h" +#include "erpc/common/include/erpc_error_handler.h" -// ====== 可按需修改的参数 ====== -#ifndef ERPC_UART_NAME -#define ERPC_UART_NAME "uart2" +// ====== 参数 ====== +#ifndef ERPC_SERVER_UART_NAME +#define ERPC_SERVER_UART_NAME "uart2" #endif #ifndef ERPC_UART_BAUD -#define ERPC_UART_BAUD (115200) +#define ERPC_UART_BAUD (921600 ) #endif #ifndef ERPC_THREAD_STACK -#define ERPC_THREAD_STACK (8192) +#define ERPC_THREAD_STACK (4096) #endif #ifndef ERPC_THREAD_PRIO -#define ERPC_THREAD_PRIO (20) +#define ERPC_THREAD_PRIO (4) #endif #ifndef ERPC_THREAD_TICK -#define ERPC_THREAD_TICK (10) +#define ERPC_THREAD_TICK (5) #endif static void erpc_server_entry(void *parameter) { (void)parameter; + // rt_kprintf("CPACR=%08lx\n", SCB->CPACR); - rt_kprintf("[erpc] server init on %s, %d\r\n", ERPC_UART_NAME, ERPC_UART_BAUD); + + rt_kprintf("[erpc] server init on %s, %d\r\n", ERPC_SERVER_UART_NAME, ERPC_UART_BAUD); // 1) transport - erpc_transport_t transport = erpc_transport_cmsis_uart_init(ERPC_UART_NAME); + erpc_transport_t transport = erpc_transport_serial_init(ERPC_SERVER_UART_NAME,ERPC_UART_BAUD); + // erpc_transport_t transport = erpc_transport_cmsis_uart_init(ERPC_SERVER_UART_NAME); if (!transport) { rt_kprintf("[erpc] transport init failed!\r\n"); @@ -79,7 +84,7 @@ static void erpc_server_entry(void *parameter) erpc_status_t tcp_status = erpc_server_poll(server); if (tcp_status != kErpcStatus_Success) { - // erpc_error_handler(tcp_status,0); + erpc_error_handler(tcp_status,0); } } } @@ -102,5 +107,5 @@ extern "C" int erpc_server_start(void) return RT_EOK; } -// 让系统启动后自动拉起(如果你希望手动启动,就把这一行注释掉) + INIT_APP_EXPORT(erpc_server_start); diff --git a/applications/erpc/service/src/head_service_impl.cpp b/applications/erpc/service/src/head_service_impl.cpp index 82726e8..3fda4cb 100644 --- a/applications/erpc/service/src/head_service_impl.cpp +++ b/applications/erpc/service/src/head_service_impl.cpp @@ -8,6 +8,10 @@ int32_t HeadServiceImpl::add(int32_t a, int32_t b) { - rt_kprintf("[erpc] add(%d, %d)\r\n", (int)a, (int)b); - return a + b; + int32_t r = a + b; + rt_tick_t now = rt_tick_get(); + rt_uint32_t ms = (rt_uint32_t)((rt_uint64_t)now * 1000 / RT_TICK_PER_SECOND); + rt_kprintf("[%lu ms] [erpc service] add(%ld,%ld)=%ld\r\n", + (unsigned long)ms, (long)a, (long)b, (long)r); + return r; } diff --git a/applications/main.c b/applications/main.c index 6a88899..f12ed8e 100644 --- a/applications/main.c +++ b/applications/main.c @@ -21,6 +21,7 @@ int main(void) int count = 1; /* set LED0 pin mode to output */ rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); + rt_pin_mode(GET_PIN(D, 0), PIN_MODE_OUTPUT); while (count++) @@ -33,6 +34,15 @@ int main(void) } return RT_EOK; } +static inline int dwt_init(void) +{ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + return 0; +} + +INIT_APP_EXPORT(dwt_init); diff --git a/board/Kconfig b/board/Kconfig index bd99c55..9c7d952 100644 --- a/board/Kconfig +++ b/board/Kconfig @@ -29,6 +29,25 @@ endmenu menu "On-chip Peripheral Drivers" + config BSP_SCB_ENABLE_I_CACHE + bool "Enable I-Cache (SCB_EnableICache)" + default y + help + Enable Cortex-M7 I-Cache for better XIP performance. + + config BSP_SCB_ENABLE_D_CACHE + bool "Enable D-Cache (SCB_EnableDCache)" + default n + help + Enable Cortex-M7 D-Cache. Make sure MPU is configured correctly. + + config BSP_ENABLE_FPU + bool "Enable FPU support (select RT_USING_FPU)" + default y + select RT_USING_FPU + help + Enable RT-Thread FPU context support on Cortex-M7. + config BSP_USING_GPIO bool "Enable GPIO" select RT_USING_PIN diff --git a/libraries/HAL_Drivers/drivers/config/h7/dma_config.h b/libraries/HAL_Drivers/drivers/config/h7/dma_config.h index 922bd0a..29bfb76 100644 --- a/libraries/HAL_Drivers/drivers/config/h7/dma_config.h +++ b/libraries/HAL_Drivers/drivers/config/h7/dma_config.h @@ -17,6 +17,7 @@ #ifdef __cplusplus extern "C" { + #endif /* DMA1 stream0 */ @@ -37,6 +38,22 @@ extern "C" { #define UART2_TX_DMA_IRQ DMA1_Stream1_IRQn #endif +/* DMA1 stream2/3 for USART3 */ +#if defined(BSP_UART3_RX_USING_DMA) && !defined(UART3_RX_DMA_INSTANCE) +#define UART3_DMA_RX_IRQHandler DMA1_Stream2_IRQHandler +#define UART3_RX_DMA_RCC RCC_AHB1ENR_DMA1EN +#define UART3_RX_DMA_INSTANCE DMA1_Stream2 +#define UART3_RX_DMA_REQUEST DMA_REQUEST_USART3_RX +#define UART3_RX_DMA_IRQ DMA1_Stream2_IRQn +#endif + +#if defined(BSP_UART3_TX_USING_DMA) && !defined(UART3_TX_DMA_INSTANCE) +#define UART3_DMA_TX_IRQHandler DMA1_Stream3_IRQHandler +#define UART3_TX_DMA_RCC RCC_AHB1ENR_DMA1EN +#define UART3_TX_DMA_INSTANCE DMA1_Stream3 +#define UART3_TX_DMA_REQUEST DMA_REQUEST_USART3_TX +#define UART3_TX_DMA_IRQ DMA1_Stream3_IRQn +#endif /* DMA1 stream2 */ #if defined(BSP_SPI3_RX_USING_DMA) && !defined(SPI3_RX_DMA_INSTANCE) #define SPI3_DMA_RX_IRQHandler DMA1_Stream2_IRQHandler diff --git a/libraries/HAL_Drivers/drivers/config/h7/uart_config.h b/libraries/HAL_Drivers/drivers/config/h7/uart_config.h index ca929bd..a4c05d5 100644 --- a/libraries/HAL_Drivers/drivers/config/h7/uart_config.h +++ b/libraries/HAL_Drivers/drivers/config/h7/uart_config.h @@ -17,6 +17,7 @@ #ifdef __cplusplus extern "C" { + #endif #if defined(BSP_USING_UART1) @@ -99,6 +100,17 @@ extern "C" { #endif /* UART3_DMA_RX_CONFIG */ #endif /* BSP_UART3_RX_USING_DMA */ +#if defined(BSP_UART3_TX_USING_DMA) +#ifndef UART3_DMA_TX_CONFIG +#define UART3_DMA_TX_CONFIG \ + { \ + .Instance = UART3_TX_DMA_INSTANCE, \ + .request = UART3_TX_DMA_REQUEST, \ + .dma_rcc = UART3_TX_DMA_RCC, \ + .dma_irq = UART3_TX_DMA_IRQ, \ + } +#endif /* UART3_DMA_TX_CONFIG */ +#endif /* BSP_UART3_TX_USING_DMA */ #if defined(BSP_USING_UART4) #ifndef UART4_CONFIG #define UART4_CONFIG \ diff --git a/packages/CMSIS-Core-latest b/packages/CMSIS-Core-latest new file mode 160000 index 0000000..39d8e01 --- /dev/null +++ b/packages/CMSIS-Core-latest @@ -0,0 +1 @@ +Subproject commit 39d8e01f0be84b83a8f11d33756e82ce1ef07a84 diff --git a/packages/Kconfig b/packages/Kconfig new file mode 100644 index 0000000..6bd6e1d --- /dev/null +++ b/packages/Kconfig @@ -0,0 +1,49 @@ +menu "Third Packages Drivers" + + menuconfig BSP_USING_ERPC + bool "Enable using erpc" + default n + + + if BSP_USING_ERPC + + + config ERPC_USING_RTT + bool "Enable erpc using rtt" + default n + + + + menuconfig ERPC_MODE + bool "Select erpc mode" + default y + if ERPC_MODE + config ERPC_MODE_SERVER + bool "ERPC Server Mode" + default y + config ERPC_MODE_CLIENT + bool "ERPC Client Mode" + default n + endif + + + + menuconfig ERPC_TRANSPORTS + bool "Select erpc transports" + default y + if ERPC_TRANSPORTS + config ERPC_TRANSPORTS_SPI + bool "SPI transports" + default n + config ERPC_TRANSPORTS_UART + bool "UART transports" + default n + config ERPC_TRANSPORTS_TCP + bool "TCP transports" + default n + endif + + endif + + +endmenu \ No newline at end of file diff --git a/packages/SConscript b/packages/SConscript new file mode 100644 index 0000000..e6d5f75 --- /dev/null +++ b/packages/SConscript @@ -0,0 +1,37 @@ +import os +from building import * + +objs = [] +cwd = GetCurrentDir() + +# 黑名单(exact) +exclude_dirs = { + 'cmsis-core-latest', + 'stm32h7_cmsis_driver-latest', + 'stm32h7_hal_driver-latest', +} + +#黑名单(prefix) +exclude_prefixes = ( + 'cmsis-core-', + 'stm32h7_cmsis_driver-', + 'stm32h7_hal_driver-', +) + +for item in os.listdir(cwd): + item_path = os.path.join(cwd, item) + + if not os.path.isdir(item_path): + continue + + name = item.lower() + + if name in exclude_dirs or name.startswith(exclude_prefixes): + print('[scons] skip dir:', item) + continue + + scon = os.path.join(item_path, 'SConscript') + if os.path.isfile(scon): + objs += SConscript(scon) + +Return('objs') diff --git a/packages/erpc-1.14.0/.circleci/config.yml b/packages/erpc-1.14.0/.circleci/config.yml new file mode 100644 index 0000000..d714b6b --- /dev/null +++ b/packages/erpc-1.14.0/.circleci/config.yml @@ -0,0 +1,103 @@ +version: 2.1 + +orbs: + win: circleci/windows@5.0 # The Windows orb gives you everything you need to start using the + +commands: + install_dependencies: + parameters: + compiler: + default: "" + type: string + steps: + - run: chmod u+x install_dependencies.sh && ./install_dependencies.sh <> + run_tests: + parameters: + compiler: + default: "" + type: string + steps: + - run: chmod u+x run_tests.sh && ./run_tests.sh <> + +jobs: + build-linux-gcc: + machine: + image: ubuntu-2204:2022.04.2 #https://circleci.com/developer/machine/image/ubuntu-2204 pick LTS + steps: + - checkout + - install_dependencies + - run_tests + - store_artifacts: + path: ./Release/Linux/erpcgen/erpcgen + + build-linux-clang: + machine: + image: ubuntu-2204:2022.04.2 #https://circleci.com/developer/machine/image/ubuntu-2204 pick LTS + steps: + - checkout + - install_dependencies: + compiler: "clang" + - run_tests: + compiler: "clang" + # - store_artifacts: + # path: ./Release/Linux/erpcgen/erpcgen + + build-mac-gcc: + macos: + xcode: 12.5.1 # https://circleci.com/docs/using-macos/#supported-xcode-versions https://en.wikipedia.org/wiki/MacOS_version_history#Releases + resource_class: macos.x86.medium.gen2 + steps: + - checkout + - install_dependencies + - run_tests + - store_artifacts: + path: ./Release/Darwin/erpcgen/erpcgen + + build-mac-clang: + macos: + xcode: 12.5.1 # https://circleci.com/docs/using-macos/#supported-xcode-versions https://en.wikipedia.org/wiki/MacOS_version_history#Releases + resource_class: macos.x86.medium.gen2 + steps: + - checkout + - install_dependencies: + compiler: "clang" + - run_tests: + compiler: "clang" + # - store_artifacts: + # path: ./Release/Darwin/erpcgen/erpcgen + + build-windows-mingw: + executor: + name: win/default + size: large + steps: + - checkout + - run: powershell.exe .\install_dependencies.ps1 + - run: .\mingw64\bin\mingw32-make all + - run: .\mingw64\opt\bin\python3.exe .\test\run_unit_tests.py -m"..\\..\\mingw64\\bin\\mingw32-make" + # - store_artifacts: + # path: ./Release/MINGW64/erpcgen/erpcgen.exe + + build-windows-VS: + executor: + name: win/default + size: large + steps: + - checkout + - run: + name: Install VS buuildtools + no_output_timeout: 60m + command: powershell.exe .\install_dependencies.ps1 VS + - run: powershell.exe "& 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe' .\erpcgen\VisualStudio_v14\erpcgen.sln /property:Configuration=Release" + - store_artifacts: + path: ./erpcgen/VisualStudio_v14/Release/erpcgen.exe + +workflows: + build-workflow: + jobs: + - build-linux-gcc + - build-linux-clang + - build-mac-gcc + - build-mac-clang + - build-windows-mingw + - build-windows-VS diff --git a/packages/erpc-1.14.0/.clang-format b/packages/erpc-1.14.0/.clang-format new file mode 100644 index 0000000..6cec938 --- /dev/null +++ b/packages/erpc-1.14.0/.clang-format @@ -0,0 +1,80 @@ +#https://releases.llvm.org/16.0.0/tools/clang/docs/ClangFormatStyleOptions.html +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakBeforeMultilineStrings: true +BasedOnStyle: Google +#BinPackParameters : false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: false +ColumnLimit: 120 +ContinuationIndentWidth: 4 +DerivePointerAlignment: false +DisableFormat: false +IndentCaseLabels: true +IndentWrappedFunctionNames: false +IndentWidth: 4 +Language: Cpp +MaxEmptyLinesToKeep: 1 +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpacesBeforeTrailingComments: 1 +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +Standard: c++11 +TabWidth: 1 +UseTab: Never +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignEscapedNewlines: Left +AlignOperands: Align +AllowShortCaseLabelsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakInheritanceList: AfterColon +BreakConstructorInitializers: AfterColon +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 0 +Cpp11BracedListStyle: false +FixNamespaceComments: true +NamespaceIndentation: None +PointerAlignment: Right +SortIncludes: Never +SortUsingDeclarations: Lexicographic +SpacesInAngles: Never +SpaceAfterCStyleCast: false +SpaceInEmptyParentheses: false +SpacesInSquareBrackets: false +KeepEmptyLinesAtTheStartOfBlocks: true +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + BeforeWhile: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true + +IncludeBlocks: Preserve +IncludeCategories: + - Regex: "^<" # system includes + Priority: 10 + - Regex: '^"erpc_' # erpc public includes + Priority: 1 +CommentPragmas: "#" diff --git a/packages/erpc-1.14.0/.clang-format-ignore b/packages/erpc-1.14.0/.clang-format-ignore new file mode 100644 index 0000000..d103944 --- /dev/null +++ b/packages/erpc-1.14.0/.clang-format-ignore @@ -0,0 +1,9 @@ +#list of ignored files to format +./erpc_c/port/erpc_serial.cpp +./erpcgen/src/cpptemplate/cpptempl.hpp +./erpcgen/src/cpptemplate/cpptempl.cpp +./erpcgen/src/cpptemplate/cpptempl_test.cpp +./erpcgen/test/test_includes/test_includes_union.h +./test/common/gtest/gtest.h +./test/common/gtest/gtest.cpp +./test/common/retarget_cpp_streamed_io.c diff --git a/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/bug_report.md b/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..911ad25 --- /dev/null +++ b/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,43 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG] " +labels: bug +assignees: '' + +--- + +## Describe the bug + + +## To Reproduce + + +## Expected behavior + + +## Screenshots + + +## Desktop (please complete the following information) + +- OS: +- eRPC Version: + +## Steps you didn't forgot to do + +- [ ] I checked if there is no related issue opened/closed. +- [ ] I checked that there doesn't exist opened PR which is solving this issue. + +## Additional context + diff --git a/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/feature_request.md b/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..b525e53 --- /dev/null +++ b/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,33 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FEATURE]" +labels: enhancement +assignees: '' + +--- + +## Is your feature request related to a problem? Please describe + + +## Describe the solution you'd like + + +## Describe alternatives you've considered + + +## Steps you didn't forgot to do + +- [ ] I checked if there is no related issue opened/closed. +- [ ] I checked that there doesn't exist opened PR which is solving this issue. + +## Additional context + diff --git a/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/question.md b/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..1f85d3b --- /dev/null +++ b/packages/erpc-1.14.0/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,19 @@ +--- +name: Question +about: Question regarding to eRPC +title: "[QUESTION]" +labels: question +assignees: '' + +--- + +## If you didn't find answer in existing open/closed issues you may ask here + + +## Steps you didn't forgot to do + +- [ ] I checked if there is no related issue opened/closed. +- [ ] I checked that there doesn't exist opened/closed PR which is solving this issue. +- [ ] I looked in documentation if there is related information. diff --git a/packages/erpc-1.14.0/.github/PULL_REQUEST_TEMPLATE.md b/packages/erpc-1.14.0/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..6e792f9 --- /dev/null +++ b/packages/erpc-1.14.0/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,44 @@ +# Pull request + +## Choose Correct + +- [ ] bug +- [ ] feature + +## Describe the pull request + + +## To Reproduce + + +## Expected behavior + + +## Screenshots + + +## Desktop (please complete the following information): + +- OS: +- eRPC Version: + +## Steps you didn't forgot to do + +- [ ] I checked if other PR isn't solving this issue. +- [ ] I read Contribution details and did appropriate actions. +- [ ] PR code is tested. +- [ ] PR code is formatted. +- [ ] Allow edits from maintainers pull request option is set (recommended). + +## Additional context + diff --git a/packages/erpc-1.14.0/.github/workflows/clang-format.yml b/packages/erpc-1.14.0/.github/workflows/clang-format.yml new file mode 100644 index 0000000..9f37eaf --- /dev/null +++ b/packages/erpc-1.14.0/.github/workflows/clang-format.yml @@ -0,0 +1,22 @@ +name: clang-format lint + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: DoozyX/clang-format-lint-action@v0.16.2 + with: + source: '.' + exclude: './examples/zephyr/matrix_multiply_mbox/remote/src/service + ./examples/zephyr/matrix_multiply_mbox/src/service + ./examples/zephyr/matrix_multiply_rpmsglite/remote/src/service + ./examples/zephyr/matrix_multiply_rpmsglite/src/service + ./examples/zephyr/matrix_multiply_tcp/src/service + ./examples/zephyr/matrix_multiply_uart/src/service + ./examples/MCUXPRESSO_SDK/erpc_matrix_multiply/service + ./examples/MCUXPRESSO_SDK/erpc_two_way_rpc/service' + clangFormatVersion: 16 diff --git a/packages/erpc-1.14.0/.github/workflows/greetings.yml b/packages/erpc-1.14.0/.github/workflows/greetings.yml new file mode 100644 index 0000000..21ffe6c --- /dev/null +++ b/packages/erpc-1.14.0/.github/workflows/greetings.yml @@ -0,0 +1,16 @@ +name: Greetings + +on: [pull_request, issues] + +jobs: + greeting: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: 'Hi eRPC user. Thank you for your interest and welcome. We hope you will enjoy this framework well.' + pr-message: 'Hi eRPC user. Thank you for your PR. We are appreciating that and we will try to review it as soon as possible. We hope you are enjoying this framework so far.' diff --git a/packages/erpc-1.14.0/.gitignore b/packages/erpc-1.14.0/.gitignore new file mode 100644 index 0000000..1b0ce80 --- /dev/null +++ b/packages/erpc-1.14.0/.gitignore @@ -0,0 +1,116 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# NOTE! Please use 'git ls-files -i --exclude-standard' +# command after changing this file, to see if there are +# any tracked files which get ignored after the change. +# +# Normal rules +# +*.o +*.o.* +*.a +*.ko +*.so +*.so.dbg +*.mod.c +*.i +*.lst +*.symtypes +*.order +*.elf +*.bin +*.gz +._* +.DS_Store +*.swp +*.tmp +*.log + +# +# Top-level generic files +# +[rR]elease +[dD]ebug +*_release +tags +TAGS +vmlinux +System.map +Module.markers +Module.symvers +!.gitignore +!.mailmap + +# +# Generated include files +# + +# stgit generated dirs +patches-* + +# quilt's files +patches +series +*.patch + +# cscope files +cscope.* +ncscope.* + +*.orig +*~ +\#*# +workspace +.BUILD* +~* + +# Windows project stuff +*.suo +*.sdf +*.opensdf + +# Xcode user state +*.xcbkptlist +*.xcuserstate + +# Python bytecode +*.pyc +__pycache__ +.pytest_cache + +# IAR temp files +EW*.tmp + +# Xcode build folders +DerivedData/ +Build/ + +# Generated output +erpcgen-output +*.stackdump +*.tags* +/lib +armgcc +gcc +atl +kds +iar +mdk +lpcx +tags + +format-files-to-commit.rb +language\.settings\.xml +*.vsix +null.d +boost.7z +boost*/ +mingw.7z +mingw64/ +vs_BuildTools* + +# Zephyr's repo link +__repo__/ \ No newline at end of file diff --git a/packages/erpc-1.14.0/.gitpod.Dockerfile b/packages/erpc-1.14.0/.gitpod.Dockerfile new file mode 100644 index 0000000..f8e49f2 --- /dev/null +++ b/packages/erpc-1.14.0/.gitpod.Dockerfile @@ -0,0 +1,7 @@ +FROM gitpod/workspace-full + +# Install custom tools, runtimes, etc. +# For example "bastet", a command-line tetris clone: +# RUN brew install bastet +# +# More information: https://www.gitpod.io/docs/config-docker/ diff --git a/packages/erpc-1.14.0/.gitpod.yml b/packages/erpc-1.14.0/.gitpod.yml new file mode 100644 index 0000000..d1bad91 --- /dev/null +++ b/packages/erpc-1.14.0/.gitpod.yml @@ -0,0 +1,6 @@ +image: + file: .gitpod.Dockerfile + - command: apt-get update && apt-get install flex + +tasks: + - init: make diff --git a/packages/erpc-1.14.0/.idea/.gitignore b/packages/erpc-1.14.0/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/packages/erpc-1.14.0/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/packages/erpc-1.14.0/.idea/codeStyles/Project.xml b/packages/erpc-1.14.0/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..35c56fc --- /dev/null +++ b/packages/erpc-1.14.0/.idea/codeStyles/Project.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/erpc-1.14.0/.idea/codeStyles/codeStyleConfig.xml b/packages/erpc-1.14.0/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/packages/erpc-1.14.0/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/packages/erpc-1.14.0/.idea/editor.xml b/packages/erpc-1.14.0/.idea/editor.xml new file mode 100644 index 0000000..3d63c62 --- /dev/null +++ b/packages/erpc-1.14.0/.idea/editor.xml @@ -0,0 +1,250 @@ + + + + + \ No newline at end of file diff --git a/packages/erpc-1.14.0/.idea/erpc-1.14.0.iml b/packages/erpc-1.14.0/.idea/erpc-1.14.0.iml new file mode 100644 index 0000000..4c94235 --- /dev/null +++ b/packages/erpc-1.14.0/.idea/erpc-1.14.0.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/packages/erpc-1.14.0/.idea/misc.xml b/packages/erpc-1.14.0/.idea/misc.xml new file mode 100644 index 0000000..0b76fe5 --- /dev/null +++ b/packages/erpc-1.14.0/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/packages/erpc-1.14.0/.idea/modules.xml b/packages/erpc-1.14.0/.idea/modules.xml new file mode 100644 index 0000000..02d34b1 --- /dev/null +++ b/packages/erpc-1.14.0/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/erpc-1.14.0/CHANGELOG.md b/packages/erpc-1.14.0/CHANGELOG.md new file mode 100644 index 0000000..4fc46d1 --- /dev/null +++ b/packages/erpc-1.14.0/CHANGELOG.md @@ -0,0 +1,374 @@ +# Changelog eRPC + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.14.0] + +### Added + +- Added Cmake/Kconfig support. +- Made java code jdk11 compliant, GitHub PR #432. +- Added imxrt1186 support into mu transport layer. +- erpcgen: Added assert for listType before usage, GitHub PR #406. + +### Fixed + +- eRPC: Sources reformatted. +- erpc: Fixed typo in semaphore get (mutex -> semaphore), and write it can fail in case of timeout, GitHub PR #446. +- erpc: Free the arbitrated client token from client manager, GitHub PR #444. +- erpc: Fixed Makefile, install the erpc_simple_server header, GitHub PR #447. +- erpc_python: Fixed possible AttributeError and OSError on calling TCPTransport.close(), GitHub PR #438. +- Examples and tests consolidated. + +## [1.13.0] + +### Added + +- erpc: Add BSD-3 license to endianness agnostic files, GitHub PR #417. +- eRPC: Add new Zephyr-related transports (zephyr_uart, zephyr_mbox). +- eRPC: Add new Zephyr-related examples. + +### Fixed + +- eRPC,erpcgen: Fixing/improving markdown files, GitHub PR #395. +- eRPC: Fix Python client TCPTransports not being able to close, GitHub PR #390. +- eRPC,erpcgen: Align switch brackets, GitHub PR #396. +- erpc: Fix zephyr uart transport, GitHub PR #410. +- erpc: UART ZEPHYR Transport stop to work after a few transactions when using USB-CDC resolved, GitHub PR #420. + +### Removed + +- eRPC,erpcgen: Remove cstbool library, GitHub PR #403. + +## [1.12.0] + +### Added + +- eRPC: Add dynamic/static option for transport init, GitHub PR #361. +- eRPC,erpcgen: Winsock2 support, GitHub PR #365. +- eRPC,erpcgen: Feature/support multiple clients, GitHub PR #271. +- eRPC,erpcgen: Feature/buffer head - Framed transport header data stored in MessageBuffer, GitHub PR #378. +- eRPC,erpcgen: Add experimental Java support. + +### Fixed + +- eRPC: Fix receive error value for spidev, GitHub PR #363. +- eRPC: UartTransport::init adaptation to changed driver. +- eRPC: Fix typo in assert, GitHub PR #371. +- eRPC,erpcgen: Move enums to enum classes, GitHub PR #379. +- eRPC: Fixed rpmsg tty transport to work with serial transport, GitHub PR #373. + +## [1.11.0] + +### Fixed + +- eRPC: Makefiles update, GitHub PR #301. +- eRPC: Resolving warnings in Python, GitHub PR #325. +- eRPC: Python3.8 is not ready for usage of typing.Any type, GitHub PR #325. +- eRPC: Improved codec function to use reference instead of address, GitHub PR #324. +- eRPC: Fix NULL check for pending client creation, GitHub PR #341. +- eRPC: Replace sprintf with snprintf, GitHub PR #343. +- eRPC: Use MU_SendMsg blocking call in MU transport. +- eRPC: New LPSPI and LPI2C transport layers. +- eRPC: Freeing static objects, GitHub PR #353. +- eRPC: Fixed casting in deinit functions, GitHub PR #354. +- eRPC: Align LIBUSBSIO.GetNumPorts API use with libusbsio python module v. 2.1.11. +- erpcgen: Renamed temp variable to more generic one, GitHub PR #321. +- erpcgen: Add check that string read is not more than max length, GitHub PR #328. +- erpcgen: Move to g++ in pytest, GitHub PR #335. +- erpcgen: Use build=release for make, GitHub PR #334. +- erpcgen: Removed boost dependency, GitHub PR #346. +- erpcgen: Mingw support, GitHub PR #344. +- erpcgen: VS build update, GitHub PR #347. +- erpcgen: Modified name for common types macro scope, GitHub PR #337. +- erpcgen: Fixed memcpy for template, GitHub PR #352. +- eRPC,erpcgen: Change default build target to release + adding artefacts, GitHub PR #334. +- eRPC,erpcgen: Remove redundant includes, GitHub PR #338. +- eRPC,erpcgen: Many minor code improvements, GitHub PR #323. + +## [1.10.0] + +### Fixed + +- eRPC: MU transport layer switched to blocking MU_SendMsg() API use. + +## [1.10.0] + +### Added + +- eRPC: Add TCP_NODELAY option to python, GitHub PR #298. + +### Fixed + +- eRPC: MUTransport adaptation to new supported SoCs. +- eRPC: Simplifying CI with installing dependencies using shell script, GitHub PR #267. +- eRPC: Using event for waiting for sock connection in TCP python server, formatting python code, C specific includes, GitHub PR #269. +- eRPC: Endianness agnostic update, GitHub PR #276. +- eRPC: Assertion added for functions which are returning status on freeing memory, GitHub PR #277. +- eRPC: Fixed closing arbitrator server in unit tests, GitHub PR #293. +- eRPC: Makefile updated to reflect the correct header names, GitHub PR #295. +- eRPC: Compare value length to used length() in reading data from message buffer, GitHub PR #297. +- eRPC: Replace EXPECT_TRUE with EXPECT_EQ in unit tests, GitHub PR #318. +- eRPC: Adapt rpmsg_lite based transports to changed rpmsg_lite_wait_for_link_up() API parameters. +- eRPC, erpcgen: Better distuingish which file can and cannot by linked by C linker, GitHub PR #266. +- eRPC, erpcgen: Stop checking if pointer is NULL before sending it to the erpc_free function, GitHub PR #275. +- eRPC, erpcgen: Changed api to count with more interfaces, GitHub PR #304. +- erpcgen: Check before reading from heap the buffer boundaries, GitHub PR #287. +- erpcgen: Several fixes for tests and CI, GitHub PR #289. +- erpcgen: Refactoring erpcgen code, GitHub PR #302. +- erpcgen: Fixed assigning const value to enum, GitHub PR #309. +- erpcgen: Enable runTesttest_enumErrorCode_allDirection, serialize enums as int32 instead of uint32. + +## [1.9.1] + +### Fixed + +- eRPC: Construct the USB CDC transport, rather than a client, GitHub PR #220. +- eRPC: Fix premature import of package, causing failure when attempting installation of Python library in a clean environment, GitHub PR #38, #226. +- eRPC: Improve python detection in make, GitHub PR #225. +- eRPC: Fix several warnings with deprecated call in pytest, GitHub PR #227. +- eRPC: Fix freeing union members when only default need be freed, GitHub PR #228. +- eRPC: Fix making test under Linux, GitHub PR #229. +- eRPC: Assert costumizing, GitHub PR #148. +- eRPC: Fix corrupt clientList bug in TransportArbitrator, GitHub PR #199. +- eRPC: Fix build issue when invoking g++ with -Wno-error=free-nonheap-object, GitHub PR #233. +- eRPC: Fix inout cases, GitHub PR #237. +- eRPC: Remove ERPC_PRE_POST_ACTION dependency on return type, GitHub PR #238. +- eRPC: Adding NULL to ptr when codec function failed, fixing memcpy when fail is present during deserialization, GitHub PR #253. +- eRPC: MessageBuffer usage improvement, GitHub PR #258. +- eRPC: Get rid for serial and enum34 dependency (enum34 is in python3 since 3.4 (from 2014)), GitHub PR #247. +- eRPC: Several MISRA violations addressed. +- eRPC: Fix timeout for Freertos semaphore, GitHub PR #251. +- eRPC: Use of rpmsg_lite_wait_for_link_up() in rpmsg_lite based transports, GitHub PR #223. +- eRPC: Fix codec nullptr dereferencing, GitHub PR #264. +- erpcgen: Fix two syntax errors in erpcgen Python output related to non-encapsulated unions, improved test for union, GitHub PR #206, #224. +- erpcgen: Fix serialization of list/binary types, GitHub PR #240. +- erpcgen: Fix empty list parsing, GitHub PR #72. +- erpcgen: Fix templates for malloc errors, GitHub PR #110. +- erpcgen: Get rid of encapsulated union declarations in global scale, improve enum usage in unions, GitHub PR #249, #250. +- erpcgen: Fix compile error:UniqueIdChecker.cpp:156:104:'sort' was not declared, GitHub PR #265. + +## [1.9.0] + +### Added + +- eRPC: Allow used LIBUSBSIO device index being specified from the Python command line argument. + +### Fixed + +- eRPC: Improving template usage, GitHub PR #153. +- eRPC: run_clang_format.py cleanup, GitHub PR #177. +- eRPC: Build TCP transport setup code into liberpc, GitHub PR #179. +- eRPC: Fix multiple definitions of g_client error, GitHub PR #180. +- eRPC: Fix memset past end of buffer in erpc_setup_mbf_static.cpp, GitHub PR #184. +- eRPC: Fix deprecated error with newer pytest version, GitHub PR #203. +- eRPC, erpcgen: Static allocation support and usage of rpmsg static FreeRTOSs related APi, GitHub PR #168, #169. +- erpcgen: Remove redundant module imports in erpcgen, GitHub PR #196. + +## [1.8.1] + +### Added + +- eRPC: New i2c_slave_transport trasnport introduced. + +### Fixed + +- eRPC: Fix misra erpc c, GitHub PR #158. +- eRPC: Allow conditional compilation of message_loggers and pre_post_action. +- eRPC: (D)SPI slave transports updated to avoid busy loops in rtos environments. +- erpcgen: Re-implement EnumMember::hasValue(), GitHub PR #159. +- erpcgen: Fixing several misra issues in shim code, erpcgen and unit tests updated, GitHub PR #156. +- erpcgen: Fix bison file, GitHub PR #156. + +## [1.8.0] + +### Added + +- eRPC: Support win32 thread, GitHub PR #108. +- eRPC: Add mbed support for malloc() and free(), GitHub PR #92. +- eRPC: Introduced pre and post callbacks for eRPC call, GitHub PR #131. +- eRPC: Introduced new USB CDC transport. +- eRPC: Introduced new Linux spidev-based transport. +- eRPC: Added formatting extension for VSC, GitHub PR #134. +- erpcgen: Introduce ustring type for unsigned char and force cast to char*, GitHub PR #125. + +### Fixed + +- eRPC: Update makefile. +- eRPC: Fixed warnings and error with using MessageLoggers, GitHub PR #127. +- eRPC: Extend error msg for python server service handle function, GitHub PR #132. +- eRPC: Update CMSIS UART transport layer to avoid busy loops in rtos environments, introduce semaphores. +- eRPC: SPI transport update to allow usage without handshaking GPIO. +- eRPC: Native _WIN32 erpc serial transport and threading. +- eRPC: Arbitrator deadlock fix, TCP transport updated, TCP setup functions introduced, GitHub PR #121. +- eRPC: Update of matrix_multiply.py example: Add --serial and --baud argument, GitHub PR #137. +- eRPC: Update of .clang-format, GitHub PR #140. +- eRPC: Update of erpc_framed_transport.cpp: return error if received message has zero length, GitHub PR #141. +- eRPC, erpcgen: Fixed error messages produced by -Wall -Wextra -Wshadow -pedantic-errors compiler flags, GitHub PR #136, #139. +- eRPC, erpcgen: Core re-formatted using Clang version 10. +- erpcgen: Enable deallocation in server shim code when callback/function pointer used as out parameter in IDL. +- erpcgen: Removed '$' character from generated symbol name in '_$union' suffix, GitHub PR #103. +- erpcgen: Resolved mismatch between C++ and Python for callback index type, GitHub PR #111. +- erpcgen: Python generator improvements, GitHub PR #100, #118. +- erpcgen: Fixed error messages produced by -Wall -Wextra -Wshadow -pedantic-errors compiler flags, GitHub PR #136. + + +## [1.7.4] + +### Added + +- eRPC: Support MU transport unit testing. +- eRPC: Adding mbed os support. + +### Fixed + +- eRPC: Unit test code updated to handle service add and remove operations. +- eRPC: Several MISRA issues in rpmsg-based transports addressed. +- eRPC: Fixed Linux/TCP acceptance tests in release target. +- eRPC: Minor documentation updates, code formatting. +- erpcgen: Whitespace removed from C common header template. + +## [1.7.3] + +### Fixed + +- eRPC: Improved the test_callbacks logic to be more understandable and to allow requested callback execution on the server side. +- eRPC: TransportArbitrator::prepareClientReceive modified to avoid incorrect return value type. +- eRPC: The ClientManager and the ArbitratedClientManager updated to avoid performing client requests when the previous serialization phase fails. +- erpcgen: Generate the shim code for destroy of statically allocated services. + +## [1.7.2] + +### Added + +- eRPC: Add missing doxygen comments for transports. + +### Fixed + +- eRPC: Improved support of const types. +- eRPC: Fixed Mac build. +- eRPC: Fixed serializing python list. +- eRPC: Documentation update. + +## [1.7.1] + +### Fixed + +- eRPC: Fixed semaphore in static message buffer factory. +- erpcgen: Fixed MU received error flag. +- erpcgen: Fixed tcp transport. + +## [1.7.0] + +### Added + +- eRPC: List names are based on their types. Names are more deterministic. +- eRPC: Service objects are as a default created as global static objects. +- eRPC: Added missing doxygen comments. +- eRPC: Added support for 64bit numbers. +- eRPC: Added support of program language specific annotations. + +### Fixed + +- eRPC: Improved code size of generated code. +- eRPC: Generating crc value is optional. +- eRPC: Fixed CMSIS Uart driver. Removed dependency on KSDK. +- eRPC: Forbid users use reserved words. +- eRPC: Removed outByref for function parameters. +- eRPC: Optimized code style of callback functions. + +## [1.6.0] + +### Added + +- eRPC: Added \@nullable support for scalar types. + +### Fixed + +- eRPC: Improved code size of generated code. +- eRPC: Improved eRPC nested calls. +- eRPC: Improved eRPC list length variable serialization. + +## [1.5.0] + +### Added + +- eRPC: Added support for unions type non-wrapped by structure. +- eRPC: Added callbacks support. +- eRPC: Added support \@external annotation for functions. +- eRPC: Added support \@name annotation. +- eRPC: Added Messaging Unit transport layer. +- eRPC: Added RPMSG Lite RTOS TTY transport layer. +- eRPC: Added version verification and IDL version verification between eRPC code and eRPC generated shim code. +- eRPC: Added support of shared memory pointer. +- eRPC: Added annotation to forbid generating const keyword for function parameters. +- eRPC: Added python matrix multiply example. +- eRPC: Added nested call support. +- eRPC: Added struct member "byref" option support. +- eRPC: Added support of forward declarations of structures +- eRPC: Added Python RPMsg Multiendpoint kernel module support +- eRPC: Added eRPC sniffer tool + +## [1.4.0] + +### Added + +- eRPC: New RPMsg-Lite Zero Copy (RPMsgZC) transport layer. + +### Fixed + +- eRPC: win_flex_bison.zip for windows updated. +- eRPC: Use one codec (instead of inCodec outCodec). + +## [1.3.0] + +### Added + +- eRPC: New annotation types introduced (\@length, \@max_length, ...). +- eRPC: Support for running both erpc client and erpc server on one side. +- eRPC: New transport layers for (LP)UART, (D)SPI. +- eRPC: Error handling support. + +## [1.2.0] + +### Added + +- eRPC source directory organization changed. +- Many eRPC improvements. + +## [1.1.0] + +### Added + +- Multicore SDK 1.1.0 ported to KSDK 2.0.0. + +## [1.0.0] + +### Added + +- Initial Release + + +[unreleased]: https://github.com/EmbeddedRPC/erpc/compare/1.14.0...HEAD +[1.14.0]: https://github.com/EmbeddedRPC/erpc/compare/1.13.0...1.14.0 +[1.13.0]: https://github.com/EmbeddedRPC/erpc/compare/1.12.0...1.13.0 +[1.12.0]: https://github.com/EmbeddedRPC/erpc/compare/1.11.0...1.12.0 +[1.11.0]: https://github.com/EmbeddedRPC/erpc/compare/1.10.0...1.11.0 +[1.10.0]: https://github.com/EmbeddedRPC/erpc/compare/1.9.1...1.10.0 +[1.9.1]: https://github.com/EmbeddedRPC/erpc/compare/1.9.0...1.9.1 +[1.9.0]: https://github.com/EmbeddedRPC/erpc/compare/1.8.1...1.9.0 +[1.8.1]: https://github.com/EmbeddedRPC/erpc/compare/1.8.0...1.8.1 +[1.8.0]: https://github.com/EmbeddedRPC/erpc/compare/1.7.4...1.8.0 +[1.7.4]: https://github.com/EmbeddedRPC/erpc/compare/1.7.3...1.7.4 +[1.7.3]: https://github.com/EmbeddedRPC/erpc/compare/1.7.2...1.7.3 +[1.7.2]: https://github.com/EmbeddedRPC/erpc/compare/1.7.1...1.7.2 +[1.7.1]: https://github.com/EmbeddedRPC/erpc/compare/1.7.0...1.7.1 +[1.7.0]: https://github.com/EmbeddedRPC/erpc/compare/1.6.0...1.7.0 +[1.6.0]: https://github.com/EmbeddedRPC/erpc/compare/1.5.0...1.6.0 +[1.5.0]: https://github.com/EmbeddedRPC/erpc/compare/1.4.0...1.5.0 +[1.4.0]: https://github.com/EmbeddedRPC/erpc/releases/tag/1.4.0 diff --git a/packages/erpc-1.14.0/CMakeLists.txt b/packages/erpc-1.14.0/CMakeLists.txt new file mode 100644 index 0000000..f902777 --- /dev/null +++ b/packages/erpc-1.14.0/CMakeLists.txt @@ -0,0 +1,58 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +cmake_minimum_required(VERSION 3.20) +project(eRPC) + +############################################################################### +# Define basic variables +############################################################################### +set(ERPC_BASE ${CMAKE_CURRENT_LIST_DIR}) + +set(ERPC_ERPCGEN ${ERPC_BASE}/erpcgen) +set(ERPC_C ${ERPC_BASE}/erpc_c) +set(ERPC_TEST ${ERPC_BASE}/test) +set(ERPC_EXAMPLES ${ERPC_BASE}/examples) + +############################################################################### +# Includes required modules +############################################################################### +include(${ERPC_BASE}/cmake/extensions.cmake) +include(${ERPC_BASE}/cmake/python.cmake) +include(${ERPC_BASE}/cmake/kconfig.cmake) +include(${ERPC_BASE}/cmake/erpc_utils.cmake) + +############################################################################### +# Add components base on Kconfig +############################################################################### + +if(CONFIG_REQUIRE_ERPCGEN) + if(CONFIG_ERPC_GENERATOR) + set(ERPCGEN_EXECUTABLE $) + else() + find_program(ERPCGEN_EXECUTABLE NAMES erpcgen) + + if(NOT ERPCGEN_EXECUTABLE) + message(FATAL_ERROR "It was not possible to find the erpcgen executable. Enable ERPC_GENERATOR in Kconfig to build erpcgen from source or add 'erpcgen' to PATH.") + endif() + endif() +endif() + +if(CONFIG_ERPC_GENERATOR) + add_subdirectory(${ERPC_ERPCGEN}) +endif() + +if(CONFIG_ERPC_LIB) + add_subdirectory(${ERPC_C}) +endif() + +if(CONFIG_ERPC_TESTS) + add_subdirectory(${ERPC_TEST}) +endif() + +if(CONFIG_ERPC_EXAMPLES) + add_subdirectory(${ERPC_EXAMPLES}) +endif() \ No newline at end of file diff --git a/packages/erpc-1.14.0/CMakePresets.json b/packages/erpc-1.14.0/CMakePresets.json new file mode 100644 index 0000000..1933242 --- /dev/null +++ b/packages/erpc-1.14.0/CMakePresets.json @@ -0,0 +1,24 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + "configurePresets": [ + { + "name": "mingw64", + "displayName": "Mingw64 eRPC config", + "description": "Default Mingw64 preset for eRPC", + "generator": "MinGW Makefiles", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_C_COMPILER": "gcc", + "CMAKE_CXX_COMPILER": "g++" + }, + "environment": { + "PATH": "${sourceDir}/mingw64/bin;$penv{PATH}" + } + } + ] +} \ No newline at end of file diff --git a/packages/erpc-1.14.0/CONTRIBUTING.md b/packages/erpc-1.14.0/CONTRIBUTING.md new file mode 100644 index 0000000..ac860c9 --- /dev/null +++ b/packages/erpc-1.14.0/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contribution + +Contribution details are described in our [wiki/Contributing](https://github.com/EmbeddedRPC/erpc/wiki/Contributing) diff --git a/packages/erpc-1.14.0/Kconfig b/packages/erpc-1.14.0/Kconfig new file mode 100644 index 0000000..adc03ba --- /dev/null +++ b/packages/erpc-1.14.0/Kconfig @@ -0,0 +1,177 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +config ERPC_GENERATOR + bool "Build eRPC Generator" + default y + +config REQUIRE_ERPCGEN + bool + default n + +config ERPC_LIB + bool "Build eRPC C Library" + default y + +menuconfig ERPC_TESTS + bool "Build eRPC Tests" + default n + select REQUIRE_ERPCGEN + +if ERPC_TESTS + menu "Test transport" + menuconfig ERPC_TESTS.transport.tcp + bool "Test transport TCP" + default y + + if ERPC_TESTS.transport.tcp + config ERPC_TESTS.transport.tcp.host + string "TCP Host" + default "localhost" + + config ERPC_TESTS.transport.tcp.port + int "TCP Port" + default 12345 + endif + + menuconfig ERPC_TESTS.transport.serial + bool "Test transport Serial" + default n + + if ERPC_TESTS.transport.serial + config ERPC_TESTS.transport.serial.port + string "Serial port" + default "localhost" + + config ERPC_TESTS.transport.serial.baud + int "Baud" + default 115200 + endif + endmenu + + config ERPC_TESTS.client + bool "Build test's client side" + default y + + config ERPC_TESTS.server + bool "Build test's server side" + default y + + menu "Test cases" + config ERPC_TESTS.testcase.test_annotations + bool "Build test_annotations" + default y + config ERPC_TESTS.testcase.test_arbitrator + bool "Build test_arbitrator" + default y + config ERPC_TESTS.testcase.test_arrays + bool "Build test_arrays" + default y + config ERPC_TESTS.testcase.test_binary + bool "Build test_binary" + default y + config ERPC_TESTS.testcase.test_builtin + bool "Build test_builtin" + default y + config ERPC_TESTS.testcase.test_callbacks + bool "Build test_callbacks" + default y + config ERPC_TESTS.testcase.test_const + bool "Build test_const" + default y + config ERPC_TESTS.testcase.test_enums + bool "Build test_enums" + default y + config ERPC_TESTS.testcase.test_lists + bool "Build test_lists" + default y + config ERPC_TESTS.testcase.test_shared + bool "Build test_shared" + default y + config ERPC_TESTS.testcase.test_struct + bool "Build test_struct" + default y + config ERPC_TESTS.testcase.test_typedef + bool "Build test_typedef" + default y + config ERPC_TESTS.testcase.test_unions + bool "Build test_unions" + default y + endmenu + +endif + +menuconfig ERPC_EXAMPLES + bool "Build eRPC Examples" + default n + select REQUIRE_ERPCGEN + +if ERPC_EXAMPLES + menuconfig ERPC_MATRIX_MULTIPLY_TCP + bool "Matrix Multiply TCP example" + default n + select REQUIRE_ERPCGEN + + if ERPC_MATRIX_MULTIPLY_TCP + config ERPC_MATRIX_MULTIPLY_TCP.host + string "TCP Host" + default "localhost" + + config ERPC_MATRIX_MULTIPLY_TCP.port + int "TCP Port" + default 8811 + + config ERPC_MATRIX_MULTIPLY_TCP.c + bool "Build C version of the demo" + default y + config ERPC_MATRIX_MULTIPLY_TCP.cpp + bool "Build C++ version of the demo" + default y + endif + + menuconfig ERPC_MATRIX_MULTIPLY_UART + bool "Matrix Multiply UART example" + default n + select REQUIRE_ERPCGEN + + if ERPC_MATRIX_MULTIPLY_UART + config ERPC_MATRIX_MULTIPLY_UART.serial + string "Serial port" + default "localhost" + + config ERPC_MATRIX_MULTIPLY_UART.baud + int "Baud" + default 115200 + + config ERPC_MATRIX_MULTIPLY_UART.c + bool "Build C version of the demo" + default y + config ERPC_MATRIX_MULTIPLY_UART.cpp + bool "Build C++ version of the demo" + default y + endif + + menuconfig ERPC_HELLO_WORLD + bool "Hello World example" + default n + select REQUIRE_ERPCGEN + + if ERPC_HELLO_WORLD + config ERPC_HELLO_WORLD.c + bool "Build C version of the demo" + default y + config ERPC_HELLO_WORLD.cpp + bool "Build C++ version of the demo" + default y + config ERPC_HELLO_WORLD.python + bool "Generate shim code for Python" + default y + config ERPC_HELLO_WORLD.java + bool "Generate shim code for Java" + default y + endif +endif + diff --git a/packages/erpc-1.14.0/LICENSE b/packages/erpc-1.14.0/LICENSE new file mode 100644 index 0000000..76727b5 --- /dev/null +++ b/packages/erpc-1.14.0/LICENSE @@ -0,0 +1,26 @@ +The BSD 3 Clause License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/erpc-1.14.0/Makefile b/packages/erpc-1.14.0/Makefile new file mode 100644 index 0000000..9258e5c --- /dev/null +++ b/packages/erpc-1.14.0/Makefile @@ -0,0 +1,96 @@ +#------------------------------------------------------------------------------- +# Copyright (C) 2014-2016 Freescale Semiconductor +# +# THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL FREESCALE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +#------------------------------------------------------------------------------- + +# +# Top-level Makefile. +# +# This file is responsible for building all libraries and applications. +# + +include mk/erpc_common.mk + +# Turn off parallel jobs for this makefile only. Child makefiles will still use the +# specified number of jobs. This isn't strictly necessary, and actually slows the build +# a little bit, but greatly improves the readability of the log output. +#.NOTPARALLEL: + +ifeq "$(is_linux)" "1" +ERPCSNIFFER = erpcsniffer +endif + +# Subdirectories to run make on. +TESTDIR = test +SUBDIRS_LIST = erpcgen $(ERPCSNIFFER) $(TESTDIR) +# test if all exists +SUBDIRS = $(foreach f,$(SUBDIRS_LIST), $(if $(wildcard $(f)), $(f))) + +# Default target. +.PHONY: default +default: erpc $(ERPCSNIFFER) erpcgen + +erpcsniffer: erpc + +.PHONY: erpc +erpc: + @$(MAKE) $(silent_make) -j$(MAKETHREADS) -r -C erpc_c + +.PHONY: install +install: erpc erpc_c erpcgen $(ERPCSNIFFER) + @$(MAKE) $(silent_make) -j$(MAKETHREADS) -r -C erpc_c install + @$(MAKE) $(silent_make) -j$(MAKETHREADS) -r -C erpcgen install +ifeq "$(is_linux)" "1" + @$(MAKE) $(silent_make) -j$(MAKETHREADS) -r -C erpcsniffer install +endif + +#make all target +.PHONY: all +all: erpc $(SUBDIRS) + +# Unit Test Targets +.PHONY: test-tcp +test-tcp: TESTTARGET := test-tcp +test-tcp: $(TESTDIR) + +.PHONY: test-serial +test-serial: TESTTARGET := test-serial +test-serial: $(TESTDIR) + +# Force rebuild +.PHONY: fresh +fresh: clean all + +# define clean_fun +# $(warning "$(at)$(POWERSHELL) "if (Test-Path $(1)) { $(rmc) $(1) }"") +# $(at)$(POWERSHELL) 'if (Test-Path $(1)) { $(rmc) $(1) }' +# endef + +# Target to clean everything. +.PHONY: clean +clean:: + @echo "Deleting output directories..." + @$(rmc) Debug Release + @$(rmc) out*.* + @$(rmc) erpc_outputs +# @$(call clean_fun,Debug,) +# @$(call clean_fun,Release,) +# @$(call clean_fun,erpc_outputs,) + @echo "done." + +# Process subdirs +include $(ERPC_ROOT)/mk/subdirs.mk + +.PHONY: os_name +os_name: + @echo $(os_name) diff --git a/packages/erpc-1.14.0/README.md b/packages/erpc-1.14.0/README.md new file mode 100644 index 0000000..ac91af0 --- /dev/null +++ b/packages/erpc-1.14.0/README.md @@ -0,0 +1,431 @@ +# MCUXpresso SDK : mcuxsdk-middleware-erpc + +## Overview +This repository is for MCUXpresso SDK eRPC middleware delivery and it contains eRPC component officially provided in NXP MCUXpresso SDK. This repository is part of the MCUXpresso SDK overall delivery which is composed of several sub-repositories/projects. Navigate to the top/parent repository [mcuxsdk](https://github.com/nxp-mcuxpresso/mcuxsdk-manifests/) for the complete delivery of MCUXpresso SDK to be able to build and run eRPC examples that are based on mcux-sdk-middleware-erpc component. + +## Documentation +Overall details can be reviewed here: [MCUXpresso SDK Online Documentation](https://mcuxpresso.nxp.com/mcuxsdk/latest/html/introduction/README.html) + +Visit [eRPC - Documentation](https://mcuxpresso.nxp.com/mcuxsdk/latest/html/middleware/multicore/erpc/README.html) to review details on the contents in this sub-repo. + +## Setup +Instructions on how to install the MCUXpresso SDK provided from GitHub via west manifest [Getting Started with SDK - Detailed Installation Instructions](https://mcuxpresso.nxp.com/mcuxsdk/latest/html/gsd/installation.html#installation) + +## Contribution +We welcome and encourage the community to submit patches directly to the eRPC project placed on github. Contributing can be managed via pull-requests. Before a pull-request is created the code should be tested and properly formatted. + +--------------------------------- + +# eRPC + +![GitHub all releases](https://img.shields.io/github/downloads/EmbeddedRPC/erpc/total) +[![GitHub License](https://img.shields.io/github/license/EmbeddedRPC/erpc)](/LICENSE) +[![Version](https://img.shields.io/github/v/release/EmbeddedRPC/erpc)](https://github.com/EmbeddedRPC/erpc/releases/latest) +![GitHub language count](https://img.shields.io/github/languages/count/EmbeddedRPC/erpc) +![GitHub top language](https://img.shields.io/github/languages/top/EmbeddedRPC/erpc) +![GitHub repo size](https://img.shields.io/github/repo-size/EmbeddedRPC/erpc) +![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/EmbeddedRPC/erpc) +[![GitHub forks](https://img.shields.io/github/forks/EmbeddedRPC/erpc)](https://github.com/EmbeddedRPC/erpc/forks) +![GitHub Repo stars](https://img.shields.io/github/stars/EmbeddedRPC/erpc) +![GitHub watchers](https://img.shields.io/github/watchers/EmbeddedRPC/erpc) +![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/t/EmbeddedRPC/erpc) +![GitHub commits difference between two branches/tags/commits](https://img.shields.io/github/commits-difference/EmbeddedRPC/erpc?base=main&head=develop&label=master%20behind%20develop%20commits) +[![Contributors](https://img.shields.io/github/contributors/EmbeddedRPC/erpc)](https://github.com/EmbeddedRPC/erpc/graphs/contributors) +[![Issues](https://img.shields.io/github/issues/EmbeddedRPC/erpc)](https://github.com/EmbeddedRPC/erpc/issues) +[![PRs Welcome](https://img.shields.io/github/issues-pr/EmbeddedRPC/erpc)](https://github.com/EmbeddedRPC/erpc/pulls) + +- [MCUXpresso SDK : mcuxsdk-middleware-erpc](#mcuxpresso-sdk--mcuxsdk-middleware-erpc) + - [Overview](#overview) + - [Documentation](#documentation) + - [Setup](#setup) + - [Contribution](#contribution) +- [eRPC](#erpc) + - [About](#about) + - [Releases](#releases) + - [Edge releases](#edge-releases) + - [Documentation](#documentation-1) + - [Examples](#examples) + - [References](#references) + - [Directories](#directories) + - [Building and installing](#building-and-installing) + - [Requirements](#requirements) + - [Windows](#windows) + - [Mac OS X](#mac-os-x) + - [Building](#building) + - [CMake and KConfig](#cmake-and-kconfig) + - [Make](#make) + - [Installing for Python](#installing-for-python) + - [Known issues and limitations](#known-issues-and-limitations) + - [Code providing](#code-providing) + +## About + +[![Open enhancement issues](https://img.shields.io/github/issues/EmbeddedRPC/erpc/enhancement?labelColor=blue&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) +[![Closed enhancement issues](https://img.shields.io/github/issues-closed/EmbeddedRPC/erpc/enhancement?labelColor=blue&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement) +[![Open enhancement PRs](https://img.shields.io/github/issues-pr/EmbeddedRPC/erpc/enhancement?labelColor=blue&color=black)](https://github.com/EmbeddedRPC/erpc/pulls?q=is%3Apr+is%3Aopen+label%3Aenhancement) +[![Closed enhancement PRs](https://img.shields.io/github/issues-pr-closed/EmbeddedRPC/erpc/enhancement?labelColor=blue&color=black)](https://github.com/EmbeddedRPC/erpc/pulls?q=is%3Apr+is%3Aclosed+label%3Aenhancement) + +[![Open bug issues](https://img.shields.io/github/issues/EmbeddedRPC/erpc/bug?labelColor=darkred&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aopen+label%3Abug) +[![Closed bug issues](https://img.shields.io/github/issues-closed/EmbeddedRPC/erpc/bug?labelColor=darkred&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aclosed+label%3Abug) +[![Open bug PRs](https://img.shields.io/github/issues-pr/EmbeddedRPC/erpc/bug?labelColor=darkred&color=black)](https://github.com/EmbeddedRPC/erpc/pulls?q=is%3Apr+is%3Aopen+label%3Abug) +[![Closed bug PRs](https://img.shields.io/github/issues-pr-closed/EmbeddedRPC/erpc/bug?labelColor=darkred&color=black)](https://github.com/EmbeddedRPC/erpc/pulls?q=is%3Apr+is%3Aclosed+label%3Abug) + +[![Open question issues](https://img.shields.io/github/issues/EmbeddedRPC/erpc/question?labelColor=darkviolet&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aopen+label%3Aquestion) +[![Closed question issues](https://img.shields.io/github/issues-closed/EmbeddedRPC/erpc/question?labelColor=darkviolet&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aclosed+label%3Aquestion) + +[![Open help-wanted issues](https://img.shields.io/github/issues/EmbeddedRPC/erpc/help%20wanted?labelColor=darkgreen&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aopen+label%3A%22help%20wanted%22) +[![Closed help-wanted issues](https://img.shields.io/github/issues-closed/EmbeddedRPC/erpc/help%20wanted?labelColor=darkgreen&color=black)](https://github.com/EmbeddedRPC/erpc/issues?q=is%3Aissue+is%3Aclosed+label%3A%22help%20wanted%22) + +eRPC (Embedded RPC) is an open source Remote Procedure Call (RPC) system for multichip embedded systems and heterogeneous multicore SoCs. + +Unlike other modern RPC systems, such as the excellent [Apache Thrift](http://thrift.apache.org), eRPC distinguishes itself by being designed for tightly coupled systems, using plain C for remote functions, and having a small code size (<5kB). It is not intended for high performance distributed systems over a network. + +eRPC does not force upon you any particular API style. It allows you to export existing C functions, without having to change their prototypes. (There are limits, of course.) And although the internal infrastructure is written in C++, most users will be able to use only the simple C setup APIs shown in the examples below. + +A code generator tool called `erpcgen` is included. It accepts input IDL files, having an `.erpc` extension, that have definitions of your data types and remote interfaces, and generates the shim code that handles serialization and invocation. `erpcgen` can generate either C/C++ or Python code. + +Example `.erpc` file: + +```C++ +// Define a data type. +enum LEDName { kRed, kGreen, kBlue } + +// An interface is a logical grouping of functions. +interface IO { + // Simple function declaration with an empty reply. + set_led(LEDName whichLed, bool onOrOff) -> void +} +``` + +Client side usage: + +```C +void example_client(void) { + erpc_transport_t transport; + erpc_mbf_t message_buffer_factory; + erpc_client_t client_manager; + + /* Init eRPC client infrastructure */ + transport = erpc_transport_cmsis_uart_init(Driver_USART0); + message_buffer_factory = erpc_mbf_dynamic_init(); + client_manager = erpc_client_init(transport, message_buffer_factory); + + /* init eRPC client IO service */ + initIO_client(client_manager); + + // Now we can call the remote function to turn on the green LED. + set_led(kGreen, true); + + /* deinit objects */ + deinitIO_client(); + erpc_client_deinit(client_manager); + erpc_mbf_dynamic_deinit(message_buffer_factory); + erpc_transport_tcp_deinit(transport); +} +``` + +```C++ +void example_client(void) { + erpc_transport_t transport; + erpc_mbf_t message_buffer_factory; + erpc_client_t client_manager; + + /* Init eRPC client infrastructure */ + transport = erpc_transport_cmsis_uart_init(Driver_USART0); + message_buffer_factory = erpc_mbf_dynamic_init(); + client_manager = erpc_client_init(transport, message_buffer_factory); + + /* scope for client service */ + { + /* init eRPC client IO service */ + IO_client client(client_manager); + + // Now we can call the remote function to turn on the green LED. + client.set_led(kGreen, true); + } + + /* deinit objects */ + erpc_client_deinit(client_manager); + erpc_mbf_dynamic_deinit(message_buffer_factory); + erpc_transport_tcp_deinit(transport); +} +``` + +Server side usage: + +```C +// Implement the remote function. +void set_led(LEDName whichLed, bool onOrOff) { + // implementation goes here +} + +void example_server(void) { + erpc_transport_t transport; + erpc_mbf_t message_buffer_factory; + erpc_server_t server; + erpc_service_t service = create_IO_service(); + + /* Init eRPC server infrastructure */ + transport = erpc_transport_cmsis_uart_init(Driver_USART0); + message_buffer_factory = erpc_mbf_dynamic_init(); + server = erpc_server_init(transport, message_buffer_factory); + + /* add custom service implementation to the server */ + erpc_add_service_to_server(server, service); + + // Run the server. + erpc_server_run(); + + /* deinit objects */ + destroy_IO_service(service); + erpc_server_deinit(server); + erpc_mbf_dynamic_deinit(message_buffer_factory); + erpc_transport_tcp_deinit(transport); +} +``` + +```C++ +// Implement the remote function. +class IO : public IO_interface +{ + /* eRPC call definition */ + void set_led(LEDName whichLed, bool onOrOff) override { + // implementation goes here + } +} + +void example_server(void) { + erpc_transport_t transport; + erpc_mbf_t message_buffer_factory; + erpc_server_t server; + IO IOImpl; + IO_service io(&IOImpl); + + /* Init eRPC server infrastructure */ + transport = erpc_transport_cmsis_uart_init(Driver_USART0); + message_buffer_factory = erpc_mbf_dynamic_init(); + server = erpc_server_init(transport, message_buffer_factory); + + /* add custom service implementation to the server */ + erpc_add_service_to_server(server, &io); + + /* poll for requests */ + erpc_status_t err = server.run(); + + /* deinit objects */ + erpc_server_deinit(server); + erpc_mbf_dynamic_deinit(message_buffer_factory); + erpc_transport_tcp_deinit(transport); +} +``` + +A number of transports are supported, and new transport classes are easy to write. + +Supported transports can be found in [erpc/erpc_c/transport](/erpc_c/transports) folder. E.g: + +* CMSIS UART +* NXP Kinetis SPI and DSPI +* POSIX and Windows serial port +* TCP/IP (mostly for testing) +* [NXP RPMsg-Lite / RPMsg TTY](https://github.com/nxp-mcuxpresso/rpmsg-lite) +* SPIdev Linux +* USB CDC +* NXP Messaging Unit + +eRPC is available with an unrestrictive BSD 3-clause license. See the [LICENSE file](https://github.com/EmbeddedRPC/erpc/blob/develop/LICENSE) for the full license text. + +## Releases + +[eRPC releases](https://github.com/EmbeddedRPC/erpc/releases) + +### Edge releases + +Edge releases can by found on [eRPC CircleCI](https://app.circleci.com/pipelines/github/EmbeddedRPC/erpc) webpage. Choose build of interest, then platform target and choose ARTIFACTS tab. Here you can find binary application from chosen build. + +## Documentation + +[Documentation](https://github.com/EmbeddedRPC/erpc/wiki) is in the `wiki` section. + +[eRPC Infrastructure documentation](https://embeddedrpc.github.io/) + +## Examples + +[Example IDL](examples/README.md) is available in the [examples/](/examples/) folder. + +Plenty of eRPC multicore and multiprocessor examples can be also found in NXP MCUXpressoSDK packages. Visit [https://mcuxpresso.nxp.com](https://mcuxpresso.nxp.com) to configure, build and download these packages. + +To get the board list with multicore support (eRPC included) use filtering based on Middleware and search for 'multicore' string. Once the selected package with the multicore middleware is downloaded, see + +/boards//multicore_examples for eRPC multicore examples (RPMsg_Lite or Messaging Unit transports used) or + +/boards//multiprocessor_examples for eRPC multiprocessor examples (UART or SPI transports used). + +eRPC examples use the 'erpc_' name prefix. + +Another way of getting NXP MCUXpressoSDK eRPC multicore and multiprocessor examples is using the [mcux-sdk](https://github.com/nxp-mcuxpresso/mcux-sdk) Github repo. Follow the description how to use the West tool +to clone and update the mcuxsdk repo in [readme Overview section](https://github.com/nxp-mcuxpresso/mcux-sdk#overview). Once done the armgcc eRPC examples can be found in + +mcuxsdk/examples//multicore_examples or in + +mcuxsdk/examples//multiprocessor_examples folders. + +You can use the evkmimxrt1170 as the board_name for instance. Similar to MCUXpressoSDK packages the eRPC examples use the 'erpc_' name prefix. + +## References + +This section provides links to interesting erpc-based projects, articles, blogs or guides: + +* [erpc (EmbeddedRPC) getting started notes](https://programmersought.com/article/37585084512/) +* [ERPC Linux Local Environment Construction and Use](https://programmersought.com/article/88827920353/) +* [The New Wio Terminal eRPC Firmware](https://www.hackster.io/Salmanfarisvp/the-new-wio-terminal-erpc-firmware-bfd8bd) + +## Directories + +[doc](/doc) - Documentation. + +[doxygen](/doxygen) - Configuration and support files for running Doxygen over the eRPC C++ infrastructure and erpcgen code. + +[erpc_c](/erpc_c) - Holds C/C++ infrastructure for eRPC. This is the code you will include in your application. + +[erpc_python](/erpc_python) - Holds Python version of the eRPC infrastructure. + +[erpcgen](/erpcgen) - Holds source code for erpcgen and makefiles or project files to build erpcgen on Windows, Linux, and OS X. + +[erpcsniffer](/erpcsniffer) - Holds source code for erpcsniffer application. + +[examples](/examples) - Several example IDL files. + +[mk](/mk) - Contains common makefiles for building eRPC components. + +[test](/test) - Client/server tests. These tests verify the entire communications path from client to server and back. + +[utilities](/utilities) - Holds utilities which bring additional benefit to eRPC apps developers. + +## Building and installing + +These build instructions apply to host PCs and embedded Linux. For bare metal or RTOS embedded environments, you should copy the [erpc_c](/erpc_c) directory into your application sources. + +**CMake and KConfig build**: + +It builds a static library of the eRPC C/C++ infrastructure, the `erpcgen` executable, and optionally the unit tests and examples. + +CMake is compatible with gcc and clang. On Windows local MingGW downloaded by [script](./install_dependencies.ps1) can be used. + +**Make build**: + +It builds a static library of the eRPC C/C++ infrastructure, the `erpcgen` executable, and optionally the unit tests. + +The makefiles are compatible with gcc or clang on Linux, OS X, and Cygwin. A Windows build +of erpcgen using Visual Studio is also available in the [erpcgen/VisualStudio_v14](erpcgen/VisualStudio_v14) directory. +There is also an Xcode project file in the [erpcgen](/erpcgen) directory, which can be used to build erpcgen for OS X. + +### Requirements + +eRPC now support building **erpcgen**, **erpc_lib**, **tests** and **C examples** using CMake. + +Requirements when using CMake: +* **CMake** (minimal version 3.20.0) +* Generator - **Make**, **Ninja**, ... +* **C/C++ compiler** - **GCC**, **CLANG**, ... +* **Binson** - https://www.gnu.org/software/bison/ +* **Flex** - https://github.com/westes/flex/ + +Requirements when using Make: +* **Make** +* **C/C++ compiler** - **GCC**, **CLANG**, ... +* **Binson** - https://www.gnu.org/software/bison/ +* **Flex** - https://github.com/westes/flex/ + + +#### Windows +Related steps to build **erpcgen** using **Visual Studio** are described in [`erpcgen/VisualStudio_v14/readme_erpcgen.txt`](erpcgen/VisualStudio_v14/readme_erpcgen.txt). + +To install MinGW, Bison, Flex locally on Windows: +```bash +./install_dependencies.ps1 +* ``` + +#### Linux + +```bash +./install_dependencies.sh +``` + +Mandatory for case, when build for different architecture is needed + +* gcc-multilib, g++-multilib + +#### Mac OS X + +```bash +./install_dependencies.sh +``` + +### Building + +#### CMake and KConfig +eRPC use CMake and KConfig to configurate and build eRPC related targets. KConfig can be edited by [prj.conf](./prj.conf) or _menuconfig_ when building. + +Generate project, config and build. In [erpc/](./) execute: +```bash +cmake -B ./build # in erpc/build generate cmake project +cmake --build ./build --target menuconfig # Build menuconfig and configurate erpcgen, erpc_lib, tests and examples +cmake --build ./build # Build all selected target from prj.conf/menuconfig +``` +**CMake will use the system's default compilers and generator + +If you want to use Windows and locally installed MinGW, use [CMake preset](./CMakePresets.json) : +```bash +cmake --preset mingw64 # Generate project in ./build using mingw64's make and compilers +cmake --build ./build --target menuconfig # Build menuconfig and configurate erpcgen, erpc_lib, tests and examples +cmake --build ./build # Build all selected target from prj.conf/menuconfig +``` + +#### Make +To build the library and erpcgen, run from the repo root directory: + +```sh +make +``` + +To install the library, erpcgen, and include files, run: + +```sh +make install +``` + +You may need to sudo the `make install`. + +By default this will install into `/usr/local`. If you want to install elsewhere, set the `PREFIX` environment variable. Example for installing into `/opt`: + +```sh +make install PREFIX=/opt +``` + +List of top level Makefile targets: + +* `erpc`: build the liberpc.a static library +* `erpcgen`: build the erpcgen tool +* `erpcsniffer`: build the sniffer tool +* `test`: build the unit tests under the [test](/test) directory +* `all`: build all of the above +* `install`: install liberpc.a, erpcgen, and include files + +eRPC code is validated with respect to the C++ 11 standard. + +### Installing for Python + +To install the Python infrastructure for eRPC see instructions in the [erpc python readme](/erpc_python/readme.md). + +## Known issues and limitations + +* Static allocations controlled by the ERPC_ALLOCATION_POLICY config macro are not fully supported yet, i.e. not all erpc objects can be allocated statically now. It deals with the ongoing process and the full static allocations support will be added in the future. + +## Code providing + +Repository on Github contains two main branches: __main__ and __develop__. Code is developed on __develop__ branch. Release version is created via merging __develop__ branch into __main__ branch. + +--- +Copyright 2014-2016 Freescale Semiconductor, Inc. + +Copyright 2016-2025 NXP diff --git a/packages/erpc-1.14.0/SBOM.spdx.json b/packages/erpc-1.14.0/SBOM.spdx.json new file mode 100644 index 0000000..b5003ae --- /dev/null +++ b/packages/erpc-1.14.0/SBOM.spdx.json @@ -0,0 +1,114 @@ +{ + "SPDXID": "SPDXRef-DOCUMENT", + "spdxVersion": "SPDX-2.3", + "creationInfo": { + "created": "2025-05-30T06:44:48Z", + "creators": [ + "Organization: NXP" + ], + "licenseListVersion": "3.20" + }, + "name": "erpc-1.14.0", + "dataLicense": "CC0-1.0", + "documentNamespace": "https://nxp.com/spdx/1dfe3ec4-b29f-4e7b-afd3-36278a134a93", + "packages": [ + { + "SPDXID": "SPDXRef-package-1dfe3ec4-b29f-4e7b-afd3-36278a134a93", + "name": "erpc", + "versionInfo": "1.14.0", + "licenseConcluded": "(BSD-3-Clause)", + "licenseDeclared": "(BSD-3-Clause)", + "downloadLocation": "https://github.com/EmbeddedRPC/erpc", + "originator": "Organization: NXP", + "supplier": "NOASSERTION", + "externalRefs": [], + "filesAnalyzed": false + }, + { + "SPDXID": "SPDXRef-package-f919933c-33b3-4b0a-950f-83c11a3d4b39", + "name": "BusPirate/Bus_Pirate", + "versionInfo": "v6.1", + "licenseConcluded": "CC0-1.0", + "licenseDeclared": "CC0-1.0", + "downloadLocation": "NOASSERTION", + "originator": "Organization: NXP", + "supplier": "NOASSERTION", + "externalRefs": [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceLocator": "pkg:github/BusPirate/Bus_Pirate@v6.1", + "referenceType": "purl" + }, + { + "referenceCategory": "OTHER", + "referenceLocator": "3a28d3d0-0713-4113-92c5-9a8b53e12e05", + "referenceType": "BlackDuck-ComponentOrigin" + } + ], + "filesAnalyzed": false + }, + { + "SPDXID": "SPDXRef-package-d83f2de3-93ed-46e7-9472-401fe64df55d", + "name": "Kconfiglib", + "versionInfo": "14.1.0", + "licenseConcluded": "ISC", + "licenseDeclared": "ISC", + "homepage": "https://github.com/ulfalizer/Kconfiglib", + "downloadLocation": "NOASSERTION", + "externalRefs": [], + "filesAnalyzed": false, + "supplier": "NOASSERTION" + }, + { + "SPDXID": "SPDXRef-package-9069e7c0-e11a-4d17-aa04-153e5fd93c3c", + "name": "zephyr", + "versionInfo": "v3.6.0", + "licenseConcluded": "Apache-2.0", + "licenseDeclared": "Apache-2.0", + "homepage": "https://zephyrproject.org/doc", + "downloadLocation": "https://github.com/zephyrproject-rtos/zephyr", + "originator": "Organization: NXP", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:zephyrproject:zephyr:3.6.0:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:o:zephyrproject:zephyr:3.6.0:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:zephyrproject_rtos:zephyr:3.6.0:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + } + ], + "filesAnalyzed": false, + "supplier": "NOASSERTION" + } + ], + "relationships": [ + { + "spdxElementId": "SPDXRef-DOCUMENT", + "relationshipType": "DESCRIBES", + "relatedSpdxElement": "SPDXRef-package-1dfe3ec4-b29f-4e7b-afd3-36278a134a93" + }, + { + "spdxElementId": "SPDXRef-package-1dfe3ec4-b29f-4e7b-afd3-36278a134a93", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-package-d83f2de3-93ed-46e7-9472-401fe64df55d" + }, + { + "spdxElementId": "SPDXRef-package-1dfe3ec4-b29f-4e7b-afd3-36278a134a93", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-package-9069e7c0-e11a-4d17-aa04-153e5fd93c3c" + }, + { + "spdxElementId": "SPDXRef-package-1dfe3ec4-b29f-4e7b-afd3-36278a134a93", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-package-f919933c-33b3-4b0a-950f-83c11a3d4b39" + } + ] +} \ No newline at end of file diff --git a/packages/erpc-1.14.0/SCR.txt b/packages/erpc-1.14.0/SCR.txt new file mode 100644 index 0000000..fe526f3 --- /dev/null +++ b/packages/erpc-1.14.0/SCR.txt @@ -0,0 +1,78 @@ +Release Name: eRPC +Release Version: 1.14.0 +Package License: BSD-3-Clause + +the_bus_pirate Name: The Bus Pirate + Version: NA + Outgoing License: Open Source - CC0 (Public Domain + Dedication License) + License File: http://code.google.com/p/the-bus-pirate/ + Format: source code + Description: OS independent serial interface + Location: + erpc_c/port/erpc_serial.h, + erpc_c/port/erpc_serial.cpp + Origin: Community + Url: http://code.google.com/p/the-bus-pirate/ + +cpp_template Name: CPP Template + Version: NA + Outgoing License: Open Source - MIT + License File: + erpcgen/src/cpptemplate/LICENSE.txt + Format: source code + Description: CPP Template + Location: erpcgen/src/cpptemplate + Origin: Ryan Ginstrom & Martinho Fernandes + +cpp_option_parser Name: C++ option-parser + Version: NA + Outgoing License: Brad Appleton's license + License File: http://www.bradapp.com/ftp/src/libs/C++/Options.tar.gz + , see README file + Format: Plain Text + Description: C++ option-parser + Location: erpcgen/src/options.cpp + Origin: Brad Appleton bradapp@enteract.com + Url: http://www.bradapp.com/ftp/src/libs/C++/Options.html + +kconfig_scripts Name: A flexible Python 2/3 Kconfig implementation and library + Version: NA + Outgoing License: ISC + License File: https://github.com/ulfalizer/Kconfiglib/blob/master/LICENSE.txt + Format: source code + Description: A flexible Python 2/3 Kconfig implementation and library + Location: scripts/kconfig/kconfiglib.py, + scripts/kconfig/guiconfig.py, scripts/kconfig/menuconfig.py + Origin: Ulf Magnusson + Url: https://github.com/ulfalizer/Kconfiglib + +hardenconfig_script Name: Zephyr RTOS scripts + Version: 3.6 + Outgoing License: Apache 2.0 + License File: https://github.com/zephyrproject-rtos/zephyr/blob/main/LICENSE + Format: source code + Description: Zephyr RTOS scripts + Location: scripts/kconfig/hardenconfig.py + Origin: Intel Corporation + Url: https://github.com/zephyrproject-rtos/zephyr + +kconfigfunctions_script Name: Zephyr RTOS scripts + Version: 3.6 + Outgoing License: Apache 2.0 + License File: https://github.com/zephyrproject-rtos/zephyr/blob/main/LICENSE + Format: source code + Description: Zephyr RTOS scripts + Location: scripts/kconfig/kconfigfunctions.py + Origin: Nordic Semiconductor ASA, Linaro + Url: https://github.com/zephyrproject-rtos/zephyr + +lint_script Name: Zephyr RTOS scripts + Version: 3.6 + Outgoing License: Apache 2.0 + License File: https://github.com/zephyrproject-rtos/zephyr/blob/main/LICENSE + Format: source code + Description: Zephyr RTOS scripts + Location: scripts/kconfig/lint.py + Origin: Nordic Semiconductor ASA + Url: https://github.com/zephyrproject-rtos/zephyr diff --git a/packages/erpc-1.14.0/SConscript b/packages/erpc-1.14.0/SConscript new file mode 100644 index 0000000..5267221 --- /dev/null +++ b/packages/erpc-1.14.0/SConscript @@ -0,0 +1,94 @@ +import os +from building import * +import rtconfig + +import shutil + +cwd = GetCurrentDir() + + + +src = [] +inc = [] + +cwd = cwd + '/erpc_c/' + +inc = inc + [cwd] +for root, dirs, files in os.walk(cwd): + for dir in dirs: + inc = inc + [os.path.join(root,dir)] + +src = Split(""" + + erpc_c/infra/erpc_basic_codec.cpp + erpc_c/infra/erpc_message_buffer.cpp + erpc_c/infra/erpc_message_loggers.cpp + erpc_c/infra/erpc_crc16.cpp + erpc_c/infra/erpc_pre_post_action.cpp + erpc_c/infra/erpc_framed_transport.cpp + + + erpc_c/setup/erpc_setup_mbf_static.cpp + erpc_c/setup/erpc_setup_mbf_dynamic.cpp + +""") + +if GetDepend(['ERPC_USING_RTT']): + src += Glob('erpc_c/port/erpc_threading_pthreads.cpp') +# src += Glob('erpc_c/port/erpc_port_threadx.cpp') + +if GetDepend(['ERPC_TRANSPORTS_SPI','ERPC_MODE_CLIENT']): + src += Glob('erpc_c/setup/erpc_setup_spi_master.cpp') + src += Glob('erpc_c/transports/erpc_spi_master_transport.cpp') + +if GetDepend(['ERPC_TRANSPORTS_SPI','ERPC_MODE_SERVER']): + src += Glob('erpc_c/setup/erpc_setup_spi_slave.cpp') + src += Glob('erpc_c/transports/erpc_spi_slave_transport.cpp') +# +# if GetDepend(['ERPC_TRANSPORTS_UART']): +# src += Glob('erpc_c/setup/erpc_setup_uart_cmsis.cpp') +# src += Glob('erpc_c/transports/erpc_uart_cmsis_transport.cpp') +if GetDepend(['ERPC_TRANSPORTS_UART']): + src += Glob('erpc_c/setup/erpc_setup_serial.cpp') + src += Glob('erpc_c/transports/erpc_serial_transport.cpp') + +if GetDepend(['ERPC_TRANSPORTS_TCP']): + src += Glob('erpc_c/setup/erpc_setup_tcp.cpp') + src += Glob('erpc_c/transports/erpc_tcp_transport.cpp') + +if GetDepend(['ERPC_MODE_CLIENT']): + src += Glob('erpc_c/infra/erpc_client_manager.cpp') + src += Glob('erpc_c/setup/erpc_client_setup.cpp') + + +if GetDepend(['ERPC_MODE_SERVER']): + src += Glob('erpc_c/infra/erpc_simple_server.cpp') + src += Glob('erpc_c/infra/erpc_server.cpp') + src += Glob('erpc_c/setup/erpc_server_setup.cpp') + + +if GetDepend(['ERPC_MODE_CLIENT','ERPC_USING_RTT']): + src += Glob('erpc_c/infra/erpc_arbitrated_client_manager.cpp') + src += Glob('erpc_c/infra/erpc_transport_arbitrator.cpp') + src += Glob('erpc_c/setup/erpc_arbitrated_client_setup.cpp') + src += Glob('erpc_c/transports/erpc_inter_thread_buffer_transport.cpp') + + +if GetDepend(['ERPC_MODE_SERVER','ERPC_USING_RTT']): + src += Glob('erpc_c/infra/erpc_transport_arbitrator.cpp') + src += Glob('erpc_c/transports/erpc_inter_thread_buffer_transport.cpp') + + +# LOCAL_CCFLAGS = '' +# if rtconfig.PLATFORM == 'gcc': # GCC +# LOCAL_CCFLAGS += ' -std=c99' +# elif rtconfig.PLATFORM == 'armcc': # Keil AC5 +# LOCAL_CCFLAGS += ' --c99 --gnu -g -W' +# elif rtconfig.PLATFORM == 'armclang': # Keil AC6 +# LOCAL_CCFLAGS += ' -std=c99 -g -w' +# +# # group = DefineGroup('erpc', src, depend = [''],CPPPATH = inc,LOCAL_CCFLAGS = LOCAL_CCFLAGS) +group = DefineGroup('erpc', src, depend = [''],CPPPATH = inc) + +Return('group') + diff --git a/packages/erpc-1.14.0/cmake/erpc_utils.cmake b/packages/erpc-1.14.0/cmake/erpc_utils.cmake new file mode 100644 index 0000000..d07185a --- /dev/null +++ b/packages/erpc-1.14.0/cmake/erpc_utils.cmake @@ -0,0 +1,57 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# To optimize build process, for each erpc_config.h file used, generate only one library. +# This function compute MD5 of given config file and base on this hash check if target library exist, +# otherwise create new library with hash postfix +function(erpc_link_c_library) + cmake_parse_arguments(_ "" "TARGET;CONFIG_DIR;TRANSPORT" "" ${ARGN}) + + + include(${ERPC_C}/erpc_c_sources.cmake) + + if(NOT __TARGET) + message(FATAL_ERROR "Not target specified.") + endif() + + + if(NOT __CONFIG_DIR) + set(__CONFIG_DIR ${ERPC_C}/config) + endif() + + file(MD5 ${__CONFIG_DIR}/erpc_config.h CONFIG_HASH) + + if(NOT TARGET erpc_c_lib_${CONFIG_HASH}) + add_library(erpc_c_lib_${CONFIG_HASH} ${ERPC_C_SOURCES}) + target_include_directories(erpc_c_lib_${CONFIG_HASH} PUBLIC ${ERPC_C_INCLUDES} ${__CONFIG_DIR}) + + # Required for TCP transport + if(WIN32) + target_link_libraries(erpc_c_lib_${CONFIG_HASH} PUBLIC wsock32 ws2_32) + endif() + + target_link_libraries(erpc_c_lib_${CONFIG_HASH} PUBLIC Threads::Threads) + endif() + + find_package(Threads REQUIRED) + target_link_libraries(${__TARGET} PRIVATE erpc_c_lib_${CONFIG_HASH}) +endfunction() + +function(erpc_generate_shim_code) + cmake_parse_arguments(_ "" "IDL_FILE;OUTPUT_DIR;LANGUAGE;WORKING_DIRECTORY" "OUTPUT_FILES" ${ARGN}) + + if(NOT ERPCGEN_EXECUTABLE) + message(FATAL_ERROR "erpcgen executable not found. Enable CONFIG_ERPC_GENERATOR in Kconfig or provide erpcgen in PATH.") + endif() + + add_custom_command( + OUTPUT ${__OUTPUT_FILES} + COMMAND ${ERPCGEN_EXECUTABLE} -g c -o ${__OUTPUT_DIR} ${__IDL_FILE} + WORKING_DIRECTORY ${__WORKING_DIRECTORY} + DEPENDS ${__IDL_FILE} + COMMENT "erpcgen: ${ERPCGEN_EXECUTABLE} -g c -o ${__OUTPUT_DIR} ${__IDL_FILE}" + ) +endfunction() \ No newline at end of file diff --git a/packages/erpc-1.14.0/cmake/extensions.cmake b/packages/erpc-1.14.0/cmake/extensions.cmake new file mode 100644 index 0000000..8778caf --- /dev/null +++ b/packages/erpc-1.14.0/cmake/extensions.cmake @@ -0,0 +1,5531 @@ +# Copyright 2024 NXP +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +include_guard(GLOBAL) + +######################################################## +# Table of contents +######################################################## +# 1. Zephyr-aware extensions +# 1.1. zephyr_* +# 1.2. zephyr_library_* +# 1.2.1 zephyr_interface_library_* +# 1.3. generate_inc_* +# 1.4. board_* +# 1.5. Misc. +# 2. Kconfig-aware extensions +# 2.1 Misc +# 3. CMake-generic extensions +# 3.1. *_ifdef +# 3.2. *_ifndef +# 3.3. *_option compiler compatibility checks +# 3.3.1 Toolchain integration +# 3.4. Debugging CMake +# 3.5. File system management +# 4. Devicetree extensions +# 4.1 dt_* +# 4.2. *_if_dt_node +# 4.3 zephyr_dt_* +# 5. Zephyr linker functions +# 5.1. zephyr_linker* +# 6 Function helper macros +# 7 Linkable loadable extensions (llext) +# 7.1 llext_* configuration functions +# 7.2 add_llext_* build control functions + +######################################################## +# 1. Zephyr-aware extensions +######################################################## +# 1.1. zephyr_* +# +# The following methods are for modifying the CMake library[0] called +# "zephyr". zephyr is a catch-all CMake library for source files that +# can be built purely with the include paths, defines, and other +# compiler flags that all zephyr source files use. +# [0] https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html +# +# Example usage: +# zephyr_sources( +# random_esp32.c +# utils.c +# ) +# +# Is short for: +# target_sources(zephyr PRIVATE +# ${CMAKE_CURRENT_SOURCE_DIR}/random_esp32.c +# ${CMAKE_CURRENT_SOURCE_DIR}/utils.c +# ) +# +# As a very high-level introduction here are two call graphs that are +# purposely minimalistic and incomplete. +# +# zephyr_library_cc_option() +# | +# v +# zephyr_library_compile_options() --> target_compile_options() +# +# +# zephyr_cc_option() ---> target_cc_option() +# | +# v +# zephyr_cc_option_fallback() ---> target_cc_option_fallback() +# | +# v +# zephyr_compile_options() ---> target_compile_options() +# + + +# https://cmake.org/cmake/help/latest/command/target_sources.html +function(zephyr_sources) + foreach(arg ${ARGV}) + if(IS_DIRECTORY ${arg}) + message(FATAL_ERROR "zephyr_sources() was called on a directory") + endif() + target_sources(zephyr PRIVATE ${arg}) + endforeach() +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_include_directories.html +function(zephyr_include_directories) + target_include_directories(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_include_directories.html +function(zephyr_system_include_directories) + target_include_directories(zephyr_interface SYSTEM INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_compile_definitions.html +function(zephyr_compile_definitions) + target_compile_definitions(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_compile_options.html +function(zephyr_compile_options) + target_compile_options(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_link_libraries.html +function(zephyr_link_libraries) + target_link_libraries(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +function(zephyr_libc_link_libraries) + set_property(TARGET zephyr_interface APPEND PROPERTY LIBC_LINK_LIBRARIES ${ARGV}) +endfunction() + +# See this file section 3.1. target_cc_option +function(zephyr_cc_option) + foreach(arg ${ARGV}) + target_cc_option(zephyr_interface INTERFACE ${arg}) + endforeach() +endfunction() + +function(zephyr_cc_option_fallback option1 option2) + target_cc_option_fallback(zephyr_interface INTERFACE ${option1} ${option2}) +endfunction() + +function(zephyr_ld_options) + target_ld_options(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# Getter functions for extracting build information from +# zephyr_interface. Returning lists, and strings is supported, as is +# requesting specific categories of build information (defines, +# includes, options). +# +# The naming convention follows: +# zephyr_get_${build_information}_for_lang${format}(lang x [STRIP_PREFIX]) +# Where +# the argument 'x' is written with the result +# and +# ${build_information} can be one of +# - include_directories # -I directories +# - system_include_directories # -isystem directories +# - compile_definitions # -D'efines +# - compile_options # misc. compiler flags +# and +# ${format} can be +# - the empty string '', signifying that it should be returned as a list +# - _as_string signifying that it should be returned as a string +# and +# ${lang} can be one of +# - C +# - CXX +# - ASM +# +# STRIP_PREFIX +# +# By default the result will be returned ready to be passed directly +# to a compiler, e.g. prefixed with -D, or -I, but it is possible to +# omit this prefix by specifying 'STRIP_PREFIX' . This option has no +# effect for 'compile_options'. +# +# e.g. +# zephyr_get_include_directories_for_lang(ASM x) +# writes "-Isome_dir;-Isome/other/dir" to x + +function(zephyr_get_include_directories_for_lang_as_string lang i) + zephyr_get_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN}) + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_system_include_directories_for_lang_as_string lang i) + zephyr_get_system_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN}) + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_definitions_for_lang_as_string lang i) + zephyr_get_compile_definitions_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN}) + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_options_for_lang_as_string lang i) + zephyr_get_compile_options_for_lang(${lang} list_of_flags DELIMITER " ") + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_include_directories_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + if(NOT ARGN) + set(result_output_list "-I$-I>") + elseif(args_STRIP_PREFIX) + # The list has no prefix, so don't add it. + set(result_output_list ${output_list}) + elseif(args_DELIMITER) + set(result_output_list "-I$") + endif() + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +function(zephyr_get_system_include_directories_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + set_ifndef(args_DELIMITER "$") + set(result_output_list "$<$:-isystem$>") + + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_definitions_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + set_ifndef(args_DELIMITER "$") + set(result_output_list "-D$") + + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_options_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + set_ifndef(args_DELIMITER "$") + set(result_output_list "$") + + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +# This function writes a dict to it's output parameter +# 'return_dict'. The dict has information about the parsed arguments, +# +# Usage: +# zephyr_get_parse_args(foo ${ARGN}) +# print(foo_STRIP_PREFIX) # foo_STRIP_PREFIX might be set to 1 +function(zephyr_get_parse_args return_dict) + foreach(x ${ARGN}) + if(DEFINED single_argument) + set(${single_argument} ${x} PARENT_SCOPE) + unset(single_argument) + else() + if(x STREQUAL STRIP_PREFIX) + set(${return_dict}_STRIP_PREFIX 1 PARENT_SCOPE) + elseif(x STREQUAL NO_SPLIT) + set(${return_dict}_NO_SPLIT 1 PARENT_SCOPE) + elseif(x STREQUAL DELIMITER) + set(single_argument ${return_dict}_DELIMITER) + endif() + endif() + endforeach() +endfunction() + +function(process_flags lang input output) + # The flags might contains compile language generator expressions that + # look like this: + # $<$:-fno-exceptions> + # $<$:$> + # + # Flags that don't specify a language like this apply to all + # languages. + # + # See COMPILE_LANGUAGE in + # https://cmake.org/cmake/help/v3.3/manual/cmake-generator-expressions.7.html + # + # To deal with this, we apply a regex to extract the flag and also + # to find out if the language matches. + # + # If this doesn't work out we might need to ban the use of + # COMPILE_LANGUAGE and instead partition C, CXX, and ASM into + # different libraries + set(languages C CXX ASM) + + set(tmp_list "") + + foreach(flag ${${input}}) + set(is_compile_lang_generator_expression 0) + foreach(l ${languages}) + if(flag MATCHES ":([^>]+)>") + set(updated_flag ${CMAKE_MATCH_1}) + set(is_compile_lang_generator_expression 1) + if(${l} STREQUAL ${lang}) + # This test will match in case there are more generator expressions in the flag. + # As example: $<$:$> + # $<$:something>> + string(REGEX MATCH "(\\\$<)[^\\\$]*(\\\$<)[^\\\$]*(\\\$<)" IGNORE_RESULT ${flag}) + if(CMAKE_MATCH_2) + # Nested generator expressions are used, just substitute `$` to `1` + string(REGEX REPLACE "\\\$" "1" updated_flag ${flag}) + endif() + list(APPEND tmp_list ${updated_flag}) + break() + endif() + endif() + endforeach() + + if(NOT is_compile_lang_generator_expression) + # SHELL is used to avoid de-duplication, but when process flags + # then this tag must be removed to return real compile/linker flags. + if(flag MATCHES "SHELL:[ ]*(.*)") + separate_arguments(flag UNIX_COMMAND ${CMAKE_MATCH_1}) + endif() + # Flags may be placed inside generator expression, therefore any flag + # which is not already a generator expression must have commas converted. + if(NOT flag MATCHES "\\\$<.*>") + string(REPLACE "," "$" flag "${flag}") + endif() + list(APPEND tmp_list ${flag}) + endif() + endforeach() + + set(${output} ${tmp_list} PARENT_SCOPE) +endfunction() + +function(convert_list_of_flags_to_string_of_flags ptr_list_of_flags string_of_flags) + # Convert the list to a string so we can do string replace + # operations on it and replace the ";" list separators with a + # whitespace so the flags are spaced out + string(REPLACE ";" " " locally_scoped_string_of_flags "${${ptr_list_of_flags}}") + + # Set the output variable in the parent scope + set(${string_of_flags} ${locally_scoped_string_of_flags} PARENT_SCOPE) +endfunction() + +macro(get_property_and_add_prefix result target property prefix) + zephyr_get_parse_args(args ${ARGN}) + + if(args_STRIP_PREFIX) + set(maybe_prefix "") + else() + set(maybe_prefix ${prefix}) + endif() + + get_property(target_property TARGET ${target} PROPERTY ${property}) + foreach(x ${target_property}) + list(APPEND ${result} ${maybe_prefix}${x}) + endforeach() +endmacro() + +# 1.2 zephyr_library_* +# +# Zephyr libraries use CMake's library concept and a set of +# assumptions about how zephyr code is organized to cut down on +# boilerplate code. +# +# A Zephyr library can be constructed by the function zephyr_library +# or zephyr_library_named. The constructors create a CMake library +# with a name accessible through the variable ZEPHYR_CURRENT_LIBRARY. +# +# The variable ZEPHYR_CURRENT_LIBRARY should seldom be needed since +# the zephyr libraries have methods that modify the libraries. These +# methods have the signature: zephyr_library_ +# +# The methods are wrappers around the CMake target_* functions. See +# https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for +# documentation on the underlying target_* functions. +# +# The methods modify the CMake target_* API to reduce boilerplate; +# PRIVATE is assumed +# The target is assumed to be ZEPHYR_CURRENT_LIBRARY +# +# When a flag that is given through the zephyr_* API conflicts with +# the zephyr_library_* API then precedence will be given to the +# zephyr_library_* API. In other words, local configuration overrides +# global configuration. + +# Constructor with a directory-inferred name +macro(zephyr_library) + zephyr_library_get_current_dir_lib_name(${ZEPHYR_BASE} lib_name) + zephyr_library_named(${lib_name}) +endmacro() + +# Determines what the current directory's lib name would be according to the +# provided base and writes it to the argument "lib_name" +macro(zephyr_library_get_current_dir_lib_name base lib_name) + # Remove the prefix (/home/sebo/zephyr/driver/serial/CMakeLists.txt => driver/serial/CMakeLists.txt) + file(RELATIVE_PATH name ${base} ${CMAKE_CURRENT_LIST_FILE}) + + # Remove the filename (driver/serial/CMakeLists.txt => driver/serial) + get_filename_component(name ${name} DIRECTORY) + + # Replace / with __ (driver/serial => driver__serial) + string(REGEX REPLACE "/" "__" name ${name}) + + # Replace : with __ (C:/zephyrproject => C____zephyrproject) + string(REGEX REPLACE ":" "__" name ${name}) + + set(${lib_name} ${name}) +endmacro() + +# Constructor with an explicitly given name. +macro(zephyr_library_named name) + # This is a macro because we need add_library() to be executed + # within the scope of the caller. + set(ZEPHYR_CURRENT_LIBRARY ${name}) + add_library(${name} STATIC "") + + zephyr_append_cmake_library(${name}) + + target_link_libraries(${name} PUBLIC zephyr_interface) +endmacro() + +# Provides amend functionality to a Zephyr library for out-of-tree usage. +# +# When called from a Zephyr module, the corresponding zephyr library defined +# within Zephyr will be looked up. +# +# Note, in order to ensure correct library when amending, the folder structure in the +# Zephyr module must resemble the structure used in Zephyr, as example: +# +# Example: to amend the zephyr library created in +# ZEPHYR_BASE/drivers/entropy/CMakeLists.txt +# add the following file: +# ZEPHYR_MODULE/drivers/entropy/CMakeLists.txt +# with content: +# zephyr_library_amend() +# zephyr_library_sources(...) +# +# It is also possible to use generator expression when amending to Zephyr +# libraries. +# +# For example, in case it is required to expose the Zephyr library's folder as +# include path then the following is possible: +# zephyr_library_amend() +# zephyr_library_include_directories($) +# +# See the CMake documentation for more target properties or generator +# expressions. +# +macro(zephyr_library_amend) + # This is a macro because we need to ensure the ZEPHYR_CURRENT_LIBRARY and + # following zephyr_library_* calls are executed within the scope of the + # caller. + if(NOT ZEPHYR_CURRENT_MODULE_DIR) + message(FATAL_ERROR "Function only available for Zephyr modules.") + endif() + + zephyr_library_get_current_dir_lib_name(${ZEPHYR_CURRENT_MODULE_DIR} lib_name) + + set(ZEPHYR_CURRENT_LIBRARY ${lib_name}) +endmacro() + +function(zephyr_link_interface interface) + target_link_libraries(${interface} INTERFACE zephyr_interface) +endfunction() + +# +# zephyr_library versions of normal CMake target_ functions +# Note, paths passed to this function must be relative in order +# to support the library relocation feature of zephyr_code_relocate +# +function(zephyr_library_sources source) + target_sources(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${source} ${ARGN}) +endfunction() + +function(zephyr_library_include_directories) + target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${ARGN}) +endfunction() + +function(zephyr_library_link_libraries item) + target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PUBLIC ${item} ${ARGN}) +endfunction() + +function(zephyr_library_compile_definitions item) + target_compile_definitions(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${item} ${ARGN}) +endfunction() + +function(zephyr_library_compile_options item) + # The compiler is relied upon for sane behaviour when flags are in + # conflict. Compilers generally give precedence to flags given late + # on the command line. So to ensure that zephyr_library_* flags are + # placed late on the command line we create a dummy interface + # library and link with it to obtain the flags. + # + # Linking with a dummy interface library will place flags later on + # the command line than the the flags from zephyr_interface because + # zephyr_interface will be the first interface library that flags + # are taken from. + + string(MD5 uniqueness "${ARGV}") + set(lib_name options_interface_lib_${uniqueness}) + + if (NOT TARGET ${lib_name}) + # Create the unique target only if it doesn't exist. + add_library( ${lib_name} INTERFACE) + target_compile_options(${lib_name} INTERFACE ${item} ${ARGN}) + endif() + + target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${lib_name}) +endfunction() + +function(zephyr_library_cc_option) + foreach(option ${ARGV}) + string(MAKE_C_IDENTIFIER check${option} check) + zephyr_check_compiler_flag(C ${option} ${check}) + + if(${${check}}) + zephyr_library_compile_options(${option}) + endif() + endforeach() +endfunction() + +function(zephyr_library_add_dependencies) + add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ${ARGN}) +endfunction() + +# Add the existing CMake library 'library' to the global list of +# Zephyr CMake libraries. This is done automatically by the +# constructor but must be called explicitly on CMake libraries that do +# not use a zephyr library constructor. +function(zephyr_append_cmake_library library) + if(TARGET zephyr_prebuilt) + message(WARNING + "zephyr_library() or zephyr_library_named() called in Zephyr CMake " + "application mode. `${library}` will not be treated as a Zephyr library." + "To create a Zephyr library in Zephyr CMake kernel mode consider " + "creating a Zephyr module. See more here: " + "https://docs.zephyrproject.org/latest/guides/modules.html" + ) + endif() + set_property(GLOBAL APPEND PROPERTY ZEPHYR_LIBS ${library}) +endfunction() + +# Add the imported library 'library_name', located at 'library_path' to the +# global list of Zephyr CMake libraries. +function(zephyr_library_import library_name library_path) + add_library(${library_name} STATIC IMPORTED GLOBAL) + set_target_properties(${library_name} + PROPERTIES IMPORTED_LOCATION + ${library_path} + ) + zephyr_append_cmake_library(${library_name}) +endfunction() + +# Place the current zephyr library in the application memory partition. +# +# The partition argument is the name of the partition where the library shall +# be placed. +# +# Note: Ensure the given partition has been defined using +# K_APPMEM_PARTITION_DEFINE in source code. +function(zephyr_library_app_memory partition) + set_property(TARGET zephyr_property_target + APPEND PROPERTY COMPILE_OPTIONS + "-l" $ "${partition}") +endfunction() + +# Configure a Zephyr library specific property. +# +# Usage: +# zephyr_library_property( ) +# +# Current Zephyr library specific properties that are supported: +# ALLOW_EMPTY : Allow a Zephyr library to be empty. +# An empty Zephyr library will generate a CMake +# configure time warning unless `ALLOW_EMPTY` is TRUE. +function(zephyr_library_property) + set(single_args "ALLOW_EMPTY") + cmake_parse_arguments(LIB_PROP "" "${single_args}" "" ${ARGN}) + + if(LIB_PROP_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_library_property(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}") + endif() + + foreach(arg ${single_args}) + if(DEFINED LIB_PROP_${arg}) + set_property(TARGET ${ZEPHYR_CURRENT_LIBRARY} PROPERTY ${arg} ${LIB_PROP_${arg}}) + endif() + endforeach() +endfunction() + +# 1.2.1 zephyr_interface_library_* +# +# A Zephyr interface library is a thin wrapper over a CMake INTERFACE +# library. The most important responsibility of this abstraction is to +# ensure that when a user KConfig-enables a library then the header +# files of this library will be accessible to the 'app' library. +# +# This is done because when a user uses Kconfig to enable a library he +# expects to be able to include its header files and call its +# functions out-of-the box. +# +# A Zephyr interface library should be used when there exists some +# build information (include directories, defines, compiler flags, +# etc.) that should be applied to a set of Zephyr libraries and 'app' +# might be one of these libraries. +# +# Zephyr libraries must explicitly call +# zephyr_library_link_libraries() to use this build +# information. 'app' is treated as a special case for usability +# reasons; a Kconfig option (CONFIG_APP_LINK_WITH_) +# should exist for each interface_library and will determine if 'app' +# links with the interface_library. +# +# This API has a constructor like the zephyr_library API has, but it +# does not have wrappers over the other cmake target functions. +macro(zephyr_interface_library_named name) + add_library(${name} INTERFACE) + set_property(GLOBAL APPEND PROPERTY ZEPHYR_INTERFACE_LIBS ${name}) +endmacro() + +# 1.3 generate_inc_* + +# These functions are useful if there is a need to generate a file +# that can be included into the application at build time. The file +# can also be compressed automatically when embedding it. +# +# See tests/application_development/gen_inc_file for an example of +# usage. +function(generate_inc_file + source_file # The source file to be converted to hex + generated_file # The generated file + ) + add_custom_command( + OUTPUT ${generated_file} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/file2hex.py + ${ARGN} # Extra arguments are passed to file2hex.py + --file ${source_file} + > ${generated_file} # Does pipe redirection work on Windows? + DEPENDS ${source_file} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endfunction() + +function(generate_inc_file_for_gen_target + target # The cmake target that depends on the generated file + source_file # The source file to be converted to hex + generated_file # The generated file + gen_target # The generated file target we depend on + # Any additional arguments are passed on to file2hex.py + ) + generate_inc_file(${source_file} ${generated_file} ${ARGN}) + + # Ensure 'generated_file' is generated before 'target' by creating a + # dependency between the two targets + + add_dependencies(${target} ${gen_target}) +endfunction() + +function(generate_inc_file_for_target + target # The cmake target that depends on the generated file + source_file # The source file to be converted to hex + generated_file # The generated file + # Any additional arguments are passed on to file2hex.py + ) + # Ensure 'generated_file' is generated before 'target' by creating a + # 'custom_target' for it and setting up a dependency between the two + # targets + + # But first create a unique name for the custom target + generate_unique_target_name_from_filename(${generated_file} generated_target_name) + + add_custom_target(${generated_target_name} DEPENDS ${generated_file}) + generate_inc_file_for_gen_target(${target} ${source_file} ${generated_file} ${generated_target_name} ${ARGN}) +endfunction() + +# 1.4. board_* +# +# This section is for extensions related to Zephyr board handling. +# +# Zephyr board extensions current contains: +# - Board runners +# - Board revision + +# Zephyr board runners: +# Zephyr board runner extension functions control Zephyr's board runners +# from the build system. The Zephyr build system has targets for +# flashing and debugging supported boards. These are wrappers around a +# "runner" Python subpackage that is part of Zephyr's "west" tool. +# +# This section provides glue between CMake and the Python code that +# manages the runners. + +function(_board_check_runner_type type) # private helper + if (NOT (("${type}" STREQUAL "FLASH") OR ("${type}" STREQUAL "DEBUG"))) + message(FATAL_ERROR "invalid type ${type}; should be FLASH or DEBUG") + endif() +endfunction() + +# This function sets the runner for the board unconditionally. It's +# meant to be used from application CMakeLists.txt files. +# +# NOTE: Usually board_set_xxx_ifnset() is best in board.cmake files. +# This lets the user set the runner at cmake time, or in their +# own application's CMakeLists.txt. +# +# Usage: +# board_set_runner(FLASH pyocd) +# +# This would set the board's flash runner to "pyocd". +# +# In general, "type" is FLASH or DEBUG, and "runner" is the name of a +# runner. +function(board_set_runner type runner) + _board_check_runner_type(${type}) + if (DEFINED BOARD_${type}_RUNNER) + message(STATUS "overriding ${type} runner ${BOARD_${type}_RUNNER}; it's now ${runner}") + endif() + set(BOARD_${type}_RUNNER ${runner} PARENT_SCOPE) +endfunction() + +# This macro is like board_set_runner(), but will only make a change +# if that runner is currently not set. +# +# See also board_set_flasher_ifnset() and board_set_debugger_ifnset(). +macro(board_set_runner_ifnset type runner) + _board_check_runner_type(${type}) + # This is a macro because set_ifndef() works at parent scope. + # If this were a function, that would be this function's scope, + # which wouldn't work. + set_ifndef(BOARD_${type}_RUNNER ${runner}) +endmacro() + +# A convenience macro for board_set_runner(FLASH ${runner}). +macro(board_set_flasher runner) + board_set_runner(FLASH ${runner}) +endmacro() + +# A convenience macro for board_set_runner(DEBUG ${runner}). +macro(board_set_debugger runner) + board_set_runner(DEBUG ${runner}) +endmacro() + +# A convenience macro for board_set_runner_ifnset(FLASH ${runner}). +macro(board_set_flasher_ifnset runner) + board_set_runner_ifnset(FLASH ${runner}) +endmacro() + +# A convenience macro for board_set_runner_ifnset(DEBUG ${runner}). +macro(board_set_debugger_ifnset runner) + board_set_runner_ifnset(DEBUG ${runner}) +endmacro() + +# This function is intended for board.cmake files and application +# CMakeLists.txt files. +# +# Usage from board.cmake files: +# board_runner_args(runner "--some-arg=val1" "--another-arg=val2") +# +# The build system will then ensure the command line used to +# create the runner contains: +# --some-arg=val1 --another-arg=val2 +# +# Within application CMakeLists.txt files, ensure that all calls to +# board_runner_args() are part of a macro named app_set_runner_args(), +# like this, which is defined before calling 'find_package(Zephyr)': +# macro(app_set_runner_args) +# board_runner_args(runner "--some-app-setting=value") +# endmacro() +# +# The build system tests for the existence of the macro and will +# invoke it at the appropriate time if it is defined. +# +# Any explicitly provided settings given by this function override +# defaults provided by the build system. +function(board_runner_args runner) + string(MAKE_C_IDENTIFIER ${runner} runner_id) + # Note the "_EXPLICIT_" here, and see below. + set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_EXPLICIT_${runner_id} ${ARGN}) +endfunction() + +# This function is intended for internal use by +# boards/common/runner.board.cmake files. +# +# Basic usage: +# board_finalize_runner_args(runner) +# +# This ensures the build system captures all arguments added in any +# board_runner_args() calls, and otherwise finishes registering a +# runner for use. +# +# Extended usage: +# board_runner_args(runner "--some-arg=default-value") +# +# This provides common or default values for arguments. These are +# placed before board_runner_args() calls, so they generally take +# precedence, except for arguments which can be given multiple times +# (use these with caution). +function(board_finalize_runner_args runner) + # If the application provided a macro to add additional runner + # arguments, handle them. + if(COMMAND app_set_runner_args) + app_set_runner_args() + endif() + + # Retrieve the list of explicitly set arguments. + string(MAKE_C_IDENTIFIER ${runner} runner_id) + get_property(explicit GLOBAL PROPERTY "BOARD_RUNNER_ARGS_EXPLICIT_${runner_id}") + + # Note no _EXPLICIT_ here. This property contains the final list. + set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_${runner_id} + # Default arguments from the common runner file come first. + ${ARGN} + # Arguments explicitly given with board_runner_args() come + # next, so they take precedence over the common runner file. + ${explicit} + # Arguments given via the CMake cache come last of all. Users + # can provide variables in this way from the CMake command line. + ${BOARD_RUNNER_ARGS_${runner_id}} + ) + + # Add the finalized runner to the global property list. + set_property(GLOBAL APPEND PROPERTY ZEPHYR_RUNNERS ${runner}) +endfunction() + +function(board_set_rimage_target target) + set(RIMAGE_TARGET ${target} CACHE STRING "rimage target") + zephyr_check_cache(RIMAGE_TARGET) +endfunction() + +# Zephyr board revision: +# +# This section provides a function for revision checking. + +# Usage: +# board_check_revision(FORMAT +# [EXACT] +# [DEFAULT_REVISION ] +# [HIGHEST_REVISION ] +# ) +# +# Zephyr board extension function. +# +# This function can be used in `boards//revision.cmake` to check a user +# requested revision against available board revisions. +# +# The function will check the revision from `-DBOARD=@` that +# is provided by the user according to the arguments. +# When `EXACT` is not specified, this function will set the Zephyr build system +# variable `ACTIVE_BOARD_REVISION` with the selected revision. +# +# FORMAT : Specify the revision format. +# LETTER: Revision format is a single letter from A - Z. +# NUMBER: Revision format is a single integer number. +# MAJOR.MINOR.PATCH: Revision format is three numbers, separated by `.`, +# `x.y.z`. Trailing zeroes may be omitted on the +# command line, which means: +# 1.0.0 == 1.0 == 1 +# +# OPTIONAL: Revision specifier is optional. If revision is not provided the base +# board will be used. If both `EXACT` and `OPTIONAL` are given, then +# specifying the revision is optional, but if it is given then the +# `EXACT` requirements apply. Mutually exclusive with `DEFAULT_REVISION`. +# +# EXACT: Revision is required to be an exact match. As example, available revisions are: +# 0.1.0 and 0.3.0, and user provides 0.2.0, then an error is reported +# when `EXACT` is given. +# If `EXACT` is not provided, then closest lower revision will be selected +# as the active revision, which in the example will be `0.1.0`. +# +# DEFAULT_REVISION: Provides a default revision to use when user has not selected +# a revision number. If no default revision is provided then +# user will be printed with an error if no revision is given +# on the command line. +# +# HIGHEST_REVISION: Allows to specify highest valid revision for a board. +# This can be used to ensure that a newer board cannot be used +# with an older Zephyr. As example, if current board supports +# revisions 0.x.0-0.99.99 and 1.0.0-1.99.99, and it is expected +# that current board implementation will not work with board +# revision 2.0.0, then HIGHEST_REVISION can be set to 1.99.99, +# and user will be printed with an error if using +# `@2.0.0` or higher. +# This field is not needed when `EXACT` is used. +# +# VALID_REVISIONS: A list of valid revisions for this board. +# If this argument is not provided, then each Kconfig fragment +# of the form ``_.conf`` in the board folder +# will be used as a valid revision for the board. +# +function(board_check_revision) + set(options OPTIONAL EXACT) + set(single_args FORMAT DEFAULT_REVISION HIGHEST_REVISION) + set(multi_args VALID_REVISIONS) + cmake_parse_arguments(BOARD_REV "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + string(TOUPPER ${BOARD_REV_FORMAT} BOARD_REV_FORMAT) + + if(DEFINED BOARD_REV_DEFAULT_REVISION AND BOARD_REV_OPTIONAL) + message(FATAL_ERROR "Arguments BOARD_REVISION and OPTIONAL are mutually exclusive") + endif() + + if(NOT DEFINED BOARD_REVISION) + if(BOARD_REV_OPTIONAL) + return() + elseif(DEFINED BOARD_REV_DEFAULT_REVISION) + set(BOARD_REVISION ${BOARD_REV_DEFAULT_REVISION}) + set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE) + else() + message(FATAL_ERROR "No board revision specified, Board: `${BOARD}` \ + requires a revision. Please use: `-DBOARD=${BOARD}@`") + endif() + endif() + + if(DEFINED BOARD_REV_HIGHEST_REVISION) + if(((BOARD_REV_FORMAT STREQUAL LETTER) AND + (BOARD_REVISION STRGREATER BOARD_REV_HIGHEST_REVISION)) OR + ((BOARD_REV_FORMAT STREQUAL NUMBER) AND + (BOARD_REVISION GREATER BOARD_REV_HIGHEST_REVISION)) OR + ((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND + (BOARD_REVISION VERSION_GREATER BOARD_REV_HIGHEST_REVISION)) + ) + message(FATAL_ERROR "Board revision `${BOARD_REVISION}` greater than \ + highest supported revision `${BOARD_REV_HIGHEST_REVISION}`. \ + Please specify a valid board revision.") + endif() + endif() + + if(BOARD_REV_FORMAT STREQUAL LETTER) + set(revision_regex "([A-Z])") + elseif(BOARD_REV_FORMAT STREQUAL NUMBER) + set(revision_regex "([0-9]+)") + elseif(BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") + set(revision_regex "((0|[1-9][0-9]*)(\.[0-9]+)(\.[0-9]+))") + # We allow loose @ typing on command line. + # so append missing zeroes. + if(BOARD_REVISION MATCHES "((0|[1-9][0-9]*)(\.[0-9]+)?(\.[0-9]+)?)") + if(NOT CMAKE_MATCH_3) + set(BOARD_REVISION ${BOARD_REVISION}.0) + set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE) + endif() + if(NOT CMAKE_MATCH_4) + set(BOARD_REVISION ${BOARD_REVISION}.0) + set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE) + endif() + endif() + else() + message(FATAL_ERROR "Invalid format specified for \ + `board_check_revision(FORMAT )`") + endif() + + if(NOT (BOARD_REVISION MATCHES "^${revision_regex}$")) + message(FATAL_ERROR "Invalid revision format used for `${BOARD_REVISION}`. \ + Board `${BOARD}` uses revision format: ${BOARD_REV_FORMAT}.") + endif() + + if(NOT DEFINED BOARD_REV_VALID_REVISIONS) + file(GLOB revision_candidates LIST_DIRECTORIES false RELATIVE ${BOARD_DIR} + ${BOARD_DIR}/${BOARD}_*.conf + ) + string(REPLACE "." "_" underscore_revision_regex ${revision_regex}) + set(file_revision_regex "${BOARD}_${underscore_revision_regex}.conf") + foreach(candidate ${revision_candidates}) + if(${candidate} MATCHES "${file_revision_regex}") + string(REPLACE "_" "." FOUND_BOARD_REVISION ${CMAKE_MATCH_1}) + list(APPEND BOARD_REV_VALID_REVISIONS ${FOUND_BOARD_REVISION}) + endif() + endforeach() + endif() + + if(${BOARD_REVISION} IN_LIST BOARD_REV_VALID_REVISIONS) + # Found exact match. + return() + endif() + + if(NOT BOARD_REV_EXACT) + foreach(TEST_REVISION ${BOARD_REV_VALID_REVISIONS}) + if((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND + (${BOARD_REVISION} VERSION_GREATER_EQUAL ${TEST_REVISION}) AND + (${TEST_REVISION} VERSION_GREATER_EQUAL "${ACTIVE_BOARD_REVISION}") + ) + set(ACTIVE_BOARD_REVISION ${TEST_REVISION}) + elseif((BOARD_REV_FORMAT STREQUAL LETTER) AND + (${BOARD_REVISION} STRGREATER ${TEST_REVISION}) AND + (${TEST_REVISION} STRGREATER "${ACTIVE_BOARD_REVISION}") + ) + set(ACTIVE_BOARD_REVISION ${TEST_REVISION}) + elseif((BOARD_REV_FORMAT STREQUAL NUMBER) AND + (${BOARD_REVISION} GREATER ${TEST_REVISION}) AND + (${TEST_REVISION} GREATER "${ACTIVE_BOARD_REVISION}") + ) + set(ACTIVE_BOARD_REVISION ${TEST_REVISION}) + endif() + endforeach() + endif() + + if(BOARD_REV_EXACT OR NOT DEFINED ACTIVE_BOARD_REVISION) + message(FATAL_ERROR "Board revision `${BOARD_REVISION}` for board \ + `${BOARD}` not found. Please specify a valid board revision.") + endif() + + set(ACTIVE_BOARD_REVISION ${ACTIVE_BOARD_REVISION} PARENT_SCOPE) +endfunction() + +# 1.5. Misc. + +# zephyr_check_compiler_flag is a part of Zephyr's toolchain +# infrastructure. It should be used when testing toolchain +# capabilities and it should normally be used in place of the +# functions: +# +# check_compiler_flag +# check_c_compiler_flag +# check_cxx_compiler_flag +# +# See check_compiler_flag() for API documentation as it has the same +# API. +# +# It is implemented as a wrapper on top of check_compiler_flag, which +# again wraps the CMake-builtin's check_c_compiler_flag and +# check_cxx_compiler_flag. +# +# It takes time to check for compatibility of flags against toolchains +# so we cache the capability test results in USER_CACHE_DIR (This +# caching comes in addition to the caching that CMake does in the +# build folder's CMakeCache.txt) +function(zephyr_check_compiler_flag lang option check) + # Check if the option is covered by any hardcoded check before doing + # an automated test. + zephyr_check_compiler_flag_hardcoded(${lang} "${option}" _${check} exists) + if(exists) + set(${check} ${_${check}} PARENT_SCOPE) + return() + endif() + + # Locate the cache directory + set_ifndef( + ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR + ${USER_CACHE_DIR}/ToolchainCapabilityDatabase + ) + + # The toolchain capability database/cache is maintained as a + # directory of files. The filenames in the directory are keys, and + # the file contents are the values in this key-value store. + + # We need to create a unique key wrt. testing the toolchain + # capability. This key must include everything that can affect the + # toolchain test. + # + # Also, to fit the key into a filename we calculate the MD5 sum of + # the key. + + # The 'cacheformat' must be bumped if a bug in the caching mechanism + # is detected and all old keys must be invalidated. + set(cacheformat 3) + + set(key_string "") + set(key_string "${key_string}${cacheformat}_") + set(key_string "${key_string}${TOOLCHAIN_SIGNATURE}_") + set(key_string "${key_string}${lang}_") + set(key_string "${key_string}${option}_") + set(key_string "${key_string}${CMAKE_REQUIRED_FLAGS}_") + + string(MD5 key "${key_string}") + + # Check the cache + set(key_path ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/${key}) + if(EXISTS ${key_path}) + file(READ + ${key_path} # File to be read + key_value # Output variable + LIMIT 1 # Read at most 1 byte ('0' or '1') + ) + + set(${check} ${key_value} PARENT_SCOPE) + return() + endif() + + # Flags that start with -Wno- can not be tested by + # check_compiler_flag, they will always pass, but -W can be + # tested, so to test -Wno- flags we test -W + # instead. + if("${option}" MATCHES "-Wno-(.*)") + string(REPLACE "-Wno-" "-W" possibly_translated_option "${option}") + else() + set(possibly_translated_option ${option}) + endif() + + check_compiler_flag(${lang} "${possibly_translated_option}" inner_check) + + set(${check} ${inner_check} PARENT_SCOPE) + + # Populate the cache + if(NOT (EXISTS ${key_path})) + + # This is racy. As often with race conditions, this one can easily be + # made worse and demonstrated with a simple delay: + # execute_process(COMMAND "sleep" "5") + # Delete the cache, add the sleep above and run twister with a + # large number of JOBS. Once it's done look at the log.txt file + # below and you will see that concurrent cmake processes created the + # same files multiple times. + + # While there are a number of reasons why this race seems both very + # unlikely and harmless, let's play it safe anyway and write to a + # private, temporary file first. All modern filesystems seem to + # support at least one atomic rename API and cmake's file(RENAME + # ...) officially leverages that. + string(RANDOM LENGTH 8 tempsuffix) + + file( + WRITE + "${key_path}_tmp_${tempsuffix}" + ${inner_check} + ) + file( + RENAME + "${key_path}_tmp_${tempsuffix}" "${key_path}" + ) + + # Populate a metadata file (only intended for trouble shooting) + # with information about the hash, the toolchain capability + # result, and the toolchain test. + file( + APPEND + ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/log.txt + "${inner_check} ${key} ${key_string}\n" + ) + endif() +endfunction() + +function(zephyr_check_compiler_flag_hardcoded lang option check exists) + # Various flags that are not supported for CXX may not be testable + # because they would produce a warning instead of an error during + # the test. Exclude them by toolchain-specific blocklist. + if((${lang} STREQUAL CXX) AND ("${option}" IN_LIST CXX_EXCLUDED_OPTIONS)) + set(${check} 0 PARENT_SCOPE) + set(${exists} 1 PARENT_SCOPE) + else() + # There does not exist a hardcoded check for this option. + set(${exists} 0 PARENT_SCOPE) + endif() +endfunction(zephyr_check_compiler_flag_hardcoded) + +# zephyr_linker_sources( [SORT_KEY ] ) +# +# is one or more .ld formatted files whose contents will be +# copied/included verbatim into the given in the global linker.ld. +# Preprocessor directives work inside . Relative paths are resolved +# relative to the calling file, like zephyr_sources(). +# Subsequent calls to zephyr_linker_sources with the same file(s) will remove +# these from the original location. Only the last call is considered. +# is one of +# NOINIT Inside the noinit output section. +# RWDATA Inside the data output section. +# RODATA Inside the rodata output section. +# ROM_START Inside the first output section of the image. This option is +# currently only available on ARM Cortex-M, ARM Cortex-R, +# x86, ARC, openisa_rv32m1, and RISC-V. +# RAM_SECTIONS Inside the RAMABLE_REGION GROUP, not initialized. +# DATA_SECTIONS Inside the RAMABLE_REGION GROUP, initialized. +# RAMFUNC_SECTION Inside the RAMFUNC RAMABLE_REGION GROUP, not initialized. +# NOCACHE_SECTION Inside the NOCACHE section +# ITCM_SECTION Inside the itcm section. +# DTCM_SECTION Inside the dtcm data section. +# SECTIONS Near the end of the file. Don't use this when linking into +# RAMABLE_REGION, use RAM_SECTIONS instead. +# PINNED_RODATA Similar to RODATA but pinned in memory. +# PINNED_RAM_SECTIONS +# Similar to RAM_SECTIONS but pinned in memory. +# PINNED_DATA_SECTIONS +# Similar to DATA_SECTIONS but pinned in memory. +# is an optional key to sort by inside of each location. The key must +# be alphanumeric, and the keys are sorted alphabetically. If no key is +# given, the key 'default' is used. Keys are case-sensitive. +# +# Use NOINIT, RWDATA, and RODATA unless they don't work for your use case. +# +# When placing into NOINIT, RWDATA, RODATA, ROM_START, RAMFUNC_SECTION, +# NOCACHE_SECTION, DTCM_SECTION or ITCM_SECTION the contents of the files will +# be placed inside an output section, so assume the section definition is +# already present, e.g.: +# _mysection_start = .; +# KEEP(*(.mysection)); +# _mysection_end = .; +# _mysection_size = ABSOLUTE(_mysection_end - _mysection_start); +# +# When placing into SECTIONS, RAM_SECTIONS or DATA_SECTIONS, the files must +# instead define their own output sections to achieve the same thing: +# SECTION_PROLOGUE(.mysection,,) +# { +# _mysection_start = .; +# KEEP(*(.mysection)) +# _mysection_end = .; +# } GROUP_LINK_IN(ROMABLE_REGION) +# _mysection_size = _mysection_end - _mysection_start; +# +# Note about the above examples: If the first example was used with RODATA, and +# the second with SECTIONS, the two examples do the same thing from a user +# perspective. +# +# Friendly reminder: Beware of the different ways the location counter ('.') +# behaves inside vs. outside section definitions. +function(zephyr_linker_sources location) + # Set up the paths to the destination files. These files are #included inside + # the global linker.ld. + set(snippet_base "${__build_dir}/include/generated") + set(sections_path "${snippet_base}/snippets-sections.ld") + set(ram_sections_path "${snippet_base}/snippets-ram-sections.ld") + set(data_sections_path "${snippet_base}/snippets-data-sections.ld") + set(rom_start_path "${snippet_base}/snippets-rom-start.ld") + set(noinit_path "${snippet_base}/snippets-noinit.ld") + set(rwdata_path "${snippet_base}/snippets-rwdata.ld") + set(rodata_path "${snippet_base}/snippets-rodata.ld") + set(ramfunc_path "${snippet_base}/snippets-ramfunc-section.ld") + set(nocache_path "${snippet_base}/snippets-nocache-section.ld") + set(itcm_path "${snippet_base}/snippets-itcm-section.ld") + set(dtcm_path "${snippet_base}/snippets-dtcm-section.ld") + + set(pinned_ram_sections_path "${snippet_base}/snippets-pinned-ram-sections.ld") + set(pinned_data_sections_path "${snippet_base}/snippets-pinned-data-sections.ld") + set(pinned_rodata_path "${snippet_base}/snippets-pinned-rodata.ld") + + # Clear destination files if this is the first time the function is called. + get_property(cleared GLOBAL PROPERTY snippet_files_cleared) + if (NOT DEFINED cleared) + file(WRITE ${sections_path} "") + file(WRITE ${ram_sections_path} "") + file(WRITE ${data_sections_path} "") + file(WRITE ${rom_start_path} "") + file(WRITE ${noinit_path} "") + file(WRITE ${rwdata_path} "") + file(WRITE ${rodata_path} "") + file(WRITE ${ramfunc_path} "") + file(WRITE ${nocache_path} "") + file(WRITE ${itcm_path} "") + file(WRITE ${dtcm_path} "") + file(WRITE ${pinned_ram_sections_path} "") + file(WRITE ${pinned_data_sections_path} "") + file(WRITE ${pinned_rodata_path} "") + set_property(GLOBAL PROPERTY snippet_files_cleared true) + endif() + + # Choose destination file, based on the argument. + if ("${location}" STREQUAL "SECTIONS") + set(snippet_path "${sections_path}") + elseif("${location}" STREQUAL "RAM_SECTIONS") + set(snippet_path "${ram_sections_path}") + elseif("${location}" STREQUAL "DATA_SECTIONS") + set(snippet_path "${data_sections_path}") + elseif("${location}" STREQUAL "ROM_START") + set(snippet_path "${rom_start_path}") + elseif("${location}" STREQUAL "NOINIT") + set(snippet_path "${noinit_path}") + elseif("${location}" STREQUAL "RWDATA") + set(snippet_path "${rwdata_path}") + elseif("${location}" STREQUAL "RODATA") + set(snippet_path "${rodata_path}") + elseif("${location}" STREQUAL "RAMFUNC_SECTION") + set(snippet_path "${ramfunc_path}") + elseif("${location}" STREQUAL "NOCACHE_SECTION") + set(snippet_path "${nocache_path}") + elseif("${location}" STREQUAL "ITCM_SECTION") + dt_has_chosen(HAS_ITCM PROPERTY "zephyr,itcm") + if(NOT HAS_ITCM) + message(FATAL_ERROR "Trying to link snippet into itcm but no itcm available. " + "Add `zephyr,itcm` to the device tree if supported on your device or choose another " + "location.") + endif() + set(snippet_path "${itcm_path}") + elseif("${location}" STREQUAL "DTCM_SECTION") + dt_has_chosen(HAS_DTCM PROPERTY "zephyr,dtcm") + if(NOT HAS_DTCM) + message(FATAL_ERROR "Trying to link snippet into dtcm but no dtcm available. " + "Add `zephyr,dtcm` to the device tree if supported on your device or choose another " + "location.") + endif() + set(snippet_path "${dtcm_path}") + elseif("${location}" STREQUAL "PINNED_RAM_SECTIONS") + set(snippet_path "${pinned_ram_sections_path}") + elseif("${location}" STREQUAL "PINNED_DATA_SECTIONS") + set(snippet_path "${pinned_data_sections_path}") + elseif("${location}" STREQUAL "PINNED_RODATA") + set(snippet_path "${pinned_rodata_path}") + else() + message(fatal_error "Must choose valid location for linker snippet.") + endif() + + cmake_parse_arguments(L "" "SORT_KEY" "" ${ARGN}) + set(SORT_KEY default) + if(DEFINED L_SORT_KEY) + set(SORT_KEY ${L_SORT_KEY}) + endif() + + foreach(file IN ITEMS ${L_UNPARSED_ARGUMENTS}) + # Resolve path. + if(IS_ABSOLUTE ${file}) + set(path ${file}) + else() + set(path ${CMAKE_CURRENT_SOURCE_DIR}/${file}) + endif() + + if(IS_DIRECTORY ${path}) + message(FATAL_ERROR "zephyr_linker_sources() was called on a directory") + endif() + + # Find the relative path to the linker file from the include folder. + file(RELATIVE_PATH relpath ${ZEPHYR_BASE}/include ${path}) + + # Create strings to be written into the file + set (include_str "/* Sort key: \"${SORT_KEY}\" */#include \"${relpath}\"") + + # Remove line from other snippet file, if already used + get_property(old_path GLOBAL PROPERTY "snippet_files_used_${relpath}") + if (DEFINED old_path) + file(STRINGS ${old_path} lines) + list(FILTER lines EXCLUDE REGEX ${relpath}) + string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line. + file(WRITE ${old_path} ${lines} "\n") + endif() + set_property(GLOBAL PROPERTY "snippet_files_used_${relpath}" ${snippet_path}) + + # Add new line to existing lines, sort them, and write them back. + file(STRINGS ${snippet_path} lines) # Get current lines (without newlines). + list(APPEND lines ${include_str}) + list(SORT lines) + string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line. + file(WRITE ${snippet_path} ${lines} "\n") + endforeach() +endfunction(zephyr_linker_sources) + +# Helper macro for conditionally calling zephyr_code_relocate() when a +# specific Kconfig symbol is enabled. See zephyr_code_relocate() description +# for supported arguments. +macro(zephyr_code_relocate_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_code_relocate(${ARGN}) + endif() +endmacro() + +# Helper function for CONFIG_CODE_DATA_RELOCATION +# This function may either be invoked with a list of files, or a library +# name to relocate. +# +# The FILES directive will relocate a list of files (wildcards supported) +# This directive will relocate file1. and file2.c to SRAM: +# zephyr_code_relocate(FILES file1.c file2.c LOCATION SRAM) +# Note, files can also be passed as a comma separated list to support using +# cmake generator arguments +# +# The LIBRARY directive will relocate a library +# This directive will relocate the target my_lib to SRAM: +# zephyr_code_relocate(LIBRARY my_lib SRAM) +# +# The following optional arguments are supported: +# - NOCOPY: this flag indicates that the file data does not need to be copied +# at boot time (For example, for flash XIP). +# - NOKEEP: suppress the generation of KEEP() statements in the linker script, +# to allow any unused code in the given files/library to be discarded. +# - PHDR [program_header]: add program header. Used on Xtensa platforms. +function(zephyr_code_relocate) + set(options NOCOPY NOKEEP) + set(single_args LIBRARY LOCATION PHDR) + set(multi_args FILES) + cmake_parse_arguments(CODE_REL "${options}" "${single_args}" + "${multi_args}" ${ARGN}) + # Argument validation + if(CODE_REL_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_code_relocate(${ARGV0} ...) " + "given unknown arguments: ${CODE_REL_UNPARSED_ARGUMENTS}") + endif() + if((NOT CODE_REL_FILES) AND (NOT CODE_REL_LIBRARY)) + message(FATAL_ERROR + "zephyr_code_relocate() requires either FILES or LIBRARY be provided") + endif() + if(CODE_REL_FILES AND CODE_REL_LIBRARY) + message(FATAL_ERROR "zephyr_code_relocate() only accepts " + "one argument between FILES and LIBRARY") + endif() + if(NOT CODE_REL_LOCATION) + message(FATAL_ERROR "zephyr_code_relocate() requires a LOCATION argument") + endif() + if(CODE_REL_LIBRARY) + # Use cmake generator expression to convert library to file list, + # supporting relative and absolute paths + set(genex_src_dir "$") + set(genex_src_list "$") + + if(CMAKE_HOST_WIN32) + # Note that this assumes windows absolute filenames start with a letter and colon, this does + # not support \\x network paths and is untested under the likes of msys2/cygwin + set(src_list_abs "$") + set(src_list_rel "$") + else() + set(src_list_abs "$") + set(src_list_rel "$") + endif() + + set(src_list "${genex_src_dir}/$${genex_src_dir}/>") + set(nonempty_src_list "$<$:${src_list}>") + set(sep_list "$<$,$>:$>") + set(file_list "${src_list_abs}${sep_list}${nonempty_src_list}") + else() + # Check if CODE_REL_FILES is a generator expression, if so leave it + # untouched. + string(GENEX_STRIP "${CODE_REL_FILES}" no_genex) + if(CODE_REL_FILES STREQUAL no_genex) + # no generator expression in CODE_REL_FILES, check if list of files + # is absolute + foreach(file ${CODE_REL_FILES}) + if(NOT IS_ABSOLUTE ${file}) + set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file}) + endif() + list(APPEND file_list ${file}) + endforeach() + else() + # Generator expression is present in file list. Leave the list untouched. + set(file_list ${CODE_REL_FILES}) + endif() + endif() + if(NOT CODE_REL_NOCOPY) + set(flag_list COPY) + else() + set(flag_list NOCOPY) + endif() + if(CODE_REL_NOKEEP) + list(APPEND flag_list NOKEEP) + endif() + if(CODE_REL_PHDR) + set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}") + endif() + # We use the "|" character to separate code relocation directives, instead of + # using set_property(APPEND) to produce a ";"-separated CMake list. This way, + # each directive can embed multiple CMake lists, representing flags and files, + # the latter of which can come from generator expressions. + get_property(code_rel_str TARGET code_data_relocation_target + PROPERTY COMPILE_DEFINITIONS) + set_property(TARGET code_data_relocation_target + PROPERTY COMPILE_DEFINITIONS + "${code_rel_str}|${CODE_REL_LOCATION}:${flag_list}:${file_list}") +endfunction() + +# Usage: +# check_dtc_flag("-Wtest" DTC_WARN_TEST) +# +# Writes 1 to the output variable 'ok' if +# the flag is supported, otherwise writes 0. +# +# using +function(check_dtc_flag flag ok) + execute_process( + COMMAND + ${DTC} ${flag} -v + ERROR_QUIET + OUTPUT_QUIET + RESULT_VARIABLE dtc_check_ret + ) + if (dtc_check_ret EQUAL 0) + set(${ok} 1 PARENT_SCOPE) + else() + set(${ok} 0 PARENT_SCOPE) + endif() +endfunction() + +# Function to round number to next power of two. +# +# Usage: +# pow2round() +# +# Example: +# set(test 2) +# pow2round(test) +# # test is still 2 +# +# set(test 5) +# pow2round(test) +# # test is now 8 +# +# Arguments: +# n = Variable containing the number to round +function(pow2round n) + math(EXPR x "${${n}} & (${${n}} - 1)") + if(${x} EQUAL 0) + return() + endif() + + math(EXPR ${n} "${${n}} | (${${n}} >> 1)") + math(EXPR ${n} "${${n}} | (${${n}} >> 2)") + math(EXPR ${n} "${${n}} | (${${n}} >> 4)") + math(EXPR ${n} "${${n}} | (${${n}} >> 8)") + math(EXPR ${n} "${${n}} | (${${n}} >> 16)") + math(EXPR ${n} "${${n}} | (${${n}} >> 32)") + math(EXPR ${n} "${${n}} + 1") + set(${n} ${${n}} PARENT_SCOPE) +endfunction() + +# Function to create a build string based on BOARD, BOARD_REVISION, and BUILD +# type. +# +# This is a common function to ensure that build strings are always created +# in a uniform way. +# A single string is returned containing the full build string constructed from +# all arguments. +# +# When MERGE is supplied a list of build strings will be returned with the full +# build string as first item in the list. +# The full order of build strings returned in the list will be: +# - Normalized board target build string, this includes qualifiers and revision +# - Build string with board variants removed in addition +# - Build string with cpuset removed in addition +# - Build string with soc removed in addition +# +# If BUILD is supplied, then build type will be appended to each entry in the +# list above. +# If REVISION is supplied or obtained as system wide setting a build string +# with the sanitized revision string will be added in addition to the +# non-revisioned entry for each entry. +# +# Usage: +# zephyr_build_string( +# BOARD +# [BOARD_QUALIFIERS ] +# [BOARD_REVISION ] +# [BUILD ] +# [MERGE [REVERSE]] +# ) +# +# : Output variable where the build string will be returned. +# SHORT : Output variable where the shortened build string will be returned. +# BOARD : Board name to use when creating the build string. +# BOARD_REVISION : Board revision to use when creating the build string. +# BUILD : Build type to use when creating the build string. +# MERGE: Return a list of build strings instead of a single build string. +# REVERSE: Reverse the list before returning it. +# +# Examples +# calling +# zephyr_build_string(build_string BOARD alpha BUILD debug) +# will return the string `alpha_debug` in `build_string` parameter. +# +# calling +# zephyr_build_string(build_string BOARD alpha BOARD_REVISION 1.0.0 BUILD debug) +# will return the string `alpha_1_0_0_debug` in `build_string` parameter. +# +# calling +# zephyr_build_string(build_string BOARD alpha BOARD_QUALIFIERS /soc/bar) +# will return the string `alpha_soc_bar` in `build_string` parameter. +# +# calling +# zephyr_build_string(build_string BOARD alpha BOARD_REVISION 1.0.0 BOARD_QUALIFIERS /soc/bar MERGE) +# will return a list of the following strings +# `alpha_soc_bar_1_0_0;alpha_soc_bar` in `build_string` parameter. +# +# calling +# zephyr_build_string(build_string SHORTENED short_build_string BOARD alpha BOARD_REVISION 1.0.0 BOARD_QUALIFIERS /soc/bar MERGE) +# will return two lists of the following strings +# `alpha_soc_bar_1_0_0;alpha_soc_bar` in `build_string` parameter. +# `alpha_bar_1_0_0;alpha_bar` in `short_build_string` parameter. +# +function(zephyr_build_string outvar) + set(options MERGE REVERSE) + set(single_args BOARD BOARD_QUALIFIERS BOARD_REVISION BUILD SHORT) + + cmake_parse_arguments(BUILD_STR "${options}" "${single_args}" "" ${ARGN}) + if(BUILD_STR_UNPARSED_ARGUMENTS) + message(FATAL_ERROR + "zephyr_build_string(${ARGV0} ...) given unknown arguments:" + " ${BUILD_STR_UNPARSED_ARGUMENTS}" + ) + endif() + + if(DEFINED BUILD_STR_BOARD_REVISION AND NOT BUILD_STR_BOARD) + message(FATAL_ERROR + "zephyr_build_string(${ARGV0} BOARD_REVISION ${BUILD_STR_BOARD_REVISION} ...)" + " given without BOARD argument, please specify BOARD" + ) + endif() + + if(DEFINED BUILD_STR_BOARD_QUALIFIERS AND NOT BUILD_STR_BOARD) + message(FATAL_ERROR + "zephyr_build_string(${ARGV0} BOARD_QUALIFIERS ${BUILD_STR_BOARD_QUALIFIERS} ...)" + " given without BOARD argument, please specify BOARD" + ) + endif() + + string(REPLACE "/" ";" str_segment_list "${BUILD_STR_BOARD_QUALIFIERS}") + string(REPLACE "." "_" revision_string "${BUILD_STR_BOARD_REVISION}") + + string(JOIN "_" ${outvar} ${BUILD_STR_BOARD} ${str_segment_list} ${revision_string} ${BUILD_STR_BUILD}) + + if(BUILD_STR_MERGE) + string(JOIN "_" variant_string ${BUILD_STR_BOARD} ${str_segment_list} ${BUILD_STR_BUILD}) + + if(NOT "${variant_string}" IN_LIST ${outvar}) + list(APPEND ${outvar} "${variant_string}") + endif() + endif() + + if(BUILD_STR_REVERSE) + list(REVERSE ${outvar}) + endif() + list(REMOVE_DUPLICATES ${outvar}) + + if(BUILD_STR_SHORT AND BUILD_STR_BOARD_QUALIFIERS) + string(REGEX REPLACE "^/[^/]*(.*)" "\\1" shortened_qualifiers "${BOARD_QUALIFIERS}") + string(REPLACE "/" ";" str_short_segment_list "${shortened_qualifiers}") + string(JOIN "_" ${BUILD_STR_SHORT} + ${BUILD_STR_BOARD} ${str_short_segment_list} ${revision_string} ${BUILD_STR_BUILD} + ) + if(BUILD_STR_MERGE) + string(JOIN "_" variant_string ${BUILD_STR_BOARD} ${str_short_segment_list} ${BUILD_STR_BUILD}) + + if(NOT "${variant_string}" IN_LIST ${BUILD_STR_SHORT}) + list(APPEND ${BUILD_STR_SHORT} "${variant_string}") + endif() + endif() + + if(BUILD_STR_REVERSE) + list(REVERSE ${BUILD_STR_SHORT}) + endif() + list(REMOVE_DUPLICATES ${BUILD_STR_SHORT}) + set(${BUILD_STR_SHORT} ${${BUILD_STR_SHORT}} PARENT_SCOPE) + endif() + + # This updates the provided outvar in parent scope (callers scope) + set(${outvar} ${${outvar}} PARENT_SCOPE) +endfunction() + +# Function to add one or more directories to the include list passed to the syscall generator. +function(zephyr_syscall_include_directories) + foreach(one_dir ${ARGV}) + if(EXISTS ${one_dir}) + set(include_dir ${one_dir}) + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${one_dir}) + set(include_dir ${CMAKE_CURRENT_SOURCE_DIR}/${one_dir}) + else() + message(FATAL_ERROR "Syscall include directory not found: ${one_dir}") + endif() + + target_include_directories( + syscalls_interface INTERFACE + ${include_dir} + ) + add_dependencies( + syscalls_interface + ${include_dir} + ) + + unset(include_dir) + endforeach() +endfunction() + +# Function to add header file(s) to the list to be passed to syscall generator. +function(zephyr_syscall_header) + foreach(one_file ${ARGV}) + if(EXISTS ${one_file}) + set(header_file ${one_file}) + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${one_file}) + set(header_file ${CMAKE_CURRENT_SOURCE_DIR}/${one_file}) + else() + message(FATAL_ERROR "Syscall header file not found: ${one_file}") + endif() + + target_sources( + syscalls_interface INTERFACE + ${header_file} + ) + add_dependencies( + syscalls_interface + ${header_file} + ) + + unset(header_file) + endforeach() +endfunction() + +# Function to add header file(s) to the list to be passed to syscall generator +# if condition is true. +function(zephyr_syscall_header_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_syscall_header(${ARGN}) + endif() +endfunction() + +# Verify blobs fetched using west. If the sha256 checksum isn't valid, a warning/ +# fatal error message is printed (depends on REQUIRED flag). +# +# Usage: +# zephyr_blobs_verify( [REQUIRED]) +# +# Example: +# zephyr_blobs_verify(MODULE my_module REQUIRED) # verify all blobs in my_module and fail on error +# zephyr_blobs_verify(FILES img/file.bin) # verify a single file and print on error +function(zephyr_blobs_verify) + cmake_parse_arguments(BLOBS_VERIFY "REQUIRED" "MODULE" "FILES" ${ARGN}) + + if((DEFINED BLOBS_VERIFY_MODULE) EQUAL (DEFINED BLOBS_VERIFY_FILES)) + message(FATAL_ERROR "Either MODULE or FILES required when calling ${CMAKE_CURRENT_FUNCTION}") + endif() + + if(NOT WEST) + return() + endif() + + execute_process( + COMMAND ${WEST} blobs list ${BLOBS_VERIFY_MODULE} --format "{status} {abspath}" + OUTPUT_VARIABLE BLOBS_LIST_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + + if(${BLOBS_VERIFY_REQUIRED}) + set(msg_lvl FATAL_ERROR) + else() + set(msg_lvl WARNING) + endif() + + string(REPLACE "\n" ";" BLOBS_LIST ${BLOBS_LIST_OUTPUT}) + + if(DEFINED BLOBS_VERIFY_FILES) + foreach(file ${BLOBS_VERIFY_FILES}) + # Resolve path. + if(IS_ABSOLUTE ${file}) + file(REAL_PATH "${file}" real_path) + else() + file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${file}" real_path) + endif() + file(TO_NATIVE_PATH ${real_path} path) + + message(VERBOSE "Verifying blob \"${path}\"") + + # Each path that has a correct sha256 is prefixed with an A + if(NOT "A ${path}" IN_LIST BLOBS_LIST) + message(${msg_lvl} "Blob for path \"${path}\" isn't valid.") + endif() + endforeach() + else() + foreach(blob ${BLOBS_LIST}) + separate_arguments(blob) + list(GET blob 0 status) + list(GET blob 1 path) + + message(VERBOSE "Verifying blob \"${path}\"") + + if(NOT "${status}" STREQUAL "A") + message(${msg_lvl} "Blob for path \"${path}\" isn't valid. Update with: west blobs fetch ${BLOBS_VERIFY_MODULE}") + endif() + endforeach() + endif() +endfunction() + +######################################################## +# 2. Kconfig-aware extensions +######################################################## +# +# Kconfig is a configuration language developed for the Linux +# kernel. The below functions integrate CMake with Kconfig. +# + +# 2.1 Misc +# +# import_kconfig( [] [TARGET ]) +# +# Parse a KConfig fragment (typically with extension .config) and +# introduce all the symbols that are prefixed with 'prefix' into the +# CMake namespace. List all created variable names in the 'keys' +# output variable if present. +# +# : symbol prefix of settings in the Kconfig fragment. +# : absolute path to the config fragment file. +# : output variable which will be populated with variable +# names loaded from the kconfig fragment. +# TARGET : set all symbols on instead of adding them to the +# CMake namespace. +function(import_kconfig prefix kconfig_fragment) + cmake_parse_arguments(IMPORT_KCONFIG "" "TARGET" "" ${ARGN}) + file( + STRINGS + ${kconfig_fragment} + DOT_CONFIG_LIST + ENCODING "UTF-8" + ) + + foreach (LINE ${DOT_CONFIG_LIST}) + if("${LINE}" MATCHES "^(${prefix}[^=]+)=([ymn]|.+$)") + # Matched a normal value assignment, like: CONFIG_NET_BUF=y + # Note: if the value starts with 'y', 'm', or 'n', then we assume it's a + # bool or tristate (we don't know the type from alone) + # and we only match the first character. This is to align with Kconfiglib. + set(CONF_VARIABLE_NAME "${CMAKE_MATCH_1}") + set(CONF_VARIABLE_VALUE "${CMAKE_MATCH_2}") + elseif("${LINE}" MATCHES "^# (${prefix}[^ ]+) is not set") + # Matched something like: # CONFIG_FOO is not set + # This is interpreted as: CONFIG_FOO=n + set(CONF_VARIABLE_NAME "${CMAKE_MATCH_1}") + set(CONF_VARIABLE_VALUE "n") + else() + # Ignore this line. + # Note: we also ignore assignments which don't have the desired . + continue() + endif() + + # If the provided value is n, then the corresponding CMake variable or + # target property will be unset. + if("${CONF_VARIABLE_VALUE}" STREQUAL "n") + if(DEFINED IMPORT_KCONFIG_TARGET) + set_property(TARGET ${IMPORT_KCONFIG_TARGET} PROPERTY "${CONF_VARIABLE_NAME}") + else() + unset("${CONF_VARIABLE_NAME}" PARENT_SCOPE) + endif() + list(REMOVE_ITEM keys "${CONF_VARIABLE_NAME}") + continue() + endif() + + # Otherwise, the variable/property will be set to the provided value. + # For string values, we also remove the surrounding quotation marks. + if("${CONF_VARIABLE_VALUE}" MATCHES "^\"(.*)\"$") + set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1}) + endif() + + if(DEFINED IMPORT_KCONFIG_TARGET) + set_property(TARGET ${IMPORT_KCONFIG_TARGET} PROPERTY "${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}") + else() + set("${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}" PARENT_SCOPE) + endif() + list(APPEND keys "${CONF_VARIABLE_NAME}") + endforeach() + + if(DEFINED IMPORT_KCONFIG_TARGET) + set_property(TARGET ${IMPORT_KCONFIG_TARGET} PROPERTY "kconfigs" "${keys}") + endif() + + list(LENGTH IMPORT_KCONFIG_UNPARSED_ARGUMENTS unparsed_length) + if(unparsed_length GREATER 0) + if(unparsed_length GREATER 1) + # Two mandatory arguments and one optional, anything after that is an error. + list(GET IMPORT_KCONFIG_UNPARSED_ARGUMENTS 1 first_invalid) + message(FATAL_ERROR "Unexpected argument after '': import_kconfig(... ${first_invalid})") + endif() + set(${IMPORT_KCONFIG_UNPARSED_ARGUMENTS} "${keys}" PARENT_SCOPE) + endif() +endfunction() + +######################################################## +# 3. CMake-generic extensions +######################################################## +# +# These functions extend the CMake API in a way that is not particular +# to Zephyr. Primarily they work around limitations in the CMake +# language to allow cleaner build scripts. + +# 3.1. *_ifdef +# +# Functions for conditionally executing CMake functions with oneliners +# e.g. +# +# if(CONFIG_FFT) +# zephyr_library_source( +# fft_32.c +# fft_utils.c +# ) +# endif() +# +# Becomes +# +# zephyr_source_ifdef( +# CONFIG_FFT +# fft_32.c +# fft_utils.c +# ) +# +# More Generally +# "_ifdef(CONDITION args)" +# Becomes +# """ +# if(CONDITION) +# (args) +# endif() +# """ +# +# ifdef functions are added on an as-need basis. See +# https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for +# a list of available functions. +function(add_subdirectory_ifdef feature_toggle source_dir) + if(${${feature_toggle}}) + add_subdirectory(${source_dir} ${ARGN}) + endif() +endfunction() + +function(target_sources_ifdef feature_toggle target scope item) + if(${${feature_toggle}}) + target_sources(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_compile_definitions_ifdef feature_toggle target scope item) + if(${${feature_toggle}}) + target_compile_definitions(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_include_directories_ifdef feature_toggle target scope item) + if(${${feature_toggle}}) + target_include_directories(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_link_libraries_ifdef feature_toggle target item) + if(${${feature_toggle}}) + target_link_libraries(${target} ${item} ${ARGN}) + endif() +endfunction() + +function(add_compile_option_ifdef feature_toggle option) + if(${${feature_toggle}}) + add_compile_options(${option}) + endif() +endfunction() + +function(target_compile_option_ifdef feature_toggle target scope option) + if(${feature_toggle}) + target_compile_options(${target} ${scope} ${option}) + endif() +endfunction() + +function(target_cc_option_ifdef feature_toggle target scope option) + if(${feature_toggle}) + target_cc_option(${target} ${scope} ${option}) + endif() +endfunction() + +function(zephyr_library_sources_ifdef feature_toggle source) + if(${${feature_toggle}}) + zephyr_library_sources(${source} ${ARGN}) + endif() +endfunction() + +function(zephyr_sources_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_sources(${ARGN}) + endif() +endfunction() + +function(zephyr_cc_option_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_cc_option(${ARGN}) + endif() +endfunction() + +function(zephyr_ld_option_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_ld_options(${ARGN}) + endif() +endfunction() + +function(zephyr_link_libraries_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_link_libraries(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_options_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_compile_options(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_definitions_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_compile_definitions(${ARGN}) + endif() +endfunction() + +function(zephyr_include_directories_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_definitions_ifdef feature_toggle item) + if(${${feature_toggle}}) + zephyr_library_compile_definitions(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_library_include_directories_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_library_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_options_ifdef feature_toggle item) + if(${${feature_toggle}}) + zephyr_library_compile_options(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_link_interface_ifdef feature_toggle interface) + if(${${feature_toggle}}) + target_link_libraries(${interface} INTERFACE zephyr_interface) + endif() +endfunction() + +function(zephyr_library_link_libraries_ifdef feature_toggle item) + if(${${feature_toggle}}) + zephyr_library_link_libraries(${item}) + endif() +endfunction() + +function(zephyr_linker_sources_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_linker_sources(${ARGN}) + endif() +endfunction() + +function(zephyr_library_add_dependencies_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_library_add_dependencies(${ARGN}) + endif() +endfunction() + +macro(list_append_ifdef feature_toggle list) + if(${${feature_toggle}}) + list(APPEND ${list} ${ARGN}) + endif() +endmacro() + +# 3.2. *_ifndef +# See 3.1 *_ifdef +function(set_ifndef variable value) + if(NOT ${variable}) + set(${variable} ${value} ${ARGN} PARENT_SCOPE) + endif() +endfunction() + +function(add_subdirectory_ifndef feature_toggle source_dir) + if(NOT ${feature_toggle}) + add_subdirectory(${source_dir} ${ARGN}) + endif() +endfunction() + +function(target_sources_ifndef feature_toggle target scope item) + if(NOT ${feature_toggle}) + target_sources(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_compile_definitions_ifndef feature_toggle target scope item) + if(NOT ${feature_toggle}) + target_compile_definitions(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_include_directories_ifndef feature_toggle target scope item) + if(NOT ${feature_toggle}) + target_include_directories(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_link_libraries_ifndef feature_toggle target item) + if(NOT ${feature_toggle}) + target_link_libraries(${target} ${item} ${ARGN}) + endif() +endfunction() + +function(add_compile_option_ifndef feature_toggle option) + if(NOT ${feature_toggle}) + add_compile_options(${option}) + endif() +endfunction() + +function(target_compile_option_ifndef feature_toggle target scope option) + if(NOT ${feature_toggle}) + target_compile_options(${target} ${scope} ${option}) + endif() +endfunction() + +function(target_cc_option_ifndef feature_toggle target scope option) + if(NOT ${feature_toggle}) + target_cc_option(${target} ${scope} ${option}) + endif() +endfunction() + +function(zephyr_library_sources_ifndef feature_toggle source) + if(NOT ${feature_toggle}) + zephyr_library_sources(${source} ${ARGN}) + endif() +endfunction() + +function(zephyr_sources_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_sources(${ARGN}) + endif() +endfunction() + +function(zephyr_cc_option_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_cc_option(${ARGN}) + endif() +endfunction() + +function(zephyr_ld_option_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_ld_options(${ARGN}) + endif() +endfunction() + +function(zephyr_link_libraries_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_link_libraries(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_options_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_compile_options(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_definitions_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_compile_definitions(${ARGN}) + endif() +endfunction() + +function(zephyr_include_directories_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_definitions_ifndef feature_toggle item) + if(NOT ${feature_toggle}) + zephyr_library_compile_definitions(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_library_include_directories_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_library_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_options_ifndef feature_toggle item) + if(NOT ${feature_toggle}) + zephyr_library_compile_options(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_link_interface_ifndef feature_toggle interface) + if(NOT ${feature_toggle}) + target_link_libraries(${interface} INTERFACE zephyr_interface) + endif() +endfunction() + +function(zephyr_library_link_libraries_ifndef feature_toggle item) + if(NOT ${feature_toggle}) + zephyr_library_link_libraries(${item}) + endif() +endfunction() + +function(zephyr_linker_sources_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_linker_sources(${ARGN}) + endif() +endfunction() + +function(zephyr_library_add_dependencies_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_library_add_dependencies(${ARGN}) + endif() +endfunction() + +macro(list_append_ifndef feature_toggle list) + if(NOT ${feature_toggle}) + list(APPEND ${list} ${ARGN}) + endif() +endmacro() + +# 3.3. *_option Compiler-compatibility checks +# +# Utility functions for silently omitting compiler flags when the +# compiler lacks support. *_cc_option was ported from KBuild, see +# cc-option in +# https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt + +# Writes 1 to the output variable 'ok' for the language 'lang' if +# the flag is supported, otherwise writes 0. +# +# lang must be C or CXX +# +# TODO: Support ASM +# +# Usage: +# +# check_compiler_flag(C "-Wall" my_check) +# print(my_check) # my_check is now 1 +function(check_compiler_flag lang option ok) + if(NOT DEFINED CMAKE_REQUIRED_QUIET) + set(CMAKE_REQUIRED_QUIET 1) + endif() + + string(MAKE_C_IDENTIFIER + "check${option}_${lang}_${CMAKE_REQUIRED_FLAGS}" + ${ok} + ) + + if(${lang} STREQUAL C) + check_c_compiler_flag("${option}" ${${ok}}) + else() + check_cxx_compiler_flag("${option}" ${${ok}}) + endif() + + if(${${${ok}}}) + set(ret 1) + else() + set(ret 0) + endif() + + set(${ok} ${ret} PARENT_SCOPE) +endfunction() + +function(target_cc_option target scope option) + target_cc_option_fallback(${target} ${scope} ${option} "") +endfunction() + +# Support an optional second option for when the first option is not +# supported. +function(target_cc_option_fallback target scope option1 option2) + if(CONFIG_CPP) + foreach(lang C CXX) + # For now, we assume that all flags that apply to C/CXX also + # apply to ASM. + zephyr_check_compiler_flag(${lang} ${option1} check) + if(${check}) + target_compile_options(${target} ${scope} + $<$:${option1}> + $<$:${option1}> + ) + elseif(option2) + target_compile_options(${target} ${scope} + $<$:${option2}> + $<$:${option2}> + ) + endif() + endforeach() + else() + zephyr_check_compiler_flag(C ${option1} check) + if(${check}) + target_compile_options(${target} ${scope} ${option1}) + elseif(option2) + target_compile_options(${target} ${scope} ${option2}) + endif() + endif() +endfunction() + +function(target_ld_options target scope) + zephyr_get_parse_args(args ${ARGN}) + list(REMOVE_ITEM ARGN NO_SPLIT) + + foreach(option ${ARGN}) + if(args_NO_SPLIT) + set(option ${ARGN}) + endif() + string(JOIN "" check_identifier "check" ${option}) + string(MAKE_C_IDENTIFIER ${check_identifier} check) + + set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + string(JOIN " " CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ${option}) + zephyr_check_compiler_flag(C "" ${check}) + set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS}) + + target_link_libraries_ifdef(${check} ${target} ${scope} ${option}) + + if(args_NO_SPLIT) + break() + endif() + endforeach() +endfunction() + +# 3.3.1 Toolchain integration +# +# 'toolchain_parse_make_rule' is a function that parses the output of +# 'gcc -M'. +# +# The argument 'input_file' is in input parameter with the path to the +# file with the dependency information. +# +# The argument 'include_files' is an output parameter with the result +# of parsing the include files. +function(toolchain_parse_make_rule input_file include_files) + file(STRINGS ${input_file} input) + + # The file is formatted like this: + # empty_file.o: misc/empty_file.c \ + # nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts \ + # nrf52840_qiaa.dtsi + + # The dep file will contain `\` for line continuation. + # This results in `\;` which is then treated a the char `;` instead of + # the element separator, so let's get the pure `;` back. + string(REPLACE "\;" ";" input_as_list ${input}) + + # Pop the first line and treat it specially + list(POP_FRONT input_as_list first_input_line) + string(FIND ${first_input_line} ": " index) + math(EXPR j "${index} + 2") + string(SUBSTRING ${first_input_line} ${j} -1 first_include_file) + + # Remove whitespace before and after filename and convert to CMake path. + string(STRIP "${first_include_file}" first_include_file) + file(TO_CMAKE_PATH "${first_include_file}" first_include_file) + set(result "${first_include_file}") + + # Remove whitespace before and after filename and convert to CMake path. + foreach(file ${input_as_list}) + string(STRIP "${file}" file) + file(TO_CMAKE_PATH "${file}" file) + list(APPEND result "${file}") + endforeach() + + set(${include_files} ${result} PARENT_SCOPE) +endfunction() + +# 'check_set_linker_property' is a function that check the provided linker +# flag and only set the linker property if the check succeeds +# +# This function is similar in nature to the CMake set_property function, but +# with the extension that it will check that the linker supports the flag before +# setting the property. +# +# APPEND: Flag indicated that the property should be appended to the existing +# value list for the property. +# TARGET: Name of target on which to add the property (commonly: linker) +# PROPERTY: Name of property with the value(s) following immediately after +# property name +function(check_set_linker_property) + set(options APPEND) + set(single_args TARGET) + set(multi_args PROPERTY) + cmake_parse_arguments(LINKER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + if(LINKER_PROPERTY_APPEND) + set(APPEND "APPEND") + endif() + + list(GET LINKER_PROPERTY_PROPERTY 0 property) + list(REMOVE_AT LINKER_PROPERTY_PROPERTY 0) + set(option ${LINKER_PROPERTY_PROPERTY}) + + string(MAKE_C_IDENTIFIER check${option} check) + + set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${option}") + zephyr_check_compiler_flag(C "" ${check}) + set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS}) + + if(${${check}}) + set_property(TARGET ${LINKER_PROPERTY_TARGET} ${APPEND} PROPERTY ${property} ${option}) + endif() +endfunction() + +# 'set_compiler_property' is a function that sets the property for the C and +# C++ property targets used for toolchain abstraction. +# +# This function is similar in nature to the CMake set_property function, but +# with the extension that it will set the property on both the compile and +# compiler-cpp targets. +# +# APPEND: Flag indicated that the property should be appended to the existing +# value list for the property. +# PROPERTY: Name of property with the value(s) following immediately after +# property name +function(set_compiler_property) + set(options APPEND) + set(multi_args PROPERTY) + cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN}) + if(COMPILER_PROPERTY_APPEND) + set(APPEND "APPEND") + set(APPEND-CPP "APPEND") + endif() + + set_property(TARGET compiler ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY}) + set_property(TARGET compiler-cpp ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY}) +endfunction() + +# 'check_set_compiler_property' is a function that check the provided compiler +# flag and only set the compiler or compiler-cpp property if the check succeeds +# +# This function is similar in nature to the CMake set_property function, but +# with the extension that it will check that the compiler supports the flag +# before setting the property on compiler or compiler-cpp targets. +# +# To test flags together, such as '-Wformat -Wformat-security', an option group +# can be specified by using shell-like quoting along with a 'SHELL:' prefix. +# The 'SHELL:' prefix will be dropped before testing, so that +# '"SHELL:-Wformat -Wformat-security"' becomes '-Wformat -Wformat-security' for +# testing. +# +# APPEND: Flag indicated that the property should be appended to the existing +# value list for the property. +# PROPERTY: Name of property with the value(s) following immediately after +# property name +function(check_set_compiler_property) + set(options APPEND) + set(multi_args PROPERTY) + cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN}) + if(COMPILER_PROPERTY_APPEND) + set(APPEND "APPEND") + set(APPEND-CPP "APPEND") + endif() + + list(GET COMPILER_PROPERTY_PROPERTY 0 property) + list(REMOVE_AT COMPILER_PROPERTY_PROPERTY 0) + + foreach(option ${COMPILER_PROPERTY_PROPERTY}) + if(${option} MATCHES "^SHELL:") + string(REGEX REPLACE "^SHELL:" "" option ${option}) + separate_arguments(option UNIX_COMMAND ${option}) + endif() + + if(CONFIG_CPP) + zephyr_check_compiler_flag(CXX "${option}" check) + + if(${check}) + set_property(TARGET compiler-cpp ${APPEND-CPP} PROPERTY ${property} ${option}) + set(APPEND-CPP "APPEND") + endif() + endif() + + zephyr_check_compiler_flag(C "${option}" check) + + if(${check}) + set_property(TARGET compiler ${APPEND} PROPERTY ${property} ${option}) + set(APPEND "APPEND") + endif() + endforeach() +endfunction() + + +# 3.4. Debugging CMake + +# Usage: +# print(BOARD) +# +# will print: "BOARD: nrf52dk" +function(print arg) + message(STATUS "${arg}: ${${arg}}") +endfunction() + +# Usage: +# assert(ZEPHYR_TOOLCHAIN_VARIANT "ZEPHYR_TOOLCHAIN_VARIANT not set.") +# +# will cause a FATAL_ERROR and print an error message if the first +# expression is false +macro(assert test comment) + if(NOT ${test}) + message(FATAL_ERROR "Assertion failed: ${comment}") + endif() +endmacro() + +# Usage: +# assert_not(OBSOLETE_VAR "OBSOLETE_VAR has been removed; use NEW_VAR instead") +# +# will cause a FATAL_ERROR and print an error message if the first +# expression is true +macro(assert_not test comment) + if(${test}) + message(FATAL_ERROR "Assertion failed: ${comment}") + endif() +endmacro() + +# Usage: +# assert_exists(CMAKE_READELF) +# +# will cause a FATAL_ERROR if there is no file or directory behind the +# variable +macro(assert_exists var) + if(NOT EXISTS ${${var}}) + message(FATAL_ERROR "No such file or directory: ${var}: '${${var}}'") + endif() +endmacro() + +# 3.5. File system management +function(generate_unique_target_name_from_filename filename target_name) + get_filename_component(basename ${filename} NAME) + string(REPLACE "." "_" x ${basename}) + string(REPLACE "@" "_" x ${x}) + + string(MD5 unique_chars ${filename}) + + set(${target_name} gen_${x}_${unique_chars} PARENT_SCOPE) +endfunction() + +# Usage: +# zephyr_file( ...) +# +# Zephyr file function extension. +# This function currently supports the following +# +# APPLICATION_ROOT : Check all paths in provided variable, and convert +# those paths that are defined with `-D=` +# to absolute path, relative from `APPLICATION_SOURCE_DIR` +# Issue an error for any relative path not specified +# by user with `-D` +# +# returns an updated list of absolute paths +# +# Usage: +# zephyr_file(CONF_FILES [DTS ] [KCONF ] +# [BOARD [BOARD_REVISION ] | NAMES ...] +# [BUILD ] [SUFFIX ] [REQUIRED] +# ) +# +# CONF_FILES : Find all configuration files in the list of paths and +# return them in a list. If paths is empty then no configuration +# files are returned. Configuration files will be: +# - DTS: Overlay files (.overlay) +# - Kconfig: Config fragments (.conf) +# - defconfig: defconfig files (_defconfig) +# The conf file search will return existing configuration +# files for the current board. +# CONF_FILES takes the following additional arguments: +# BOARD : Find configuration files for specified board. +# BOARD_REVISION : Find configuration files for specified board +# revision. Requires BOARD to be specified. +# +# If no board is given the current BOARD and +# BOARD_REVISION will be used, unless NAMES are +# specified. +# +# NAMES [name2] ... List of file names to look for and instead of +# creating file names based on board settings. +# Only the first match found in will be +# returned in the +# DTS : List to append DTS overlay files in to +# KCONF : List to append Kconfig fragment files in to +# DEFCONF : List to append _defconfig files in to +# BUILD : Build type to include for search. +# For example: +# BUILD debug, will look for _debug.conf +# and _debug.overlay, instead of .conf +# SUFFIX : Suffix name to check for instead of the default name +# but with a fallback to the default name if not found. +# For example: +# SUFFIX fish, will look for _fish.conf and use +# if found but will use .conf if not found +# REQUIRED: Option to indicate that the specified by DTS or KCONF +# must contain at least one element, else an error will be raised. +# +function(zephyr_file) + set(file_options APPLICATION_ROOT CONF_FILES) + if((ARGC EQUAL 0) OR (NOT (ARGV0 IN_LIST file_options))) + message(FATAL_ERROR "No given to `zephyr_file( ...)` function,\n \ +Please provide one of following: APPLICATION_ROOT, CONF_FILES") + endif() + + if(${ARGV0} STREQUAL APPLICATION_ROOT) + set(single_args APPLICATION_ROOT) + elseif(${ARGV0} STREQUAL CONF_FILES) + set(options REQUIRED) + set(single_args BOARD BOARD_REVISION BOARD_QUALIFIERS DTS KCONF DEFCONFIG BUILD SUFFIX) + set(multi_args CONF_FILES NAMES) + endif() + + cmake_parse_arguments(ZFILE "${options}" "${single_args}" "${multi_args}" ${ARGN}) + if(ZFILE_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_file(${ARGV0} ...) given unknown arguments: ${ZFILE_UNPARSED_ARGUMENTS}") + endif() + + if(ZFILE_APPLICATION_ROOT) + # Note: user can do: `-D=` and app can at same + # time specify `list(APPEND )` + # Thus need to check and update only CACHED variables (-D). + set(CACHED_PATH $CACHE{${ZFILE_APPLICATION_ROOT}}) + foreach(path ${CACHED_PATH}) + # The cached variable is relative path, i.e. provided by `-D` or + # `set( CACHE)`, so let's update current scope variable to absolute + # path from `APPLICATION_SOURCE_DIR`. + if(NOT IS_ABSOLUTE ${path}) + set(abs_path ${APPLICATION_SOURCE_DIR}/${path}) + list(FIND ${ZFILE_APPLICATION_ROOT} ${path} index) + if(NOT ${index} LESS 0) + list(REMOVE_AT ${ZFILE_APPLICATION_ROOT} ${index}) + list(INSERT ${ZFILE_APPLICATION_ROOT} ${index} ${abs_path}) + endif() + endif() + endforeach() + + # Now all cached relative paths has been updated. + # Let's check if anyone uses relative path as scoped variable, and fail + foreach(path ${${ZFILE_APPLICATION_ROOT}}) + if(NOT IS_ABSOLUTE ${path}) + message(FATAL_ERROR +"Relative path encountered in scoped variable: ${ZFILE_APPLICATION_ROOT}, value=${path}\n \ +Please adjust any `set(${ZFILE_APPLICATION_ROOT} ${path})` or `list(APPEND ${ZFILE_APPLICATION_ROOT} ${path})`\n \ +to absolute path using `\${CMAKE_CURRENT_SOURCE_DIR}/${path}` or similar. \n \ +Relative paths are only allowed with `-D${ARGV1}=`") + endif() + endforeach() + + # This updates the provided argument in parent scope (callers scope) + set(${ZFILE_APPLICATION_ROOT} ${${ZFILE_APPLICATION_ROOT}} PARENT_SCOPE) + endif() + + if(ZFILE_CONF_FILES) + if(DEFINED ZFILE_BOARD_REVISION AND NOT ZFILE_BOARD) + message(FATAL_ERROR + "zephyr_file(${ARGV0} BOARD_REVISION ${ZFILE_BOARD_REVISION} ...)" + " given without BOARD argument, please specify BOARD" + ) + endif() + + if(NOT DEFINED ZFILE_BOARD) + # Defaulting to system wide settings when BOARD is not given as argument + set(ZFILE_BOARD ${BOARD}) + if(DEFINED BOARD_REVISION) + set(ZFILE_BOARD_REVISION ${BOARD_REVISION}) + endif() + + if(DEFINED BOARD_QUALIFIERS) + set(ZFILE_BOARD_QUALIFIERS ${BOARD_QUALIFIERS}) + endif() + endif() + + if(ZFILE_NAMES) + set(dts_filename_list ${ZFILE_NAMES}) + set(kconf_filename_list ${ZFILE_NAMES}) + else() + zephyr_build_string(filename_list + SHORT shortened_filename_list + BOARD ${ZFILE_BOARD} + BOARD_REVISION ${ZFILE_BOARD_REVISION} + BOARD_QUALIFIERS ${ZFILE_BOARD_QUALIFIERS} + BUILD ${ZFILE_BUILD} + MERGE REVERSE + ) + + set(dts_filename_list ${filename_list}) + set(dts_shortened_filename_list ${shortened_filename_list}) + list(TRANSFORM dts_filename_list APPEND ".overlay") + list(TRANSFORM dts_shortened_filename_list APPEND ".overlay") + + set(kconf_filename_list ${filename_list}) + set(kconf_shortened_filename_list ${shortened_filename_list}) + list(TRANSFORM kconf_filename_list APPEND ".conf") + list(TRANSFORM kconf_shortened_filename_list APPEND ".conf") + endif() + + if(ZFILE_DTS) + foreach(path ${ZFILE_CONF_FILES}) + foreach(filename IN ZIP_LISTS dts_filename_list dts_shortened_filename_list) + foreach(i RANGE 1) + if(NOT IS_ABSOLUTE filename_${i} AND DEFINED filename_${i}) + set(test_file_${i} ${path}/${filename_${i}}) + else() + set(test_file_${i} ${filename_${i}}) + endif() + zephyr_file_suffix(test_file_${i} SUFFIX ${ZFILE_SUFFIX}) + + if(NOT EXISTS ${test_file_${i}}) + set(test_file_${i}) + endif() + endforeach() + + if(test_file_0 OR test_file_1) + list(APPEND found_dts_files ${test_file_0}) + list(APPEND found_dts_files ${test_file_1}) + + if(DEFINED ZFILE_BUILD) + set(deprecated_file_found y) + endif() + + if(ZFILE_NAMES) + break() + endif() + endif() + + if(test_file_1 AND NOT BOARD_${ZFILE_BOARD}_SINGLE_SOC) + message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name " + "(${filename_1}) not allowed, use '_.overlay' naming" + ) + endif() + + if(test_file_0 AND test_file_1) + message(FATAL_ERROR "Conflicting file names discovered. Cannot use both ${filename_0} " + "and ${filename_1}. Please choose one naming style, " + "${filename_0} is recommended." + ) + endif() + endforeach() + endforeach() + + list(APPEND ${ZFILE_DTS} ${found_dts_files}) + + # This updates the provided list in parent scope (callers scope) + set(${ZFILE_DTS} ${${ZFILE_DTS}} PARENT_SCOPE) + endif() + + if(ZFILE_KCONF) + set(found_conf_files) + foreach(path ${ZFILE_CONF_FILES}) + foreach(filename IN ZIP_LISTS kconf_filename_list kconf_shortened_filename_list) + foreach(i RANGE 1) + if(NOT IS_ABSOLUTE filename_${i} AND DEFINED filename_${i}) + set(test_file_${i} ${path}/${filename_${i}}) + else() + set(test_file_${i} ${filename_${i}}) + endif() + zephyr_file_suffix(test_file_${i} SUFFIX ${ZFILE_SUFFIX}) + + if(NOT EXISTS ${test_file_${i}}) + set(test_file_${i}) + endif() + endforeach() + + if(test_file_0 OR test_file_1) + list(APPEND found_conf_files ${test_file_0}) + list(APPEND found_conf_files ${test_file_1}) + + if(DEFINED ZFILE_BUILD) + set(deprecated_file_found y) + endif() + + if(ZFILE_NAMES) + break() + endif() + endif() + + if(test_file_1 AND NOT BOARD_${ZFILE_BOARD}_SINGLE_SOC) + message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name " + "(${filename_1}) not allowed, use '_.conf' naming" + ) + endif() + + if(test_file_0 AND test_file_1) + message(FATAL_ERROR "Conflicting file names discovered. Cannot use both ${filename_0} " + "and ${filename_1}. Please choose one naming style, " + "${filename_0} is recommended." + ) + endif() + endforeach() + endforeach() + + list(APPEND ${ZFILE_KCONF} ${found_conf_files}) + + # This updates the provided list in parent scope (callers scope) + set(${ZFILE_KCONF} ${${ZFILE_KCONF}} PARENT_SCOPE) + + if(NOT ${ZFILE_KCONF}) + set(not_found ${kconf_filename_list}) + endif() + endif() + + if(ZFILE_REQUIRED AND DEFINED not_found) + message(FATAL_ERROR + "No ${not_found} file(s) was found in the ${ZFILE_CONF_FILES} folder(s), " + "please read the Zephyr documentation on application development." + ) + endif() + + if(deprecated_file_found) + message(DEPRECATION "prj_.conf was deprecated after Zephyr 3.5," + " you should switch to using -DFILE_SUFFIX instead") + endif() + + if(ZFILE_DEFCONFIG) + set(found_defconf_files) + foreach(path ${ZFILE_CONF_FILES}) + foreach(filename IN ZIP_LISTS filename_list shortened_filename_list) + foreach(i RANGE 1) + set(test_file_${i} ${path}/${filename_${i}}_defconfig) + + if(EXISTS ${test_file_${i}}) + list(APPEND found_defconf_files ${test_file_${i}}) + else() + set(test_file_${i}) + endif() + endforeach() + + if(test_file_1 AND NOT BOARD_${ZFILE_BOARD}_SINGLE_SOC) + message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name " + "(${filename_1}_defconfig) not allowed, use '__defconfig' naming" + ) + endif() + + if(test_file_0 AND test_file_1) + message(FATAL_ERROR "Conflicting file names discovered. Cannot use both " + "${filename_0}_defconfig and ${filename_1}_defconfig. Please choose one " + "naming style, ${filename_0}_defconfig is recommended." + ) + endif() + endforeach() + endforeach() + list(APPEND ${ZFILE_DEFCONFIG} ${found_defconf_files}) + + # This updates the provided list in parent scope (callers scope) + set(${ZFILE_DEFCONFIG} ${${ZFILE_DEFCONFIG}} PARENT_SCOPE) + endif() + endif() +endfunction() + +# Usage: +# zephyr_file_copy( [ONLY_IF_DIFFERENT]) +# +# Zephyr file copy extension. +# This function is similar to CMake function +# 'file(COPY_FILE [ONLY_IF_DIFFERENT])' +# introduced with CMake 3.21. +# +# Because the minimal required CMake version with Zephyr is 3.20, this function +# is not guaranteed to be available. +# +# When using CMake version 3.21 or newer 'zephyr_file_copy()' simply calls +# 'file(COPY_FILE...)' directly. +# When using CMake version 3.20, the implementation will execute using CMake +# for running command line tool in a subprocess for identical functionality. +function(zephyr_file_copy oldname newname) + set(options ONLY_IF_DIFFERENT) + cmake_parse_arguments(ZEPHYR_FILE_COPY "${options}" "" "" ${ARGN}) + + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21.0) + if(ZEPHYR_FILE_COPY_ONLY_IF_DIFFERENT) + set(copy_file_options ONLY_IF_DIFFERENT) + endif() + file(COPY_FILE ${oldname} ${newname} ${copy_file_options}) + else() + if(ZEPHYR_FILE_COPY_ONLY_IF_DIFFERENT) + set(copy_file_command copy_if_different) + else() + set(copy_file_command copy) + endif() + execute_process( + COMMAND ${CMAKE_COMMAND} -E ${copy_file_command} ${oldname} ${newname} + ) + endif() +endfunction() + +# Usage: +# zephyr_file_suffix( SUFFIX ) +# +# Zephyr file add suffix extension. +# This function will check the provied filename or list of filenames to see if they have a +# `_` extension to them and if so, updates the supplied variable/list with the new +# path/paths. +# +# : Variable (singlular or list) of absolute path filename(s) which should be checked +# and updated if there is a filename which has the present. +# : The suffix to test for and append to the end of the provided filename. +# +# Returns an updated variable of absolute path(s) +# +function(zephyr_file_suffix filename) + set(single_args SUFFIX) + cmake_parse_arguments(SFILE "" "${single_args}" "" ${ARGN}) + + if(NOT DEFINED SFILE_SUFFIX OR NOT DEFINED ${filename}) + # If the file suffix variable is not known then there is nothing to do, return early + return() + endif() + + set(tmp_new_list) + + foreach(file ${${filename}}) + if("${file}" STREQUAL "") + # Skip checking empty variables + continue() + endif() + + # Search for the full stop so we know where to add the file suffix before the file extension + cmake_path(GET file EXTENSION file_ext) + cmake_path(REMOVE_EXTENSION file OUTPUT_VARIABLE new_filename) + cmake_path(APPEND_STRING new_filename "_${SFILE_SUFFIX}${file_ext}") + + # Use the filename with the suffix if it exists, if not then fall back to the default + if(EXISTS "${new_filename}") + list(APPEND tmp_new_list ${new_filename}) + else() + list(APPEND tmp_new_list ${file}) + endif() + endforeach() + + # Update supplied variable if it differs + if(NOT "${${filename}}" STREQUAL "${tmp_new_list}") + set(${filename} "${tmp_new_list}" PARENT_SCOPE) + endif() +endfunction() + +# Usage: +# zephyr_string( ...) +# +# Zephyr string function extension. +# This function extends the CMake string function by providing additional +# manipulation arguments to CMake string. +# +# SANITIZE: Ensure that the output string does not contain any special +# characters. Special characters, such as -, +, =, $, etc. are +# converted to underscores '_'. +# +# SANITIZE TOUPPER: Ensure that the output string does not contain any special +# characters. Special characters, such as -, +, =, $, etc. are +# converted to underscores '_'. +# The sanitized string will be returned in UPPER case. +# +# returns the updated string +function(zephyr_string) + set(options SANITIZE TOUPPER) + cmake_parse_arguments(ZEPHYR_STRING "${options}" "" "" ${ARGN}) + + if (NOT ZEPHYR_STRING_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Function zephyr_string() called without a return variable") + endif() + + list(GET ZEPHYR_STRING_UNPARSED_ARGUMENTS 0 return_arg) + list(REMOVE_AT ZEPHYR_STRING_UNPARSED_ARGUMENTS 0) + + list(JOIN ZEPHYR_STRING_UNPARSED_ARGUMENTS "" work_string) + + if(ZEPHYR_STRING_SANITIZE) + string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" work_string ${work_string}) + endif() + + if(ZEPHYR_STRING_TOUPPER) + string(TOUPPER ${work_string} work_string) + endif() + + set(${return_arg} ${work_string} PARENT_SCOPE) +endfunction() + +# Usage: +# zephyr_list(TRANSFORM +# [OUTPUT_VARIABLE : This currently must be NORMALIZE_PATHS. This action +# converts the argument list to a ;-list with +# CMake path names, after passing its contents through +# a configure_file() transformation. The input list +# may be whitespace- or semicolon-separated. +# +# OUTPUT_VARIABLE: the result is normally stored in place, but +# an alternative variable to store the result +# can be provided with this. +function(zephyr_list transform list_var action) + # Parse arguments. + if(NOT "${transform}" STREQUAL "TRANSFORM") + message(FATAL_ERROR "the first argument must be TRANSFORM") + endif() + if(NOT "${action}" STREQUAL "NORMALIZE_PATHS") + message(FATAL_ERROR "the third argument must be NORMALIZE_PATHS") + endif() + set(single_args OUTPUT_VARIABLE) + cmake_parse_arguments(ZEPHYR_LIST "" "${single_args}" "" ${ARGN}) + if(DEFINED ZEPHYR_LIST_OUTPUT_VARIABLE) + set(out_var ${ZEPHYR_LIST_OUTPUT_VARIABLE}) + else() + set(out_var ${list_var}) + endif() + set(input ${${list_var}}) + + # Perform the transformation. + set(ret) + string(CONFIGURE "${input}" input_expanded) + string(REPLACE " " ";" input_raw_list "${input_expanded}") + foreach(file ${input_raw_list}) + file(TO_CMAKE_PATH "${file}" cmake_path_file) + list(APPEND ret ${cmake_path_file}) + endforeach() + + set(${out_var} ${ret} PARENT_SCOPE) +endfunction() + +# Usage: +# zephyr_var_name( ) +# +# Internal function for construction of scoped variable name expansion string. +# Examples: +# reading a current scope FOO variable is identical to expand ${FOO}. +# reading a cache scope FOO variable is identical to expand $CACHE{FOO}. +# +# this functions will return the var name in out var for the scope if it is +# defined, else it will set the outvar to undefined. +function(zephyr_var_name variable scope out) + if(scope STREQUAL "ENV" OR scope STREQUAL "CACHE") + if(DEFINED ${scope}{${variable}}) + set(${out} "$${scope}{${variable}}" PARENT_SCOPE) + else() + set(${out} PARENT_SCOPE) + endif() + else() + if(DEFINED ${scope}_${variable}) + set(${out} "${${scope}_${variable}}" PARENT_SCOPE) + else() + set(${out} PARENT_SCOPE) + endif() + endif() +endfunction() + +# Usage: +# zephyr_get( [MERGE [REVERSE]] [SYSBUILD [LOCAL|GLOBAL]] [VAR ...]) +# +# Return the value of as local scoped variable of same name. If MERGE +# is supplied, will return a list of found items. If REVERSE is supplied +# together with MERGE, the order of the list will be reversed before being +# returned. Reverse will happen before the list is returned and hence it will +# not change the order of precedence in which the list itself is constructed. +# +# VAR can be used either to store the result in a variable with a different +# name, or to look for values from multiple variables. +# zephyr_get(FOO VAR FOO_A FOO_B) +# zephyr_get(FOO MERGE VAR FOO_A FOO_B) +# +# zephyr_get() is a common function to provide a uniform way of supporting +# build settings that can be set from sysbuild, CMakeLists.txt, CMake cache, or +# in environment. +# +# The order of precedence for variables defined in multiple scopes: +# - Sysbuild defined when sysbuild is used. +# Sysbuild variables can be defined as global or local to specific image. +# Examples: +# - BOARD is considered a global sysbuild cache variable +# - blinky_BOARD is considered a local sysbuild cache variable only for the +# blinky image. +# If no sysbuild scope is specified, GLOBAL is assumed. +# If using MERGE then SYSBUILD GLOBAL will get both the local and global +# sysbuild scope variables (in that order, if both exist). +# - CMake cache, set by `-D=` or `set( CACHE ...) +# - Environment +# - Locally in CMakeLists.txt before 'find_package(Zephyr)' +# +# For example, if ZEPHYR_TOOLCHAIN_VARIANT is set in environment but locally +# overridden by setting ZEPHYR_TOOLCHAIN_VARIANT directly in the CMake cache +# using `-DZEPHYR_TOOLCHAIN_VARIANT=`, then the value from the cache is +# returned. +function(zephyr_get variable) + cmake_parse_arguments(GET_VAR "MERGE;REVERSE" "SYSBUILD" "VAR" ${ARGN}) + + if(DEFINED GET_VAR_SYSBUILD) + if(NOT ("${GET_VAR_SYSBUILD}" STREQUAL "GLOBAL" OR + "${GET_VAR_SYSBUILD}" STREQUAL "LOCAL") + ) + message(FATAL_ERROR "zephyr_get(... SYSBUILD) requires GLOBAL or LOCAL.") + endif() + else() + set(GET_VAR_SYSBUILD "GLOBAL") + endif() + + if(GET_VAR_REVERSE AND NOT GET_VAR_MERGE) + message(FATAL_ERROR "zephyr_get(... REVERSE) missing a required argument: MERGE") + endif() + + if(NOT DEFINED GET_VAR_VAR) + set(GET_VAR_VAR ${variable}) + endif() + + # Keep current scope variables in internal variables. + # This is needed to properly handle cases where we want to check value against + # environment value or when appending with the MERGE operation. + foreach(var ${GET_VAR_VAR}) + set(current_${var} ${${var}}) + set(${var}) + + if(SYSBUILD) + get_property(sysbuild_name TARGET sysbuild_cache PROPERTY SYSBUILD_NAME) + get_property(sysbuild_main_app TARGET sysbuild_cache PROPERTY SYSBUILD_MAIN_APP) + get_property(sysbuild_local_${var} TARGET sysbuild_cache PROPERTY ${sysbuild_name}_${var}) + get_property(sysbuild_global_${var} TARGET sysbuild_cache PROPERTY ${var}) + if(NOT DEFINED sysbuild_local_${var} AND sysbuild_main_app) + set(sysbuild_local_${var} ${sysbuild_global_${var}}) + endif() + if(NOT "${GET_VAR_SYSBUILD}" STREQUAL "GLOBAL") + set(sysbuild_global_${var}) + endif() + else() + set(sysbuild_local_${var}) + set(sysbuild_global_${var}) + endif() + + if(TARGET snippets_scope) + get_property(snippets_${var} TARGET snippets_scope PROPERTY ${var}) + endif() + endforeach() + + set(${variable} "") + set(scopes "sysbuild_local;sysbuild_global;CACHE;snippets;ENV;current") + if(GET_VAR_REVERSE) + list(REVERSE scopes) + endif() + foreach(scope IN LISTS scopes) + foreach(var ${GET_VAR_VAR}) + zephyr_var_name("${var}" "${scope}" expansion_var) + if(DEFINED expansion_var) + string(CONFIGURE "${expansion_var}" scope_value) + if(GET_VAR_MERGE) + list(APPEND ${variable} ${scope_value}) + else() + set(${variable} ${scope_value} PARENT_SCOPE) + + if("${scope}" STREQUAL "ENV") + # Set the environment variable in CMake cache, so that a build + # invocation triggering a CMake rerun doesn't rely on the + # environment variable still being available / have identical value. + set(${var} $ENV{${var}} CACHE INTERNAL "Cached environment variable ${var}") + endif() + + if("${scope}" STREQUAL "ENV" AND DEFINED current_${var} + AND NOT "${current_${var}}" STREQUAL "$ENV{${var}}" + ) + # Variable exists as current scoped variable, defined in a CMakeLists.txt + # file, however it is also set in environment. + # This might be a surprise to the user, so warn about it. + message(WARNING "environment variable '${var}' is hiding local " + "variable of same name.\n" + "Environment value (in use): $ENV{${var}}\n" + "Current scope value (hidden): ${current_${var}}\n" + ) + endif() + + return() + endif() + endif() + endforeach() + endforeach() + + if(GET_VAR_MERGE) + if(GET_VAR_REVERSE) + list(REVERSE ${variable}) + list(REMOVE_DUPLICATES ${variable}) + list(REVERSE ${variable}) + else() + list(REMOVE_DUPLICATES ${variable}) + endif() + set(${variable} ${${variable}} PARENT_SCOPE) + endif() +endfunction(zephyr_get variable) + +# Usage: +# zephyr_create_scope() +# +# Create a new scope for creation of scoped variables. +# +# : Name of new scope. +# +function(zephyr_create_scope scope) + if(TARGET ${scope}_scope) + message(FATAL_ERROR "zephyr_create_scope(${scope}) already exists.") + endif() + + add_custom_target(${scope}_scope) +endfunction() + +# Usage: +# zephyr_set( SCOPE [APPEND]) +# +# Zephyr extension of CMake set which allows a variable to be set in a specific +# scope. The scope is used on later zephyr_get() invocation for precedence +# handling when a variable it set in multiple scopes. +# +# : Name of variable +# : Value of variable, multiple values will create a list. +# The SCOPE argument identifies the end of value list. +# SCOPE : Name of scope for the variable +# APPEND : Append values to the already existing variable in +# +function(zephyr_set variable) + cmake_parse_arguments(SET_VAR "APPEND" "SCOPE" "" ${ARGN}) + + zephyr_check_arguments_required_all(zephyr_set SET_VAR SCOPE) + + if(NOT TARGET ${SET_VAR_SCOPE}_scope) + message(FATAL_ERROR "zephyr_set(... SCOPE ${SET_VAR_SCOPE}) doesn't exists.") + endif() + + if(SET_VAR_APPEND) + set(property_args APPEND) + endif() + + set_property(TARGET ${SET_VAR_SCOPE}_scope ${property_args} + PROPERTY ${variable} ${SET_VAR_UNPARSED_ARGUMENTS} + ) +endfunction() + +# Usage: +# zephyr_check_cache( [REQUIRED]) +# +# Check the current CMake cache for and warn the user if the value +# is being modified. +# +# This can be used to ensure the user does not accidentally try to change +# Zephyr build variables, such as: +# - BOARD +# - SHIELD +# +# variable: Name of to check and set, for example BOARD. +# REQUIRED: Optional flag. If specified, then an unset will be +# treated as an error. +# WATCH: Optional flag. If specified, watch the variable and print a warning if +# the variable is later being changed. +# +# Details: +# can be set by 3 sources. +# - Using CMake argument, -D +# - Using an environment variable +# - In the project CMakeLists.txt before `find_package(Zephyr)`. +# +# CLI has the highest precedence, then comes environment variables, +# and then finally CMakeLists.txt. +# +# The value defined on the first CMake invocation will be stored in the CMake +# cache as CACHED_. This allows the Zephyr build system to detect +# when a user reconfigures a sticky variable. +# +# A user can ignore all the precedence rules if the same source is always used +# E.g. always specifies -D= on the command line, +# always has an environment set, or always has a set( foo) +# line in his CMakeLists.txt and avoids mixing sources. +# +# The selected can be accessed through the variable '' in +# following Zephyr CMake code. +# +# If the user tries to change to a new value, then a warning will +# be printed, and the previously cached value (CACHED_) will be +# used, as it has precedence. +# +# Together with the warning, user is informed that in order to change +# the build directory must be cleaned. +# +function(zephyr_check_cache variable) + cmake_parse_arguments(CACHE_VAR "REQUIRED;WATCH" "" "" ${ARGN}) + string(TOLOWER ${variable} variable_text) + string(REPLACE "_" " " variable_text ${variable_text}) + + get_property(cached_value CACHE ${variable} PROPERTY VALUE) + + # If the build has already been configured in an earlier CMake invocation, + # then CACHED_${variable} is set. The CACHED_${variable} setting takes + # precedence over any user or CMakeLists.txt input. + # If we detect that user tries to change the setting, then print a warning + # that a pristine build is needed. + + # If user uses -D=, then cli_argument will hold the new + # value, otherwise cli_argument will hold the existing (old) value. + set(cli_argument ${cached_value}) + if(cli_argument STREQUAL CACHED_${variable}) + # The is no changes to the value. + unset(cli_argument) + endif() + + set(app_cmake_lists ${${variable}}) + if(cached_value STREQUAL ${variable}) + # The app build scripts did not set a default, The variable we are + # reading is the cached value from the CLI + unset(app_cmake_lists) + endif() + + if(DEFINED CACHED_${variable}) + # Warn the user if it looks like he is trying to change the variable + # without cleaning first + if(cli_argument) + if(NOT ((CACHED_${variable} STREQUAL cli_argument) OR (${variable}_DEPRECATED STREQUAL cli_argument))) + message(WARNING "The build directory must be cleaned pristinely when " + "changing ${variable_text},\n" + "Current value=\"${CACHED_${variable}}\", " + "Ignored value=\"${cli_argument}\"") + endif() + endif() + + if(CACHED_${variable}) + set(${variable} ${CACHED_${variable}} PARENT_SCOPE) + set(${variable} ${CACHED_${variable}}) + # This resets the user provided value with previous (working) value. + set(${variable} ${CACHED_${variable}} CACHE STRING "Selected ${variable_text}" FORCE) + else() + unset(${variable} PARENT_SCOPE) + unset(${variable} CACHE) + endif() + else() + zephyr_get(${variable}) + endif() + + if(${CACHE_VAR_REQUIRED} AND NOT DEFINED ${variable}) + message(FATAL_ERROR "${variable} is not being defined on the CMake command-line," + " in the environment or by the app." + ) + endif() + + if(DEFINED ${variable}) + # Store the specified variable in parent scope and the cache + set(${variable} ${${variable}} PARENT_SCOPE) + set(${variable} ${${variable}} CACHE STRING "Selected ${variable_text}") + endif() + set(CACHED_${variable} ${${variable}} CACHE STRING "Selected ${variable_text}") + + if(CACHE_VAR_WATCH) + # The variable is now set to its final value. + zephyr_boilerplate_watch(${variable}) + endif() +endfunction(zephyr_check_cache variable) + + +# Usage: +# zephyr_boilerplate_watch(SOME_BOILERPLATE_VAR) +# +# Inform the build system that SOME_BOILERPLATE_VAR, a variable +# handled in the Zephyr package's boilerplate code, is now fixed and +# should no longer be changed. +# +# This function uses variable_watch() to print a noisy warning +# if the variable is set after it returns. +function(zephyr_boilerplate_watch variable) + variable_watch(${variable} zephyr_variable_set_too_late) +endfunction() + +function(zephyr_variable_set_too_late variable access value current_list_file) + if (access STREQUAL "MODIFIED_ACCESS") + message(WARNING +" + ********************************************************************** + * + * WARNING + * + * CMake variable ${variable} set to \"${value}\" in: + * ${current_list_file} + * + * This is too late to make changes! The change was ignored. + * + * Hint: ${variable} must be set before calling find_package(Zephyr ...). + * + ********************************************************************** +") + endif() +endfunction() + +# Usage: +# zephyr_get_targets( ) +# +# Get build targets for a given directory and sub-directories. +# +# This functions will traverse the build tree, starting from . +# It will read the `BUILDSYSTEM_TARGETS` for each directory in the build tree +# and return the build types matching the list. +# Example of types: OBJECT_LIBRARY, STATIC_LIBRARY, INTERFACE_LIBRARY, UTILITY. +# +# returns a list of targets in matching the required . +function(zephyr_get_targets directory types targets) + get_property(sub_directories DIRECTORY ${directory} PROPERTY SUBDIRECTORIES) + get_property(dir_targets DIRECTORY ${directory} PROPERTY BUILDSYSTEM_TARGETS) + foreach(dir_target ${dir_targets}) + get_property(target_type TARGET ${dir_target} PROPERTY TYPE) + if(${target_type} IN_LIST types) + list(APPEND ${targets} ${dir_target}) + endif() + endforeach() + + foreach(directory ${sub_directories}) + zephyr_get_targets(${directory} "${types}" ${targets}) + endforeach() + set(${targets} ${${targets}} PARENT_SCOPE) +endfunction() + +# Usage: +# test_sysbuild([REQUIRED]) +# +# Test that current sample is invoked through sysbuild. +# +# This function tests that current CMake configure was invoked through sysbuild. +# If CMake configure was not invoked through sysbuild, then a warning is printed +# to the user. The warning can be upgraded to an error by setting `REQUIRED` as +# argument the `test_sysbuild()`. +# +# This function allows samples that are multi-image samples by nature to ensure +# all samples are correctly built together. +function(test_sysbuild) + cmake_parse_arguments(TEST_SYSBUILD "REQUIRED" "" "" ${ARGN}) + + if(TEST_SYSBUILD_REQUIRED) + set(message_mode FATAL_ERROR) + else() + set(message_mode WARNING) + endif() + + if(NOT SYSBUILD) + message(${message_mode} + "Project '${PROJECT_NAME}' is designed for sysbuild.\n" + "For correct user-experiences, please build '${PROJECT_NAME}' " + "using sysbuild." + ) + endif() +endfunction() + +# Usage: +# target_byproducts(TARGET BYPRODUCTS [...]) +# +# Specify additional BYPRODUCTS that this target produces. +# +# This function allows the build system to specify additional byproducts to +# target created with `add_executable()`. When linking an executable the linker +# may produce additional files, like map files. Those files are not known to the +# build system. This function makes it possible to describe such additional +# byproducts in an easy manner. +function(target_byproducts) + cmake_parse_arguments(TB "" "TARGET" "BYPRODUCTS" ${ARGN}) + + if(NOT DEFINED TB_TARGET) + message(FATAL_ERROR "target_byproducts() missing parameter: TARGET ") + endif() + + add_custom_command(TARGET ${TB_TARGET} + POST_BUILD COMMAND ${CMAKE_COMMAND} -E true + BYPRODUCTS ${TB_BYPRODUCTS} + COMMENT "Logical command for additional byproducts on target: ${TB_TARGET}" + ) +endfunction() + +# Usage: +# topological_sort(TARGETS [ ...] +# PROPERTY_NAME +# RESULT ) +# +# This function performs topological sorting of CMake targets using a specific +# , which dictates target dependencies. A fatal error occurs if the +# provided dependencies cannot be met, e.g., if they contain cycles. +# +# TARGETS: List of target names. +# PROPERTY_NAME: Name of the target property to be used when sorting. For every +# target listed in TARGETS, this property must contain a list +# (possibly empty) of other targets, which this target depends on +# for a particular purpose. The property must not contain any +# target which is not also found in TARGETS. +# RESULT: Output variable, where the topologically sorted list of target +# names will be returned. +# +function(topological_sort) + cmake_parse_arguments(TS "" "RESULT;PROPERTY_NAME" "TARGETS" ${ARGN}) + + set(dep_targets) + set(start_targets) + set(sorted_targets) + + foreach(target ${TS_TARGETS}) + get_target_property(${target}_dependencies ${target} ${TS_PROPERTY_NAME}) + + if(${target}_dependencies) + list(APPEND dep_targets ${target}) + else() + list(APPEND start_targets ${target}) + endif() + endforeach() + + while(TRUE) + list(POP_FRONT start_targets node) + list(APPEND sorted_targets ${node}) + set(to_remove) + foreach(target ${dep_targets}) + if("${node}" IN_LIST ${target}_dependencies) + list(REMOVE_ITEM ${target}_dependencies ${node}) + if(NOT ${target}_dependencies) + list(APPEND start_targets ${target}) + list(APPEND to_remove ${target}) + endif() + endif() + endforeach() + + foreach(target ${to_remove}) + list(REMOVE_ITEM dep_targets ${target}) + endforeach() + if(NOT start_targets) + break() + endif() + endwhile() + + if(dep_targets) + foreach(target ${dep_targets}) + get_target_property(deps ${target} ${TS_PROPERTY_NAME}) + list(JOIN deps " " deps) + list(APPEND dep_string "${target} depends on: ${deps}") + endforeach() + list(JOIN dep_string "\n" dep_string) + message(FATAL_ERROR "Unmet or cyclic dependencies:\n${dep_string}") + endif() + + set(${TS_RESULT} "${sorted_targets}" PARENT_SCOPE) +endfunction() + +######################################################## +# 4. Devicetree extensions +######################################################## +# 4.1. dt_* +# +# The following methods are for retrieving devicetree information in CMake. +# +# Notes: +# +# - In CMake, we refer to the nodes using the node's path, therefore +# there is no dt_path(...) function for obtaining a node identifier +# like there is in the C devicetree.h API. +# +# - As another difference from the C API, you can generally use an +# alias at the beginning of a path interchangeably with the full +# path to the aliased node in these functions. The usage comments +# will make this clear in each case. + +# Usage: +# dt_nodelabel( NODELABEL