tools: cmake: check tool supported version with idf_tools.py

This commit is contained in:
Alexey Lapshin 2022-09-01 00:59:15 +04:00
parent d6aacbc9ce
commit e6f7b1a3a0
10 changed files with 106 additions and 96 deletions

View File

@ -2,9 +2,12 @@
# Warn if the toolchain version doesn't match
#
if(NOT (${target} STREQUAL "linux" OR CMAKE_C_COMPILER_ID MATCHES "Clang"))
get_expected_ctng_version(expected_toolchain expected_gcc)
gcc_version_check("${expected_gcc}")
crosstool_version_check("${expected_toolchain}")
execute_process(
COMMAND ${CMAKE_C_COMPILER} -dumpmachine
OUTPUT_VARIABLE toolchain_name
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
check_expected_tool_version(${toolchain_name} ${CMAKE_C_COMPILER})
endif()
if(NOT ${target} STREQUAL "linux" AND CMAKE_C_COMPILER_ID MATCHES "Clang")

View File

@ -1,35 +1,16 @@
cmake_minimum_required(VERSION 3.16)
include(${IDF_PATH}/tools/cmake/utilities.cmake)
include(${IDF_PATH}/tools/cmake/idf.cmake)
project(${ULP_APP_NAME} ASM C)
add_executable(${ULP_APP_NAME})
option(ULP_COCPU_IS_RISCV "Use RISC-V based ULP" OFF)
set(version_pattern "[a-z0-9\.-_]+")
# Check assembler version
execute_process(
COMMAND ${CMAKE_ASM_COMPILER} --version
OUTPUT_VARIABLE as_output
ERROR_QUIET)
string(REGEX MATCH "\\(GNU Binutils\\) (${version_pattern})" as_version ${as_output})
set(as_version ${CMAKE_MATCH_1})
message(STATUS "Building ULP app ${ULP_APP_NAME}")
# Check the supported assembler version
if(NOT ULP_COCPU_IS_RISCV)
message(STATUS "ULP assembler version: ${as_version}")
set(as_supported_version 2.35_20220830)
if(NOT as_version STREQUAL as_supported_version)
message(WARNING "WARNING: ULP assembler version ${as_version} is not supported. Expected to see version: \
${as_supported_version}. Please check ESP-IDF ULP setup instructions and update \
the toolchain, or proceed at your own risk.")
endif()
check_expected_tool_version("esp32ulp-elf" ${CMAKE_ASM_COMPILER})
endif()

View File

@ -190,7 +190,6 @@ extensions += ['sphinx_copybutton',
# connected to another extension
'esp_docs.idf_extensions.build_system',
'esp_docs.idf_extensions.esp_err_definitions',
'esp_docs.idf_extensions.gen_toolchain_links',
'esp_docs.idf_extensions.gen_defines',
'esp_docs.idf_extensions.gen_version_specific_includes',
'esp_docs.idf_extensions.kconfig_reference',

View File

@ -39,4 +39,3 @@ tools/set-submodules-to-github.sh
tools/templates/sample_component/CMakeLists.txt
tools/templates/sample_component/include/main.h
tools/templates/sample_component/main.c
tools/toolchain_versions.mk

View File

@ -10,7 +10,7 @@ error\.d
/.*error\S*.d
reassigning to symbol
changes choice state
crosstool_version_check\.cmake
tool_version_check\.cmake
CryptographyDeprecationWarning
Warning: \d+/\d+ app partitions are too small for binary
CMake Deprecation Warning at main/lib/tinyxml2/CMakeLists\.txt:11 \(cmake_policy\)

View File

@ -1,59 +0,0 @@
# Function to check the toolchain used the expected version
# of crosstool, and warn otherwise
set(ctng_version_warning "Check Getting Started documentation or proceed at own risk.\n")
function(gcc_version_check expected_gcc_version)
if(NOT "${CMAKE_C_COMPILER_VERSION}" STREQUAL "${expected_gcc_version}")
message(WARNING "Toolchain ${CMAKE_C_COMPILER} version ${CMAKE_C_COMPILER_VERSION} "
"is not the supported version ${expected_gcc_version}. ${ctng_version_warning}")
endif()
endfunction()
function(crosstool_version_check expected_ctng_version)
execute_process(
COMMAND ${CMAKE_C_COMPILER} --version
OUTPUT_VARIABLE toolchain_version
ERROR_QUIET)
string(REGEX REPLACE ".*(crosstool-NG ([^\)]+)).*\n" "\\2" ctng_version "${toolchain_version}")
# We use FIND to match version instead of STREQUAL because some toolchains are built
# with longer git hash strings than others. This will match any version which starts with
# the expected version string.
string(FIND "${ctng_version}" "${expected_ctng_version}" found_expected_version)
if(NOT ctng_version)
message(WARNING "Toolchain ${CMAKE_C_COMPILER} does not appear to be built with crosstool-ng. "
"${ctng_version_warning}")
elseif(found_expected_version EQUAL -1)
set(wrong_compiler_msg "\nToolchain: ${CMAKE_C_COMPILER}, "
"crosstool-ng version ${ctng_version} doesn't match supported version ${expected_ctng_version}"
"\nPlease try to run 'idf.py fullclean' to solve it quickly.\n")
set(IDF_MAINTAINER $ENV{IDF_MAINTAINER})
if(IDF_MAINTAINER)
message(WARNING ${wrong_compiler_msg} ${ctng_version_warning})
else()
set(ctng_version_error "Check Getting Started documentation if the error continues."
"\nYou can override this error and proceed with build by defining the IDF_MAINTAINER environment variable.\n")
message(FATAL_ERROR ${wrong_compiler_msg} ${ctng_version_error})
endif()
endif()
endfunction()
function(get_expected_ctng_version _toolchain_ver _gcc_ver)
idf_build_get_property(idf_path IDF_PATH)
file(STRINGS ${idf_path}/tools/toolchain_versions.mk config_contents)
foreach(name_and_value ${config_contents})
# Strip spaces
string(REPLACE " " "" name_and_value ${name_and_value})
# Find variable name
string(REGEX MATCH "^[^=]+" name ${name_and_value})
# Find the value
string(REPLACE "${name}=" "" value ${name_and_value})
# Getting values
if("${name}" STREQUAL "SUPPORTED_TOOLCHAIN_COMMIT_DESC")
set("${_toolchain_ver}" "${value}" PARENT_SCOPE)
elseif("${name}" STREQUAL "SUPPORTED_TOOLCHAIN_GCC_VERSIONS")
set(${_gcc_ver} "${value}" PARENT_SCOPE)
endif()
endforeach()
endfunction()

View File

@ -39,7 +39,7 @@ if(NOT __idf_env_set)
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(git_submodules)
include(crosstool_version_check)
include(tool_version_check)
include(kconfig)
include(component)
include(utilities)

View File

@ -0,0 +1,44 @@
function(check_expected_tool_version tool_name tool_path)
# Function to check the tool used the expected version and warn otherwise
set(tool_version_warning "Check Getting Started documentation or proceed at own risk.\n")
set(tool_version_error "Check Getting Started documentation if the error continues.\n"
"You can override this error and proceed with build by defining the IDF_MAINTAINER environment variable.\n")
set(fixing_hint "Please try to run 'idf.py fullclean' to solve it.\n")
idf_build_get_property(python PYTHON)
idf_build_get_property(idf_path IDF_PATH)
set(ENV{IDF_TOOLS_VERSION_HELPER} "1")
# Use idf_tools.py to check if tool version is supported
execute_process(
COMMAND ${python} "${idf_path}/tools/idf_tools.py"
"check-tool-supported" "--tool-name" "${tool_name}"
"--exec-path" "${tool_path}"
OUTPUT_VARIABLE is_version_supported
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
if(is_version_supported STREQUAL "False")
# Version is not supported. Need to get supported versions list to print them to user
execute_process(
COMMAND ${python} "${idf_path}/tools/idf_tools.py"
"get-tool-supported-versions" "--tool-name" "${tool_name}"
OUTPUT_VARIABLE tool_supported_versions
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
# IDF maintainers can build projects with not supported versions with just a warning
if($ENV{IDF_MAINTAINER})
set(message_mode "WARNING")
else()
set(message_mode "FATAL_ERROR")
endif()
message(${message_mode} "\n"
"Tool doesn't match supported version from list "
"${tool_supported_versions}: ${tool_path}\n"
${fixing_hint})
elseif(NOT is_version_supported STREQUAL "True")
message(WARNING "Can not get version for tool: ${tool_path}\n" ${tool_version_warning})
endif()
unset(ENV{IDF_TOOLS_VERSION_HELPER})
endfunction()

View File

@ -646,7 +646,7 @@ class IDFTool(object):
result[k] = v_repl
return result
def check_version(self, extra_paths=None): # type: (Optional[List[str]]) -> str
def get_version(self, extra_paths=None, executable_path=None): # type: (Optional[List[str]], Optional[str]) -> str
"""
Execute the tool, optionally prepending extra_paths to PATH,
extract the version string and return it as a result.
@ -658,6 +658,8 @@ class IDFTool(object):
# this function can not be called for a different platform
assert self._platform == CURRENT_PLATFORM
cmd = self._current_options.version_cmd # type: ignore
if executable_path:
cmd[0] = executable_path
try:
version_cmd_result = run_cmd_check_output(cmd, None, extra_paths)
except OSError:
@ -673,6 +675,10 @@ class IDFTool(object):
return UNKNOWN_VERSION
return re.sub(self._current_options.version_regex, self._current_options.version_regex_replace, match.group(0)) # type: ignore
def check_version(self, executable_path): # type: (Optional[str]) -> bool
version = self.get_version(executable_path=executable_path)
return version in self.versions
def get_install_type(self): # type: () -> Callable[[str], None]
return self._current_options.install # type: ignore
@ -715,7 +721,7 @@ class IDFTool(object):
assert self._platform == CURRENT_PLATFORM
# First check if the tool is in system PATH
try:
ver_str = self.check_version()
ver_str = self.get_version()
except ToolNotFound:
# not in PATH
pass
@ -738,7 +744,7 @@ class IDFTool(object):
self.versions_installed.append(version)
continue
try:
ver_str = self.check_version(self.get_export_paths(version))
ver_str = self.get_version(self.get_export_paths(version))
except ToolNotFound:
warn('directory for tool {} version {} is present, but tool was not found'.format(
self.name, version))
@ -2380,6 +2386,40 @@ More info: {info_url}
print_out('')
def action_check_tool_supported(args): # type: (Any) -> None
"""
Print "True"/"False" to stdout as a result that tool is supported in IDF
Print erorr message to stderr otherwise and set exit code to 1
"""
try:
tools_info = load_tools_info()
for _, v in tools_info.items():
if v.name == args.tool_name:
print(v.check_version(args.exec_path))
break
except (RuntimeError, ToolNotFound, ToolExecError) as err:
fatal(f'Failed to check tool support: (name: {args.tool_name}, exec: {args.exec_path})')
fatal(f'{err}')
raise SystemExit(1)
def action_get_tool_supported_versions(args): # type: (Any) -> None
"""
Print supported versions of a tool to stdout
Print erorr message to stderr otherwise and set exit code to 1
"""
try:
tools_info = load_tools_info()
for _, v in tools_info.items():
if v.name == args.tool_name:
print(list(v.versions.keys()))
break
except RuntimeError as err:
fatal(f'Failed to get tool supported versions. (tool: {args.tool_name})')
fatal(f'{err}')
raise SystemExit(1)
def main(argv): # type: (list[str]) -> None
parser = argparse.ArgumentParser()
@ -2477,6 +2517,15 @@ def main(argv): # type: (list[str]) -> None
'to manage package versions by yourself. It can be set with the IDF_PYTHON_CHECK_CONSTRAINTS '
'environment variable.')
if os.environ.get('IDF_TOOLS_VERSION_HELPER'):
check_tool_supported = subparsers.add_parser('check-tool-supported',
help='Check that selected tool is compatible with IDF. Writes "True"/"False" to stdout in success.')
check_tool_supported.add_argument('--tool-name', required=True, help='Tool name (from tools.json)')
check_tool_supported.add_argument('--exec-path', required=True, help='Full path to executable under the test')
get_tool_supported_versions = subparsers.add_parser('get-tool-supported-versions', help='Prints a list of tool\'s supported versions')
get_tool_supported_versions.add_argument('--tool-name', required=True, help='Tool name (from tools.json)')
args = parser.parse_args(argv)
if args.action is None:

View File

@ -1,6 +0,0 @@
SUPPORTED_TOOLCHAIN_COMMIT_DESC = esp-2022r1
SUPPORTED_TOOLCHAIN_GCC_VERSIONS = 11.2.0
CURRENT_TOOLCHAIN_COMMIT_DESC = esp-2022r1
CURRENT_TOOLCHAIN_COMMIT_DESC_SHORT = esp-2022r1
CURRENT_TOOLCHAIN_GCC_VERSION = 11.2.0