esp-idf/tools/cmake/targets.cmake
Frantisek Hrbata 0d859f2786 tools: move target guessing into cmake
The _guess_or_check_idf_target() function has sdkconfig and sdkconfig.defaults
file names hardcoded. Since config file names may be specified with SDKCONFIG
or SDKCONFIG_DEFAULTS cmake vars, directly in CMakeLists.txt or passed in with
the -D cmake option, they are not respected.

Problem is when SDKCONFIG or SDKCONFIG_DEFAULTS is set in
CMakeLists.txt. While idf can detect cmake vars passed through it
to cmake via the -D option, detecting SDKCONFIG and SDKCONFIG_DEFAULTS
vars settings in CMakeLists.txt would require to parse it. This seems
like error prone approach. Also if the vars defined by the -D option
are passed directly to cmake, not via idf, they will not be visible to idf.

It seems reasonable to move the logic into cmake, where we know the correct
SDKCONFIG and SDKCONFIG_DEFAULTS values. So the IDF_TARGET detection/guessing
is moved into targets.cmake, where the IDF_TARGET is actually set. The target
is guessed based on the following precendence.

1) $ENV{IDF_TARGET}
2) IDF_TARGET
3) SDKCONFIG
4) sdkconfig
5) SDKCONFIG_DEFAULTS if non-empty or
   $ENV{SDKCONFIG_DEFAULTS} if non-empty or
   sdkconfig.defaults
6) esp32

All config files referred in $ENV{SDKCONFIG_DEFAULTS} and SDKCONFIG_DEFAULTS
are searched, compared to the current behaviour. First target found in the
above chain is used.

The original _guess_or_check_idf_target() is renamed to _check_idf_target() and
used for the target consistency checks only.

The get_sdkconfig_filename() helper is now used to get the sdkconfig file
for consistency checks. It looks in SDKCONFIG specified with the -D
option and project_description.json.

With this change config full paths are reported in messages, so it's clear
e.g. from which config the target was guessed from or which config has
consistency problem. test_non_default_target.py was adjusted to this
change and also new test for testing the IDF_TARGET guessing was added.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2023-03-08 16:37:58 +01:00

160 lines
5.5 KiB
CMake

#
# Get target from single sdkconfig file
#
function(__target_from_config config target_out file_out)
set(${target_out} NOTFOUND PARENT_SCOPE)
set(${file_out} NOTFOUND PARENT_SCOPE)
if(NOT EXISTS "${config}")
return()
endif()
file(STRINGS "${config}" lines)
foreach(line ${lines})
if(NOT "${line}" MATCHES "^CONFIG_IDF_TARGET=\"[^\"]+\"$")
continue()
endif()
string(REGEX REPLACE "CONFIG_IDF_TARGET=\"([^\"]+)\"" "\\1" target "${line}")
set(${target_out} ${target} PARENT_SCOPE)
set(${file_out} ${config} PARENT_SCOPE)
return()
endforeach()
endfunction()
#
# Get target from list of sdkconfig files
#
function(__target_from_configs configs target_out file_out)
set(target NOTFOUND)
set(file NOTFOUND)
foreach(config ${configs})
message(DEBUG "Searching for target in '${config}'")
get_filename_component(config "${config}" ABSOLUTE)
__target_from_config("${config}" target file)
if(target)
break()
endif()
endforeach()
set(${target_out} ${target} PARENT_SCOPE)
set(${file_out} ${file} PARENT_SCOPE)
endfunction()
#
# Search for target in config files in the following order.
# SDKCONFIG cmake var, default sdkconfig, SDKCONFIG_DEFAULTS cmake var
# if non-empty or SDKCONFIG_DEFAULTS env var if non-empty or
# sdkconfig.defaults.
#
function(__target_guess target_out file_out)
# Select sdkconfig_defaults to look for target
if(SDKCONFIG_DEFAULTS)
set(defaults "${SDKCONFIG_DEFAULTS}")
elseif(DEFINED ENV{SDKCONFIG_DEFAULTS})
set(defaults "$ENV{SDKCONFIG_DEFAULTS}")
endif()
if(NOT defaults)
set(defaults "${CMAKE_SOURCE_DIR}/sdkconfig.defaults")
endif()
set(configs "${SDKCONFIG}" "${CMAKE_SOURCE_DIR}/sdkconfig" "${defaults}")
message(DEBUG "Searching for target in '${configs}'")
__target_from_configs("${configs}" target file)
set(${target_out} ${target} PARENT_SCOPE)
set(${file_out} ${file} PARENT_SCOPE)
endfunction()
#
# Set the target used for the standard project build.
#
macro(__target_init)
# Input is IDF_TARGET environement variable
set(env_idf_target $ENV{IDF_TARGET})
if(NOT env_idf_target)
# IDF_TARGET not set in environment, see if it is set in cache
if(IDF_TARGET)
set(env_idf_target ${IDF_TARGET})
else()
# Try to guess IDF_TARGET from sdkconfig files while honoring
# SDKCONFIG and SDKCONFIG_DEFAULTS values
__target_guess(env_idf_target where)
if(env_idf_target)
message(STATUS "IDF_TARGET is not set, guessed '${env_idf_target}' from sdkconfig '${where}'")
else()
set(env_idf_target esp32)
message(STATUS "IDF_TARGET not set, using default target: ${env_idf_target}")
endif()
endif()
else()
# IDF_TARGET set both in environment and in cache, must be the same
if(NOT ${IDF_TARGET} STREQUAL ${env_idf_target})
message(FATAL_ERROR "IDF_TARGET in CMake cache does not match "
"IDF_TARGET environment variable. To change the target, clear "
"the build directory and sdkconfig file, and build the project again")
endif()
endif()
# IDF_TARGET will be used by Kconfig, make sure it is set
set(ENV{IDF_TARGET} ${env_idf_target})
# Finally, set IDF_TARGET in cache
set(IDF_TARGET ${env_idf_target} CACHE STRING "IDF Build Target")
endmacro()
#
# Check that the set build target and the config target matches.
#
function(__target_check)
# Should be called after sdkconfig CMake file has been included.
idf_build_get_property(idf_target IDF_TARGET)
if(NOT ${idf_target} STREQUAL ${CONFIG_IDF_TARGET})
message(FATAL_ERROR "CONFIG_IDF_TARGET in sdkconfig does not match "
"IDF_TARGET environment variable. To change the target, delete "
"sdkconfig file and build the project again.")
endif()
endfunction()
#
# Used by the project CMake file to set the toolchain before project() call.
#
macro(__target_set_toolchain)
idf_build_get_property(idf_path IDF_PATH)
# See if Clang toolchain should be used
set(env_idf_toolchain $ENV{IDF_TOOLCHAIN})
if(NOT env_idf_toolchain)
# IDF_TOOLCHAIN not set in environment, see if it is set in cache
if(IDF_TOOLCHAIN)
set(env_idf_toolchain ${IDF_TOOLCHAIN})
else()
set(env_idf_toolchain gcc)
endif()
else()
# IDF_TOOLCHAIN set both in environment and in cache, must be the same
if(NOT ${IDF_TOOLCHAIN} STREQUAL ${env_idf_toolchain})
message(FATAL_ERROR "IDF_TOOLCHAIN in CMake cache does not match "
"IDF_TOOLCHAIN environment variable. To change the toolchain, clear "
"the build directory and sdkconfig file, and build the project again")
endif()
endif()
# Finally, set IDF_TOOLCHAIN in cache
set(IDF_TOOLCHAIN ${env_idf_toolchain} CACHE STRING "IDF Build Toolchain Type")
if(${env_idf_toolchain} STREQUAL "clang")
set(toolchain_type "clang-")
endif()
# First try to load the toolchain file from the tools/cmake/directory of IDF
set(toolchain_file_global ${idf_path}/tools/cmake/toolchain-${toolchain_type}${IDF_TARGET}.cmake)
if(EXISTS ${toolchain_file_global})
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global})
else()
message(FATAL_ERROR "Toolchain file ${toolchain_file_global} not found")
endif()
endmacro()