Pārlūkot izejas kodu

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

Alexey Lapshin 3 gadi atpakaļ
vecāks
revīzija
e6f7b1a3a0

+ 6 - 3
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")

+ 2 - 21
components/ulp/cmake/CMakeLists.txt

@@ -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()
 
 

+ 0 - 1
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',

+ 0 - 1
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

+ 1 - 1
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\)

+ 0 - 59
tools/cmake/crosstool_version_check.cmake

@@ -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()

+ 1 - 1
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)

+ 44 - 0
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()

+ 52 - 3
tools/idf_tools.py

@@ -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:

+ 0 - 6
tools/toolchain_versions.mk

@@ -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