mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 12:14:32 +02:00
feat(tools): Add standalone Clang libraries to tools.json
This commit is contained in:
@@ -43,6 +43,11 @@ On Linux and macOS, it is recommended to install CMake using the OS-specific pac
|
|||||||
.. tool-esp-clang-notes
|
.. tool-esp-clang-notes
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
.. tool-esp-clang-libs-notes
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
.. tool-ninja-notes
|
.. tool-ninja-notes
|
||||||
|
@@ -43,6 +43,11 @@ On Linux and macOS, it is recommended to install CMake using the OS-specific pac
|
|||||||
.. tool-esp-clang-notes
|
.. tool-esp-clang-notes
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
.. tool-esp-clang-libs-notes
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
.. tool-ninja-notes
|
.. tool-ninja-notes
|
||||||
|
@@ -82,7 +82,7 @@ TOOLS_FILE = 'tools/tools.json'
|
|||||||
TOOLS_SCHEMA_FILE = 'tools/tools_schema.json'
|
TOOLS_SCHEMA_FILE = 'tools/tools_schema.json'
|
||||||
TOOLS_FILE_NEW = 'tools/tools.new.json'
|
TOOLS_FILE_NEW = 'tools/tools.new.json'
|
||||||
IDF_ENV_FILE = 'idf-env.json'
|
IDF_ENV_FILE = 'idf-env.json'
|
||||||
TOOLS_FILE_VERSION = 2
|
TOOLS_FILE_VERSION = 3
|
||||||
IDF_TOOLS_PATH_DEFAULT = os.path.join('~', '.espressif')
|
IDF_TOOLS_PATH_DEFAULT = os.path.join('~', '.espressif')
|
||||||
UNKNOWN_VERSION = 'unknown'
|
UNKNOWN_VERSION = 'unknown'
|
||||||
SUBST_TOOL_PATH_REGEX = re.compile(r'\${TOOL_PATH}')
|
SUBST_TOOL_PATH_REGEX = re.compile(r'\${TOOL_PATH}')
|
||||||
@@ -789,6 +789,7 @@ IDFToolOptions = namedtuple('IDFToolOptions', [
|
|||||||
'version_regex',
|
'version_regex',
|
||||||
'version_regex_replace',
|
'version_regex_replace',
|
||||||
'is_executable',
|
'is_executable',
|
||||||
|
'tool_info_file',
|
||||||
'export_paths',
|
'export_paths',
|
||||||
'export_vars',
|
'export_vars',
|
||||||
'install',
|
'install',
|
||||||
@@ -818,7 +819,8 @@ class IDFTool(object):
|
|||||||
supported_targets: List[str],
|
supported_targets: List[str],
|
||||||
version_regex_replace: Optional[str] = None,
|
version_regex_replace: Optional[str] = None,
|
||||||
strip_container_dirs: int = 0,
|
strip_container_dirs: int = 0,
|
||||||
is_executable: bool = True) -> None:
|
is_executable: bool = True,
|
||||||
|
tool_info_file: str = '') -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.description = description
|
self.description = description
|
||||||
self.drop_versions()
|
self.drop_versions()
|
||||||
@@ -826,12 +828,13 @@ class IDFTool(object):
|
|||||||
self.versions_installed: List[str] = []
|
self.versions_installed: List[str] = []
|
||||||
if version_regex_replace is None:
|
if version_regex_replace is None:
|
||||||
version_regex_replace = VERSION_REGEX_REPLACE_DEFAULT
|
version_regex_replace = VERSION_REGEX_REPLACE_DEFAULT
|
||||||
self.options = IDFToolOptions(version_cmd, version_regex, version_regex_replace, is_executable,
|
self.options = IDFToolOptions(version_cmd, version_regex, version_regex_replace, is_executable, tool_info_file,
|
||||||
[], OrderedDict(), install, info_url, license, strip_container_dirs, supported_targets) # type: ignore
|
[], OrderedDict(), install, info_url, license, strip_container_dirs, supported_targets) # type: ignore
|
||||||
self.platform_overrides: List[Dict[str, str]] = []
|
self.platform_overrides: List[Dict[str, str]] = []
|
||||||
self._platform = CURRENT_PLATFORM
|
self._platform = CURRENT_PLATFORM
|
||||||
self._update_current_options()
|
self._update_current_options()
|
||||||
self.is_executable = is_executable
|
self.is_executable = is_executable
|
||||||
|
self.tool_info_file = tool_info_file
|
||||||
|
|
||||||
def copy_for_platform(self, platform: str) -> 'IDFTool':
|
def copy_for_platform(self, platform: str) -> 'IDFTool':
|
||||||
"""
|
"""
|
||||||
@@ -905,6 +908,16 @@ class IDFTool(object):
|
|||||||
result[k] = v_repl
|
result[k] = v_repl
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def parse_tool_version(self, ver_str: str) -> str:
|
||||||
|
"""
|
||||||
|
Extract the version string from the provided input and return it as a result.
|
||||||
|
Returns 'unknown' if version string can not be extracted..
|
||||||
|
"""
|
||||||
|
match = re.search(self._current_options.version_regex, ver_str) # type: ignore
|
||||||
|
if not match:
|
||||||
|
return UNKNOWN_VERSION
|
||||||
|
return re.sub(self._current_options.version_regex, self._current_options.version_regex_replace, match.group(0)) # type: ignore
|
||||||
|
|
||||||
def get_version(self, extra_paths: Optional[List[str]] = None, executable_path: Optional[str] = None) -> str:
|
def get_version(self, extra_paths: Optional[List[str]] = None, executable_path: Optional[str] = None) -> str:
|
||||||
"""
|
"""
|
||||||
Execute the tool, optionally prepending extra_paths to PATH,
|
Execute the tool, optionally prepending extra_paths to PATH,
|
||||||
@@ -934,17 +947,39 @@ class IDFTool(object):
|
|||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise ToolExecError(f'non-zero exit code ({e.returncode}) with message: {e.stderr.decode("utf-8",errors="ignore")}') # type: ignore
|
raise ToolExecError(f'non-zero exit code ({e.returncode}) with message: {e.stderr.decode("utf-8",errors="ignore")}') # type: ignore
|
||||||
|
|
||||||
in_str = version_cmd_result.decode('utf-8')
|
return self.parse_tool_version(version_cmd_result.decode('utf-8'))
|
||||||
match = re.search(self._current_options.version_regex, in_str) # type: ignore
|
|
||||||
if not match:
|
def get_version_from_file(self, version: str) -> str:
|
||||||
return UNKNOWN_VERSION
|
"""
|
||||||
return re.sub(self._current_options.version_regex, self._current_options.version_regex_replace, match.group(0)) # type: ignore
|
Extract the version string from tool info file and return it as a result.
|
||||||
|
Returns 'unknown' if version string can not be extracted.
|
||||||
|
"""
|
||||||
|
# this function can not be called for a different platform
|
||||||
|
assert self._platform == CURRENT_PLATFORM
|
||||||
|
# Replace '/' with OS specific path separator
|
||||||
|
info_file_path = os.path.join(*self.tool_info_file.split('/'))
|
||||||
|
info_file_path = os.path.join(self.get_path_for_version(version), info_file_path)
|
||||||
|
if not os.path.exists(info_file_path):
|
||||||
|
raise ToolNotFoundError(f'Tool {self.name} not found: No info file.')
|
||||||
|
with open(info_file_path, 'r', encoding='utf-8') as f:
|
||||||
|
try:
|
||||||
|
tool_info = json.load(f)
|
||||||
|
except (json.JSONDecodeError, UnicodeDecodeError):
|
||||||
|
raise ToolNotFoundError(f'Tool {self.name} not found: Bad info file.')
|
||||||
|
|
||||||
|
if 'version' not in tool_info:
|
||||||
|
raise ToolNotFoundError(f'Tool {self.name} not found: No version in info file.')
|
||||||
|
|
||||||
|
return self.parse_tool_version(tool_info['version'])
|
||||||
|
|
||||||
def check_binary_valid(self, version: str) -> bool:
|
def check_binary_valid(self, version: str) -> bool:
|
||||||
if not self.is_executable:
|
if not self.is_executable:
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
ver_str = self.get_version(self.get_export_paths(version))
|
if self.tool_info_file:
|
||||||
|
ver_str = self.get_version_from_file(version)
|
||||||
|
else:
|
||||||
|
ver_str = self.get_version(self.get_export_paths(version))
|
||||||
except (ToolNotFoundError, ToolExecError) as e:
|
except (ToolNotFoundError, ToolExecError) as e:
|
||||||
fatal(f'tool {self.name} version {version} is installed, but getting error: {e}')
|
fatal(f'tool {self.name} version {version} is installed, but getting error: {e}')
|
||||||
return False
|
return False
|
||||||
@@ -1028,17 +1063,18 @@ class IDFTool(object):
|
|||||||
# this function can not be called for a different platform
|
# this function can not be called for a different platform
|
||||||
assert self._platform == CURRENT_PLATFORM
|
assert self._platform == CURRENT_PLATFORM
|
||||||
tool_error = False
|
tool_error = False
|
||||||
# First check if the tool is in system PATH
|
if not self.tool_info_file:
|
||||||
try:
|
# First check if the tool is in system PATH
|
||||||
ver_str = self.get_version()
|
try:
|
||||||
except ToolNotFoundError:
|
ver_str = self.get_version()
|
||||||
# not in PATH
|
except ToolNotFoundError:
|
||||||
pass
|
# not in PATH
|
||||||
except ToolExecError as e:
|
pass
|
||||||
fatal(f'tool {self.name} is found in PATH, but has failed: {e}')
|
except ToolExecError as e:
|
||||||
tool_error = True
|
fatal(f'tool {self.name} is found in PATH, but has failed: {e}')
|
||||||
else:
|
tool_error = True
|
||||||
self.version_in_path = ver_str
|
else:
|
||||||
|
self.version_in_path = ver_str
|
||||||
|
|
||||||
# Now check all the versions installed in GlobalVarsStore.idf_tools_path
|
# Now check all the versions installed in GlobalVarsStore.idf_tools_path
|
||||||
self.versions_installed = []
|
self.versions_installed = []
|
||||||
@@ -1053,7 +1089,10 @@ class IDFTool(object):
|
|||||||
self.versions_installed.append(version)
|
self.versions_installed.append(version)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
ver_str = self.get_version(self.get_export_paths(version))
|
if self.tool_info_file:
|
||||||
|
ver_str = self.get_version_from_file(version)
|
||||||
|
else:
|
||||||
|
ver_str = self.get_version(self.get_export_paths(version))
|
||||||
except ToolNotFoundError as e:
|
except ToolNotFoundError as e:
|
||||||
warn(f'directory for tool {self.name} version {version} is present, but the tool has not been found: {e}')
|
warn(f'directory for tool {self.name} version {version} is present, but the tool has not been found: {e}')
|
||||||
except ToolExecError as e:
|
except ToolExecError as e:
|
||||||
@@ -1083,7 +1122,10 @@ class IDFTool(object):
|
|||||||
# export paths list directly here.
|
# export paths list directly here.
|
||||||
paths = [os.path.join(tool_path, version, *p) for p in self._current_options.export_paths]
|
paths = [os.path.join(tool_path, version, *p) for p in self._current_options.export_paths]
|
||||||
try:
|
try:
|
||||||
ver_str = self.get_version(paths)
|
if self.tool_info_file:
|
||||||
|
ver_str = self.get_version_from_file(version)
|
||||||
|
else:
|
||||||
|
ver_str = self.get_version(paths)
|
||||||
except (ToolNotFoundError, ToolExecError):
|
except (ToolNotFoundError, ToolExecError):
|
||||||
continue
|
continue
|
||||||
if ver_str != version:
|
if ver_str != version:
|
||||||
@@ -1191,6 +1233,10 @@ class IDFTool(object):
|
|||||||
if not isinstance(is_executable, bool):
|
if not isinstance(is_executable, bool):
|
||||||
raise RuntimeError(f'is_executable for tool {tool_name} is not a bool')
|
raise RuntimeError(f'is_executable for tool {tool_name} is not a bool')
|
||||||
|
|
||||||
|
tool_info_file = tool_dict.get('tool_info_file', '')
|
||||||
|
if not isinstance(tool_info_file, str):
|
||||||
|
raise RuntimeError(f'tool_info_file for tool {tool_name} is not a string')
|
||||||
|
|
||||||
version_cmd = tool_dict.get('version_cmd')
|
version_cmd = tool_dict.get('version_cmd')
|
||||||
if type(version_cmd) is not list:
|
if type(version_cmd) is not list:
|
||||||
raise RuntimeError(f'version_cmd for tool {tool_name} is not a list of strings')
|
raise RuntimeError(f'version_cmd for tool {tool_name} is not a list of strings')
|
||||||
@@ -1242,7 +1288,7 @@ class IDFTool(object):
|
|||||||
# Create the object
|
# Create the object
|
||||||
tool_obj: 'IDFTool' = cls(tool_name, description, install, info_url, license, # type: ignore
|
tool_obj: 'IDFTool' = cls(tool_name, description, install, info_url, license, # type: ignore
|
||||||
version_cmd, version_regex, supported_targets, version_regex_replace, # type: ignore
|
version_cmd, version_regex, supported_targets, version_regex_replace, # type: ignore
|
||||||
strip_container_dirs, is_executable) # type: ignore
|
strip_container_dirs, is_executable, tool_info_file) # type: ignore
|
||||||
|
|
||||||
for path in export_paths: # type: ignore
|
for path in export_paths: # type: ignore
|
||||||
tool_obj.options.export_paths.append(path) # type: ignore
|
tool_obj.options.export_paths.append(path) # type: ignore
|
||||||
@@ -1371,6 +1417,8 @@ class IDFTool(object):
|
|||||||
tool_json['strip_container_dirs'] = self.options.strip_container_dirs
|
tool_json['strip_container_dirs'] = self.options.strip_container_dirs
|
||||||
if self.options.is_executable is False:
|
if self.options.is_executable is False:
|
||||||
tool_json['is_executable'] = self.options.is_executable
|
tool_json['is_executable'] = self.options.is_executable
|
||||||
|
if self.options.tool_info_file:
|
||||||
|
tool_json['tool_info_file'] = self.options.tool_info_file
|
||||||
return tool_json
|
return tool_json
|
||||||
|
|
||||||
|
|
||||||
|
@@ -300,6 +300,67 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Standalone Clang shared libraries distribution",
|
||||||
|
"export_paths": [],
|
||||||
|
"export_vars": {},
|
||||||
|
"info_url": "https://github.com/espressif/llvm-project",
|
||||||
|
"install": "on_request",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"name": "esp-clang-libs",
|
||||||
|
"supported_targets": [
|
||||||
|
"esp32",
|
||||||
|
"esp32s2",
|
||||||
|
"esp32s3",
|
||||||
|
"esp32c3",
|
||||||
|
"esp32c2",
|
||||||
|
"esp32c6",
|
||||||
|
"esp32c5",
|
||||||
|
"esp32h2",
|
||||||
|
"esp32p4",
|
||||||
|
"esp32c61",
|
||||||
|
"esp32h21"
|
||||||
|
],
|
||||||
|
"tool_info_file": "esp-clang/esp-clang-libs.info",
|
||||||
|
"version_cmd": [],
|
||||||
|
"version_regex": "([0-9a-zA-Z\\.\\-_]+)",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"linux-amd64": {
|
||||||
|
"sha256": "c13b8a731beec0c2af56f94073ca17202c9e5047de4c6e61f5e3ed319d231962",
|
||||||
|
"size": 76164612,
|
||||||
|
"url": "https://github.com/espressif/llvm-project/releases/download/esp-19.1.2_20250312/libs-clang-esp-19.1.2_20250312-x86_64-linux-gnu.tar.xz"
|
||||||
|
},
|
||||||
|
"linux-arm64": {
|
||||||
|
"sha256": "dcf356d2a12eaf9660aa5e91cd70df14486d4bd45f47a8025327255b2fe3ece8",
|
||||||
|
"size": 69938392,
|
||||||
|
"url": "https://github.com/espressif/llvm-project/releases/download/esp-19.1.2_20250312/libs-clang-esp-19.1.2_20250312-aarch64-linux-gnu.tar.xz"
|
||||||
|
},
|
||||||
|
"linux-armhf": {
|
||||||
|
"sha256": "e9e110841ffdd43c7fcc57de24f501eec917a02e54f6dbf3a2069fed1017f8a8",
|
||||||
|
"size": 72698812,
|
||||||
|
"url": "https://github.com/espressif/llvm-project/releases/download/esp-19.1.2_20250312/libs-clang-esp-19.1.2_20250312-arm-linux-gnueabihf.tar.xz"
|
||||||
|
},
|
||||||
|
"macos": {
|
||||||
|
"sha256": "0ac4cf2340e766a240ae40519f404fceaea4262d5ab89292aa3a4118e6402492",
|
||||||
|
"size": 58104496,
|
||||||
|
"url": "https://github.com/espressif/llvm-project/releases/download/esp-19.1.2_20250312/libs-clang-esp-19.1.2_20250312-x86_64-apple-darwin.tar.xz"
|
||||||
|
},
|
||||||
|
"macos-arm64": {
|
||||||
|
"sha256": "d723ce5ae431b44305c888c989e7f405446a23c13f179edc1b6939f9ba437498",
|
||||||
|
"size": 48707440,
|
||||||
|
"url": "https://github.com/espressif/llvm-project/releases/download/esp-19.1.2_20250312/libs-clang-esp-19.1.2_20250312-aarch64-apple-darwin.tar.xz"
|
||||||
|
},
|
||||||
|
"name": "esp-19.1.2_20250312",
|
||||||
|
"status": "recommended",
|
||||||
|
"win64": {
|
||||||
|
"sha256": "29e5c945f601b85dd88c29bfabfd8c592d8064e3aba01d946e0ff475e5810c17",
|
||||||
|
"size": 59681772,
|
||||||
|
"url": "https://github.com/espressif/llvm-project/releases/download/esp-19.1.2_20250312/libs-clang-esp-19.1.2_20250312-x86_64-w64-mingw32.tar.xz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Toolchain for 32-bit RISC-V based on GCC",
|
"description": "Toolchain for 32-bit RISC-V based on GCC",
|
||||||
"export_paths": [
|
"export_paths": [
|
||||||
@@ -985,5 +1046,5 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version": 2
|
"version": 3
|
||||||
}
|
}
|
||||||
|
@@ -72,6 +72,10 @@
|
|||||||
"description": "If given, this will be used as substitute expression for the regex defined in version_regex, to obtain the version string. Not specifying this is equivalent to setting it to '\\1' (i.e. return the first capture group).",
|
"description": "If given, this will be used as substitute expression for the regex defined in version_regex, to obtain the version string. Not specifying this is equivalent to setting it to '\\1' (i.e. return the first capture group).",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"tool_info_file": {
|
||||||
|
"description": "Tools info file path. Relative to tool install folder. If present tool version will be read from it instead of invoking the binary.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"strip_container_dirs": {
|
"strip_container_dirs": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "If specified, this number of top directory levels will removed when extracting. E.g. if strip_container_dirs=2, archive path a/b/c/d.txt will be extracted as c/d.txt"
|
"description": "If specified, this number of top directory levels will removed when extracting. E.g. if strip_container_dirs=2, archive path a/b/c/d.txt will be extracted as c/d.txt"
|
||||||
@@ -286,5 +290,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"$comment": "Condition verifying that version <=2 of tools.json must not contain 'tool_info_file' keyword in any of #/definitions/toolInfo properties.",
|
||||||
|
"if": {
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"maximum": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"properties": {
|
||||||
|
"tools": {
|
||||||
|
"items": {
|
||||||
|
"not": {
|
||||||
|
"required": [
|
||||||
|
"tool_info_file"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user