diff --git a/components/esp_common/project_include.cmake b/components/esp_common/project_include.cmake index e7b1d65448..2665404c50 100644 --- a/components/esp_common/project_include.cmake +++ b/components/esp_common/project_include.cmake @@ -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") diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index 45caeb35e9..e4095507c1 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/components/ulp/cmake/CMakeLists.txt @@ -1,36 +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) 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}") if(ULP_COCPU_IS_RISCV) set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_riscv.ld) else() - 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}) set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_fsm.ld) endif() diff --git a/docs/conf_common.py b/docs/conf_common.py index a911c2aef0..38bc363874 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -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', diff --git a/tools/ci/exclude_check_tools_files.txt b/tools/ci/exclude_check_tools_files.txt index ceaa7f173e..a218ba6da7 100644 --- a/tools/ci/exclude_check_tools_files.txt +++ b/tools/ci/exclude_check_tools_files.txt @@ -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 diff --git a/tools/ci/ignore_build_warnings.txt b/tools/ci/ignore_build_warnings.txt index 92233a00aa..0f2daf214b 100644 --- a/tools/ci/ignore_build_warnings.txt +++ b/tools/ci/ignore_build_warnings.txt @@ -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\) diff --git a/tools/cmake/crosstool_version_check.cmake b/tools/cmake/crosstool_version_check.cmake deleted file mode 100644 index 5f8aeaa116..0000000000 --- a/tools/cmake/crosstool_version_check.cmake +++ /dev/null @@ -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() diff --git a/tools/cmake/idf.cmake b/tools/cmake/idf.cmake index aad4475af5..71cf857369 100644 --- a/tools/cmake/idf.cmake +++ b/tools/cmake/idf.cmake @@ -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) diff --git a/tools/cmake/tool_version_check.cmake b/tools/cmake/tool_version_check.cmake new file mode 100644 index 0000000000..df68f59b9b --- /dev/null +++ b/tools/cmake/tool_version_check.cmake @@ -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() diff --git a/tools/idf_tools.py b/tools/idf_tools.py index a388bbdb5f..fd6a6c9605 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -623,7 +623,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. @@ -635,6 +635,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: @@ -650,6 +652,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 @@ -692,7 +698,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 @@ -712,7 +718,7 @@ class IDFTool(object): # version not installed 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)) @@ -2370,6 +2376,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() @@ -2466,6 +2506,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: diff --git a/tools/toolchain_versions.mk b/tools/toolchain_versions.mk deleted file mode 100644 index ac6175da22..0000000000 --- a/tools/toolchain_versions.mk +++ /dev/null @@ -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