1# SPDX-License-Identifier: Apache-2.0 2 3include_guard(GLOBAL) 4 5include(extensions) 6include(python) 7 8# This cmake file provides functionality to import CMakeLists.txt and Kconfig 9# files for Zephyr modules into Zephyr build system. 10# 11# CMakeLists.txt and Kconfig files can reside directly in the Zephyr module or 12# in a MODULE_EXT_ROOT. 13# The `<module>/zephyr/module.yml` file specifies whether the build files are 14# located in the Zephyr module or in a MODULE_EXT_ROOT. 15# 16# A list of Zephyr modules can be provided to the build system using: 17# -DZEPHYR_MODULES=<module-path>[;<additional-module(s)-path>] 18# 19# It looks for: <module>/zephyr/module.yml or 20# <module>/zephyr/CMakeLists.txt 21# to load the Zephyr module into Zephyr build system. 22# If west is installed, it uses west's APIs to obtain a list of projects to 23# search for zephyr/module.yml from the current workspace's manifest. 24# 25# If the module.yml file specifies that build files are located in a 26# MODULE_EXT_ROOT then the variables: 27# - `ZEPHYR_<MODULE_NAME>_CMAKE_DIR` is used for inclusion of the CMakeLists.txt 28# - `ZEPHYR_<MODULE_NAME>_KCONFIG` is used for inclusion of the Kconfig 29# files into the build system. 30 31# Settings used by Zephyr module but where systems may define an alternative value. 32set_ifndef(KCONFIG_BINARY_DIR ${CMAKE_BINARY_DIR}/Kconfig) 33 34zephyr_get(ZEPHYR_MODULES) 35if(ZEPHYR_MODULES) 36 set(ZEPHYR_MODULES_ARG "--modules" ${ZEPHYR_MODULES}) 37endif() 38 39zephyr_get(EXTRA_ZEPHYR_MODULES VAR EXTRA_ZEPHYR_MODULES ZEPHYR_EXTRA_MODULES) 40if(EXTRA_ZEPHYR_MODULES) 41 set(EXTRA_ZEPHYR_MODULES_ARG "--extra-modules" ${EXTRA_ZEPHYR_MODULES}) 42endif() 43 44file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}) 45set(kconfig_modules_file ${KCONFIG_BINARY_DIR}/Kconfig.modules) 46set(kconfig_sysbuild_file ${KCONFIG_BINARY_DIR}/Kconfig.sysbuild.modules) 47set(cmake_modules_file ${CMAKE_BINARY_DIR}/zephyr_modules.txt) 48set(cmake_sysbuild_file ${CMAKE_BINARY_DIR}/sysbuild_modules.txt) 49set(zephyr_settings_file ${CMAKE_BINARY_DIR}/zephyr_settings.txt) 50 51if(WEST OR ZEPHYR_MODULES) 52 # Zephyr module uses west, so only call it if west is installed or 53 # ZEPHYR_MODULES was provided as argument to CMake. 54 execute_process( 55 COMMAND 56 ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/zephyr_module.py 57 --zephyr-base=${ZEPHYR_BASE} 58 ${ZEPHYR_MODULES_ARG} 59 ${EXTRA_ZEPHYR_MODULES_ARG} 60 --kconfig-out ${kconfig_modules_file} 61 --cmake-out ${cmake_modules_file} 62 --sysbuild-kconfig-out ${kconfig_sysbuild_file} 63 --sysbuild-cmake-out ${cmake_sysbuild_file} 64 --settings-out ${zephyr_settings_file} 65 WORKING_DIRECTORY ${ZEPHYR_BASE} 66 ERROR_VARIABLE 67 zephyr_module_error_text 68 RESULT_VARIABLE 69 zephyr_module_return 70 ) 71 72 if(${zephyr_module_return}) 73 message(FATAL_ERROR "${zephyr_module_error_text}") 74 endif() 75 76 if(EXISTS ${zephyr_settings_file}) 77 file(STRINGS ${zephyr_settings_file} zephyr_settings_txt ENCODING UTF-8 REGEX "^[^#]") 78 foreach(setting ${zephyr_settings_txt}) 79 # Match <key>:<value> for each line of file, each corresponding to 80 # a setting. The use of quotes is required due to CMake not supporting 81 # lazy regexes (it supports greedy only). 82 string(REGEX REPLACE "\"(.*)\":\".*\"" "\\1" key ${setting}) 83 string(REGEX REPLACE "\".*\":\"(.*)\"" "\\1" value ${setting}) 84 list(APPEND ${key} ${value}) 85 endforeach() 86 endif() 87 88 # Append ZEPHYR_BASE as a default ext root at lowest priority 89 list(APPEND MODULE_EXT_ROOT ${ZEPHYR_BASE}) 90 91 if(EXISTS ${cmake_modules_file}) 92 file(STRINGS ${cmake_modules_file} zephyr_modules_txt ENCODING UTF-8) 93 endif() 94 95 set(ZEPHYR_MODULE_NAMES) 96 foreach(module ${zephyr_modules_txt}) 97 # Match "<name>":"<path>" for each line of file, each corresponding to 98 # one module. The use of quotes is required due to CMake not supporting 99 # lazy regexes (it supports greedy only). 100 string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module}) 101 list(APPEND ZEPHYR_MODULE_NAMES ${module_name}) 102 endforeach() 103 104 if(EXISTS ${cmake_sysbuild_file}) 105 file(STRINGS ${cmake_sysbuild_file} sysbuild_modules_txt ENCODING UTF-8) 106 endif() 107 108 set(SYSBUILD_MODULE_NAMES) 109 foreach(module ${sysbuild_modules_txt}) 110 # Match "<name>":"<path>" for each line of file, each corresponding to 111 # one module. The use of quotes is required due to CMake not supporting 112 # lazy regexes (it supports greedy only). 113 string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module}) 114 list(APPEND SYSBUILD_MODULE_NAMES ${module_name}) 115 endforeach() 116 117 # MODULE_EXT_ROOT is process order which means Zephyr module roots processed 118 # later wins. therefore we reverse the list before processing. 119 list(REVERSE MODULE_EXT_ROOT) 120 foreach(root ${MODULE_EXT_ROOT}) 121 set(module_cmake_file_path modules/modules.cmake) 122 if(NOT EXISTS ${root}/${module_cmake_file_path}) 123 message(FATAL_ERROR "No `${module_cmake_file_path}` found in module root `${root}`.") 124 endif() 125 126 include(${root}/${module_cmake_file_path}) 127 endforeach() 128 129 foreach(module ${zephyr_modules_txt}) 130 # Match "<name>":"<path>" for each line of file, each corresponding to 131 # one Zephyr module. The use of quotes is required due to CMake not 132 # supporting lazy regexes (it supports greedy only). 133 string(CONFIGURE ${module} module) 134 string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module}) 135 string(REGEX REPLACE "\".*\":\"(.*)\":\".*\"" "\\1" module_path ${module}) 136 string(REGEX REPLACE "\".*\":\".*\":\"(.*)\"" "\\1" cmake_path ${module}) 137 138 zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) 139 if(NOT ${MODULE_NAME_UPPER} STREQUAL CURRENT) 140 set(ZEPHYR_${MODULE_NAME_UPPER}_MODULE_NAME ${module_name}) 141 set(ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR ${module_path}) 142 set(ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR ${cmake_path}) 143 else() 144 message(FATAL_ERROR "Found Zephyr module named: ${module_name}\n\ 145${MODULE_NAME_UPPER} is a restricted name for Zephyr modules as it is used for \ 146\${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR} CMake variable.") 147 endif() 148 endforeach() 149 150 foreach(module ${sysbuild_modules_txt}) 151 # Match "<name>":"<path>" for each line of file, each corresponding to 152 # one Zephyr module. The use of quotes is required due to CMake not 153 # supporting lazy regexes (it supports greedy only). 154 string(CONFIGURE ${module} module) 155 string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module}) 156 string(REGEX REPLACE "\".*\":\"(.*)\":\".*\"" "\\1" module_path ${module}) 157 string(REGEX REPLACE "\".*\":\".*\":\"(.*)\"" "\\1" cmake_path ${module}) 158 159 zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) 160 if(NOT ${MODULE_NAME_UPPER} STREQUAL CURRENT) 161 set(SYSBUILD_${MODULE_NAME_UPPER}_MODULE_DIR ${module_path}) 162 set(SYSBUILD_${MODULE_NAME_UPPER}_CMAKE_DIR ${cmake_path}) 163 else() 164 message(FATAL_ERROR "Found Zephyr module named: ${module_name}\n\ 165${MODULE_NAME_UPPER} is a restricted name for Zephyr modules as it is used for \ 166\${SYSBUILD_${MODULE_NAME_UPPER}_MODULE_DIR} CMake variable.") 167 endif() 168 endforeach() 169else() 170 171 file(WRITE ${kconfig_modules_file} 172 "# No west and no Zephyr modules\n" 173 ) 174 175 file(WRITE ${kconfig_sysbuild_file} 176 "# No west and no Zephyr modules\n" 177 ) 178 179endif() 180