diff --git a/Kconfig b/Kconfig index 392a77552b..1f36751668 100644 --- a/Kconfig +++ b/Kconfig @@ -66,6 +66,12 @@ mainmenu "Espressif IoT Development Framework Configuration" string default "$IDF_TARGET" + config IDF_INIT_VERSION + # This option records the IDF version when sdkconfig is generated the first time. + # It is not updated if environment variable $IDF_VERSION changes later + string + default "$IDF_INIT_VERSION" + config IDF_TARGET_LINUX bool default "y" if IDF_TARGET="linux" diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index aa8c4dcfac..f1f0ab20fb 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -54,6 +54,32 @@ function(__kconfig_bootloader_component_add component_dir) endfunction() +# +# Find the initial IDF version used to generate the config. +# This is needed to pass this variable back to confgen, so that the +# value of CONFIG_IDF_INIT_VERSION option stays the same. +# +function(__get_init_config_version config version_out) + set(${version_out} NOTFOUND PARENT_SCOPE) + + if(NOT EXISTS "${config}") + return() + endif() + + file(STRINGS "${config}" lines) + foreach(line ${lines}) + string(STRIP "${line}" line) + if(NOT "${line}" MATCHES "CONFIG_IDF_INIT_VERSION=\"([0-9]+\.[0-9]+\.[0-9]+)\"$") + continue() + endif() + + string(REGEX REPLACE "CONFIG_IDF_INIT_VERSION=\"([0-9]+\.[0-9]+\.[0-9]+)\"$" "\\1" version "${line}") + set(${version_out} ${version} PARENT_SCOPE) + return() + endforeach() +endfunction() + + # # Generate the config files and create config related targets and configure # dependencies. @@ -79,6 +105,12 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) endif() endforeach() + __get_init_config_version(${sdkconfig} idf_init_version) + if(NOT idf_init_version) + set(idf_init_version $ENV{IDF_VERSION}) + endif() + set(ENV{IDF_INIT_VERSION} ${idf_init_version}) + # Take into account bootloader components configuration files idf_build_get_property(bootloader_kconfigs BOOTLOADER_KCONFIGS) idf_build_get_property(bootloader_kconfigs_proj BOOTLOADER_KCONFIGS_PROJ) @@ -212,6 +244,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) --env "IDF_TARGET=${idf_target}" --env "IDF_TOOLCHAIN=${idf_toolchain}" --env "IDF_ENV_FPGA=${idf_env_fpga}" + --env "IDF_INIT_VERSION=${idf_init_version}" --dont-write-deprecated --output config ${sdkconfig} COMMAND ${TERM_CHECK_CMD} @@ -222,6 +255,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) "IDF_TARGET=${idf_target}" "IDF_TOOLCHAIN=${idf_toolchain}" "IDF_ENV_FPGA=${idf_env_fpga}" + "IDF_INIT_VERSION=${idf_init_version}" ${MENUCONFIG_CMD} ${root_kconfig} USES_TERMINAL # additional run of kconfgen esures that the deprecated options will be inserted into sdkconfig (for backward @@ -230,6 +264,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) --env "IDF_TARGET=${idf_target}" --env "IDF_TOOLCHAIN=${idf_toolchain}" --env "IDF_ENV_FPGA=${idf_env_fpga}" + --env "IDF_INIT_VERSION=${idf_init_version}" --output config ${sdkconfig} ) diff --git a/tools/kconfig_new/config.env.in b/tools/kconfig_new/config.env.in index a79768f3a2..962f02e4b8 100644 --- a/tools/kconfig_new/config.env.in +++ b/tools/kconfig_new/config.env.in @@ -4,6 +4,7 @@ "COMPONENT_SDKCONFIG_RENAMES": "${sdkconfig_renames}", "IDF_TARGET": "${idf_target}", "IDF_TOOLCHAIN": "${idf_toolchain}", + "IDF_VERSION": "$ENV{IDF_VERSION}", "IDF_ENV_FPGA": "${idf_env_fpga}", "IDF_PATH": "${idf_path}", "COMPONENT_KCONFIGS_SOURCE_FILE": "${kconfigs_path}", diff --git a/tools/test_build_system/test_sdkconfig.py b/tools/test_build_system/test_sdkconfig.py index 1b16ff213b..f84502575c 100644 --- a/tools/test_build_system/test_sdkconfig.py +++ b/tools/test_build_system/test_sdkconfig.py @@ -1,11 +1,33 @@ # SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import logging +import os +import re from pathlib import Path +from typing import Optional +import pytest from test_build_system_helpers import IdfPyFunc, file_contains +def idf_version_from_cmake() -> Optional[str]: + version_path = os.path.join(os.environ['IDF_PATH'], 'tools/cmake/version.cmake') + regex = re.compile(r'^\s*set\s*\(\s*IDF_VERSION_([A-Z]{5})\s+(\d+)') + ver = {} + try: + with open(version_path) as f: + for line in f: + m = regex.match(line) + + if m: + ver[m.group(1)] = m.group(2) + + return '%s.%s.%s' % (ver['MAJOR'], ver['MINOR'], ver['PATCH']) + except (KeyError, OSError): + pytest.fail('Cannot find ESP-IDF version in tools/cmake/version.cmake') + return None + + def test_sdkconfig_contains_all_files(idf_py: IdfPyFunc, test_app_copy: Path) -> None: logging.info('sdkconfig should have contents of all files: sdkconfig, sdkconfig.defaults, sdkconfig.defaults.IDF_TARGET') (test_app_copy / 'sdkconfig').write_text('CONFIG_PARTITION_TABLE_TWO_OTA=y') @@ -24,3 +46,18 @@ def test_sdkconfig_multiple_default_files(idf_py: IdfPyFunc, test_app_copy: Path idf_py('-DSDKCONFIG_DEFAULTS=sdkconfig.defaults1;sdkconfig.defaults2', 'reconfigure') assert all([file_contains((test_app_copy / 'sdkconfig'), x) for x in ['CONFIG_PARTITION_TABLE_TWO_OTA=y', 'CONFIG_PARTITION_TABLE_OFFSET=0x10000']]) + + +def test_keep_idf_init_version(idf_py: IdfPyFunc, test_app_copy: Path) -> None: + logging.info('sdkconfig should contain initial IDF version, even after regenerating the config') + (test_app_copy / 'sdkconfig').write_text('CONFIG_IDF_INIT_VERSION="1.2.3"') + idf_py('reconfigure') + assert file_contains((test_app_copy / 'sdkconfig'), 'CONFIG_IDF_INIT_VERSION="1.2.3"') + + +def test_empty_idf_init_version(idf_py: IdfPyFunc, test_app_copy: Path) -> None: + logging.info('sdkconfig should add current IDF version as initial IDF version') + (test_app_copy / 'sdkconfig').write_text('CONFIG_IDF_INIT_VERSION=""') + idf_py('reconfigure') + version = idf_version_from_cmake() + assert file_contains((test_app_copy / 'sdkconfig'), f'CONFIG_IDF_INIT_VERSION="{version}"')