From c6a0d9118ec993f122c214199b6ea9bbee74967a Mon Sep 17 00:00:00 2001 From: Jan Beran Date: Thu, 15 May 2025 13:55:55 +0200 Subject: [PATCH] change: Support misspelled Kconfig[.projbuild] file names If the name is misspelled, CMake prints out a warning. Original issue: https://github.com/espressif/esp-idf-kconfig/issues/14 --- tools/cmake/kconfig.cmake | 33 +++++++- .../build_test_app/main/KConfig.projbuild | 4 + tools/test_build_system/test_build.py | 75 ++++++++++++++----- 3 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 tools/test_build_system/build_test_app/main/KConfig.projbuild diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index db29e9cef4..6197b5ca2a 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -15,12 +15,37 @@ endfunction() # function(__kconfig_component_init component_target) __component_get_property(component_dir ${component_target} COMPONENT_DIR) - file(GLOB kconfig "${component_dir}/Kconfig") + file(GLOB all_files "${component_dir}/*") + + set(kconfig "") + set(kconfig_projbuild "") + + foreach(_file IN LISTS all_files) + get_filename_component(_fname ${_file} NAME) + string(TOLOWER "${_fname}" _fname_lowercase) + if(_fname_lowercase STREQUAL "kconfig") + list(APPEND kconfig "${_file}") + if(NOT _fname STREQUAL "Kconfig") + message(WARNING + "${_fname} file should be named 'Kconfig' (uppercase K, the rest lowercase)." + " Full path to the file: ${_file}") + endif() + elseif(_fname_lowercase STREQUAL "kconfig.projbuild") + list(APPEND kconfig_projbuild "${_file}") + if(NOT _fname STREQUAL "Kconfig.projbuild") + message(WARNING + "${_fname} file should be named 'Kconfig.projbuild' (uppercase K, the rest lowercase)." + " Full path to the file: ${_file}") + endif() + endif() + endforeach() + list(SORT kconfig) __component_set_property(${component_target} KCONFIG "${kconfig}") - file(GLOB kconfig "${component_dir}/Kconfig.projbuild") - list(SORT kconfig) - __component_set_property(${component_target} KCONFIG_PROJBUILD "${kconfig}") + + list(SORT kconfig_projbuild) + __component_set_property(${component_target} KCONFIG_PROJBUILD "${kconfig_projbuild}") + file(GLOB sdkconfig_rename "${component_dir}/sdkconfig.rename") file(GLOB sdkconfig_rename_target "${component_dir}/sdkconfig.rename.${IDF_TARGET}") diff --git a/tools/test_build_system/build_test_app/main/KConfig.projbuild b/tools/test_build_system/build_test_app/main/KConfig.projbuild new file mode 100644 index 0000000000..4c7e3fb244 --- /dev/null +++ b/tools/test_build_system/build_test_app/main/KConfig.projbuild @@ -0,0 +1,4 @@ +# Misspelled Kconfig file checks whether it is picked up by the build system +config FROM_MISSPELLED_KCONFIG + bool "From misspelled Kconfig" + default y diff --git a/tools/test_build_system/test_build.py b/tools/test_build_system/test_build.py index bcc2d73527..13a8f32faf 100644 --- a/tools/test_build_system/test_build.py +++ b/tools/test_build_system/test_build.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import logging import os @@ -12,12 +12,12 @@ from typing import Union import pytest from test_build_system_helpers import APP_BINS -from test_build_system_helpers import append_to_file from test_build_system_helpers import BOOTLOADER_BINS +from test_build_system_helpers import PARTITION_BIN +from test_build_system_helpers import IdfPyFunc +from test_build_system_helpers import append_to_file from test_build_system_helpers import file_contains from test_build_system_helpers import get_idf_build_env -from test_build_system_helpers import IdfPyFunc -from test_build_system_helpers import PARTITION_BIN from test_build_system_helpers import replace_in_file from test_build_system_helpers import run_cmake_and_build @@ -35,7 +35,9 @@ def test_build_alternative_directories(idf_py: IdfPyFunc, func_work_dir: Path, t assert os.listdir(alt_build_dir) != [], 'No files found in new build directory!' default_build_dir = test_app_copy / 'build' if default_build_dir.exists(): - assert os.listdir(default_build_dir) == [], f'Some files were incorrectly put into the default build directory: {default_build_dir}' + assert os.listdir(default_build_dir) == [], ( + f'Some files were incorrectly put into the default build directory: {default_build_dir}' + ) except Exception: raise else: @@ -146,10 +148,17 @@ def test_build_with_sdkconfig_build_abspath(idf_py: IdfPyFunc, test_app_copy: Pa def test_build_fail_on_build_time(idf_py: IdfPyFunc, test_app_copy: Path) -> None: logging.info('Fail on build time works') - append_to_file(test_app_copy / 'CMakeLists.txt', '\n'.join(['', - 'if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/hello.txt")', - 'fail_at_build_time(test_file "hello.txt does not exists")', - 'endif()'])) + append_to_file( + test_app_copy / 'CMakeLists.txt', + '\n'.join( + [ + '', + 'if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/hello.txt")', + 'fail_at_build_time(test_file "hello.txt does not exists")', + 'endif()', + ] + ), + ) ret = idf_py('build', check=False) assert ret.returncode != 0, 'Build should fail if requirements are not satisfied' (test_app_copy / 'hello.txt').touch() @@ -160,10 +169,14 @@ def test_build_fail_on_build_time(idf_py: IdfPyFunc, test_app_copy: Path) -> Non def test_build_dfu(idf_py: IdfPyFunc) -> None: logging.info('DFU build works') ret = idf_py('dfu', check=False) - assert 'command "dfu" is not known to idf.py and is not a Ninja target' in ret.stderr, 'DFU build should fail for default chip target' + assert 'command "dfu" is not known to idf.py and is not a Ninja target' in ret.stderr, ( + 'DFU build should fail for default chip target' + ) idf_py('set-target', 'esp32s2') ret = idf_py('dfu') - assert 'build/dfu.bin" has been written. You may proceed with DFU flashing.' in ret.stdout, 'DFU build should succeed for esp32s2' + assert 'build/dfu.bin" has been written. You may proceed with DFU flashing.' in ret.stdout, ( + 'DFU build should succeed for esp32s2' + ) assert_built(BOOTLOADER_BINS + APP_BINS + PARTITION_BIN + ['build/dfu.bin']) @@ -174,23 +187,35 @@ def test_build_uf2(idf_py: IdfPyFunc) -> None: assert 'build/uf2.bin, ready to be flashed with any ESP USB Bridge' in ret.stdout, 'UF2 build should work for esp32' assert_built(BOOTLOADER_BINS + APP_BINS + PARTITION_BIN + ['build/uf2.bin']) ret = idf_py('uf2-app') - assert 'build/uf2-app.bin, ready to be flashed with any ESP USB Bridge' in ret.stdout, 'UF2 build should work for application binary' + assert 'build/uf2-app.bin, ready to be flashed with any ESP USB Bridge' in ret.stdout, ( + 'UF2 build should work for application binary' + ) assert_built(['build/uf2-app.bin']) idf_py('set-target', 'esp32s2') ret = idf_py('uf2') - assert 'build/uf2.bin, ready to be flashed with any ESP USB Bridge' in ret.stdout, 'UF2 build should work for esp32s2' + assert 'build/uf2.bin, ready to be flashed with any ESP USB Bridge' in ret.stdout, ( + 'UF2 build should work for esp32s2' + ) assert_built(BOOTLOADER_BINS + APP_BINS + PARTITION_BIN + ['build/uf2.bin']) def test_build_loadable_elf(idf_py: IdfPyFunc, test_app_copy: Path) -> None: logging.info('Loadable ELF build works') - (test_app_copy / 'sdkconfig').write_text('\n'.join(['CONFIG_APP_BUILD_TYPE_RAM=y', - 'CONFIG_VFS_SUPPORT_TERMIOS=n', - 'CONFIG_NEWLIB_NANO_FORMAT=y', - 'CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y', - 'CONFIG_ESP_ERR_TO_NAME_LOOKUP=n'])) + (test_app_copy / 'sdkconfig').write_text( + '\n'.join( + [ + 'CONFIG_APP_BUILD_TYPE_RAM=y', + 'CONFIG_VFS_SUPPORT_TERMIOS=n', + 'CONFIG_NEWLIB_NANO_FORMAT=y', + 'CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y', + 'CONFIG_ESP_ERR_TO_NAME_LOOKUP=n', + ] + ) + ) idf_py('reconfigure') - assert (test_app_copy / 'build' / 'flasher_args.json').exists(), 'flasher_args.json should be generated in a loadable ELF build' + assert (test_app_copy / 'build' / 'flasher_args.json').exists(), ( + 'flasher_args.json should be generated in a loadable ELF build' + ) idf_py('build') @@ -221,3 +246,15 @@ def test_build_cmake_executable_suffix(idf_py: IdfPyFunc, test_app_copy: Path) - append_to_file((test_app_copy / 'CMakeLists.txt'), 'set(CMAKE_EXECUTABLE_SUFFIX_CXX ".ext")') ret = idf_py('build') assert 'Project build complete' in ret.stdout, 'Build with CMAKE_EXECUTABLE_SUFFIX set failed' + + +def test_build_with_misspelled_kconfig(idf_py: IdfPyFunc, test_app_copy: Path) -> None: + logging.info('idf.py can build with misspelled Kconfig file') + ret = idf_py('build') + assert " file should be named 'Kconfig.projbuild'" in ret.stderr, 'Misspelled Kconfig file should be detected' + assert_built(BOOTLOADER_BINS + APP_BINS + PARTITION_BIN) + with open(test_app_copy / 'sdkconfig', 'r') as f: + sdkconfig = f.read() + assert 'CONFIG_FROM_MISSPELLED_KCONFIG=y' in sdkconfig, ( + 'There should be a config from the misspelled Kconfig file in sdkconfig' + )