diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ed7c18733..bc95d53ee0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -454,7 +454,7 @@ foreach(module_name ${ZEPHYR_MODULE_NAMES}) # this binary_dir is created but stays empty. Object files land in # the main binary dir instead. # https://cmake.org/pipermail/cmake/2019-June/069547.html - string(TOUPPER ${module_name} MODULE_NAME_UPPER) + zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) if(NOT ${ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR} STREQUAL "") set(ZEPHYR_CURRENT_MODULE_DIR ${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR}) set(ZEPHYR_CURRENT_CMAKE_DIR ${ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR}) diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index c70eac0dc6..47e100f50a 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -1960,6 +1960,47 @@ Relative paths are only allowed with `-D${ARGV1}=`") 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_check_cache( [REQUIRED]) # diff --git a/cmake/kconfig.cmake b/cmake/kconfig.cmake index 1442e356d0..5cffa64c41 100644 --- a/cmake/kconfig.cmake +++ b/cmake/kconfig.cmake @@ -69,7 +69,7 @@ string(REPLACE ";" "?" DTS_ROOT_BINDINGS "${DTS_ROOT_BINDINGS}") # This allows Kconfig files to refer relative from a modules root as: # source "$(ZEPHYR_FOO_MODULE_DIR)/Kconfig" foreach(module_name ${ZEPHYR_MODULE_NAMES}) - string(TOUPPER ${module_name} MODULE_NAME_UPPER) + zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) list(APPEND ZEPHYR_KCONFIG_MODULES_DIR "ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR=${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR}" diff --git a/cmake/zephyr_module.cmake b/cmake/zephyr_module.cmake index 43230a1229..8c6735586e 100644 --- a/cmake/zephyr_module.cmake +++ b/cmake/zephyr_module.cmake @@ -104,7 +104,7 @@ if(WEST OR ZEPHYR_MODULES) list(APPEND ZEPHYR_MODULE_NAMES ${module_name}) - string(TOUPPER ${module_name} MODULE_NAME_UPPER) + zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) if(NOT ${MODULE_NAME_UPPER} STREQUAL CURRENT) set(ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR ${module_path}) set(ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR ${cmake_path}) diff --git a/doc/guides/modules.rst b/doc/guides/modules.rst index 7a8873756c..3ace14825a 100644 --- a/doc/guides/modules.rst +++ b/doc/guides/modules.rst @@ -421,6 +421,13 @@ CMake variable ``ZEPHYR__MODULE_DIR`` and the variable ``ZEPHYR__CMAKE_DIR`` holds the location of the directory containing the module's :file:`CMakeLists.txt` file. +.. note:: + When used for CMake and Kconfig variables, all letters in module names are + converted to uppercase and all non-alphanumeric characters are converted + to underscores (_). + As example, the module ``foo-bar`` must be referred to as + ``ZEPHYR_FOO_BAR_MODULE_DIR`` in CMake and Kconfig. + Here is an example for the Zephyr module ``foo``: .. code-block:: yaml diff --git a/modules/modules.cmake b/modules/modules.cmake index 8f849c2cc7..0242b9d5b1 100644 --- a/modules/modules.cmake +++ b/modules/modules.cmake @@ -5,7 +5,8 @@ file(GLOB cmake_modules "${CMAKE_CURRENT_LIST_DIR}/*/CMakeLists.txt") foreach(module ${cmake_modules}) get_filename_component(module_dir ${module} DIRECTORY) get_filename_component(module_name ${module_dir} NAME) - string(TOUPPER ${module_name} MODULE_NAME_UPPER) + zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) + set(ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR ${module_dir}) endforeach() @@ -14,6 +15,7 @@ file(GLOB kconfig_modules "${CMAKE_CURRENT_LIST_DIR}/*/Kconfig") foreach(module ${kconfig_modules}) get_filename_component(module_dir ${module} DIRECTORY) get_filename_component(module_name ${module_dir} NAME) - string(TOUPPER ${module_name} MODULE_NAME_UPPER) + zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) + set(ZEPHYR_${MODULE_NAME_UPPER}_KCONFIG ${module_dir}/Kconfig) endforeach() diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 76906bcb02..85c438e6a5 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -262,7 +262,7 @@ class KconfigCheck(ComplianceTest): with open(modules_file, 'w') as fp_module_file: for module in modules: fp_module_file.write("ZEPHYR_{}_KCONFIG = {}\n".format( - module.upper(), + re.sub('[^a-zA-Z0-9]', '_', module).upper(), modules_dir + '/' + module + '/Kconfig' )) fp_module_file.write(content) diff --git a/scripts/zephyr_module.py b/scripts/zephyr_module.py index 8725095ae3..18dedaf852 100755 --- a/scripts/zephyr_module.py +++ b/scripts/zephyr_module.py @@ -19,6 +19,7 @@ maintained in modules in addition to what is available in the main Zephyr tree. import argparse import os +import re import sys import yaml import pykwalify.core @@ -128,11 +129,13 @@ def process_module(module): .format(module_yml.as_posix(), e)) meta['name'] = meta.get('name', module_path.name) + meta['name-sanitized'] = re.sub('[^a-zA-Z0-9]', '_', meta['name']) return meta if Path(module_path.joinpath('zephyr/CMakeLists.txt')).is_file() and \ Path(module_path.joinpath('zephyr/Kconfig')).is_file(): return {'name': module_path.name, + 'name-sanitized': re.sub('[^a-zA-Z0-9]', '_', module_path.name), 'build': {'cmake': 'zephyr', 'kconfig': 'zephyr/Kconfig'}} return None @@ -148,7 +151,7 @@ def process_cmake(module, meta): return('\"{}\":\"{}\":\"{}\"\n' .format(meta['name'], module_path.as_posix(), - "${ZEPHYR_" + meta['name'].upper() + "_CMAKE_DIR}")) + "${ZEPHYR_" + meta['name-sanitized'].upper() + "_CMAKE_DIR}")) cmake_setting = section.get('cmake', None) if not validate_setting(cmake_setting, module, 'CMakeLists.txt'): @@ -185,11 +188,14 @@ def process_settings(module, meta): return out_text -def kconfig_snippet(name, path, kconfig_file=None): +def kconfig_snippet(meta, path, kconfig_file=None): + name = meta['name'] + name_sanitized = meta['name-sanitized'] + snippet = (f'menu "{name} ({path})"', f'osource "{kconfig_file.resolve().as_posix()}"' if kconfig_file - else f'osource "$(ZEPHYR_{name.upper()}_KCONFIG)"', - f'config ZEPHYR_{name.upper()}_MODULE', + else f'osource "$(ZEPHYR_{name_sanitized.upper()}_KCONFIG)"', + f'config ZEPHYR_{name_sanitized.upper()}_MODULE', ' bool', ' default y', 'endmenu\n') @@ -202,7 +208,7 @@ def process_kconfig(module, meta): module_yml = module_path.joinpath('zephyr/module.yml') kconfig_extern = section.get('kconfig-ext', False) if kconfig_extern: - return kconfig_snippet(meta['name'], module_path) + return kconfig_snippet(meta, module_path) kconfig_setting = section.get('kconfig', None) if not validate_setting(kconfig_setting, module): @@ -212,7 +218,7 @@ def process_kconfig(module, meta): kconfig_file = os.path.join(module, kconfig_setting or 'zephyr/Kconfig') if os.path.isfile(kconfig_file): - return kconfig_snippet(meta['name'], module_path, Path(kconfig_file)) + return kconfig_snippet(meta, module_path, Path(kconfig_file)) else: return ""