diff --git a/docs/en/api-guides/tools/idf-py.rst b/docs/en/api-guides/tools/idf-py.rst index 850ed40e19..917286147f 100644 --- a/docs/en/api-guides/tools/idf-py.rst +++ b/docs/en/api-guides/tools/idf-py.rst @@ -216,7 +216,7 @@ This command prints size information per source file in the project. Options ^^^^^^^ -- ``--format`` specifies the output format with available options: ``text``, ``csv``, ``json``, default being ``text``. +- ``--format`` specifies the output format with available options: ``text``, ``csv``, ``json2``, ``tree``, ``raw``, default being ``text``. - ``--output-file`` optionally specifies the name of the file to print the command output to instead of the standard output. Reconfigure the Project: ``reconfigure`` diff --git a/docs/en/migration-guides/release-6.x/6.0/tools.rst b/docs/en/migration-guides/release-6.x/6.0/tools.rst index 83ae179f71..723ed6bdde 100644 --- a/docs/en/migration-guides/release-6.x/6.0/tools.rst +++ b/docs/en/migration-guides/release-6.x/6.0/tools.rst @@ -14,9 +14,9 @@ For example, `Python 3.13 is not supported `_. For an example of migrating from Catch2 2.x to Catch2 3.x, see commit 79a2c15477dc327550ff46a64ee0f8b4679cc417. + +Dropped ``idf.py size --legacy`` option +--------------------------------------- + +The ``--legacy`` argument for ``idf.py size`` has been removed, as the legacy implementation is no longer supported. The ``ESP_IDF_SIZE_LEGACY`` environment variable also no longer has any effect. To continue using the legacy option, use ESP-IDF version 5.5 or lower. For ESP-IDF v6.0 and later, simply replace ``idf.py size --legacy`` with ``idf.py size``. If you encounter esp-idf-size version problems, please run the install script to update to the correct version. + +Changed ``idf.py size --format json`` to ``--format json2`` +----------------------------------------------------------- + +The ``--format json`` option has been replaced with ``--format json2``. The ``json2`` format provides better structure with explicit ``total``, ``used``, and ``free`` fields for each memory region, and detailed breakdown in the ``parts`` section. To migrate, replace ``idf.py size --format json`` with ``idf.py size --format json2``. + +- **Old format (json)**: Flat structure with direct memory type fields like ``"dram_data": 9192, "iram_text": 43295``. +- **New format (json2)**: Hierarchical structure with a ``layout`` array containing memory regions: + + .. code-block:: json + + { + "version": "1.1", + "layout": [ + { + "name": "DRAM", + "total": 180736, + "used": 11344, + "free": 169392, + "parts": { + ".data": {"size": 9192}, + ".bss": {"size": 2152} + } + } + ] + } + diff --git a/docs/zh_CN/api-guides/tools/idf-py.rst b/docs/zh_CN/api-guides/tools/idf-py.rst index 0cb3973f2d..a00bae8a4d 100644 --- a/docs/zh_CN/api-guides/tools/idf-py.rst +++ b/docs/zh_CN/api-guides/tools/idf-py.rst @@ -216,7 +216,7 @@ uf2 二进制文件也可以通过 :ref:`idf.py uf2 ` 生 选项 ^^^^^^^ -- ``--format`` 指定输出格式,可输出 ``text``、``csv``、 ``json`` 格式,默认格式为 ``text``。 +- ``--format`` 指定输出格式,可输出 ``text``、``csv``、``json2``、``tree``、``raw`` 格式,默认格式为 ``text``。 - ``--output-file`` 可选参数,可以指定命令输出文件的文件名,而非标准输出。 重新配置工程:``reconfigure`` diff --git a/docs/zh_CN/migration-guides/release-6.x/6.0/tools.rst b/docs/zh_CN/migration-guides/release-6.x/6.0/tools.rst index 819f20ec17..ac390d31be 100644 --- a/docs/zh_CN/migration-guides/release-6.x/6.0/tools.rst +++ b/docs/zh_CN/migration-guides/release-6.x/6.0/tools.rst @@ -14,9 +14,9 @@ gdbgui 自 v0.14 起不再支持 Windows 操作系统。由于其他兼容性问题,Windows 下需使用 Python 3.10,并配合特定依赖版本。可通过以下命令安装已知可用的 gdbgui 及其所需版本的依赖: -```bash -pipx install "gdbgui==0.13.2.0" "pygdbmi<=0.9.0.2" "python-socketio<5" "jinja2<3.1" "itsdangerous<2.1" -``` +.. code-block:: bash + + pipx install "gdbgui==0.13.2.0" "pygdbmi<=0.9.0.2" "python-socketio<5" "jinja2<3.1" "itsdangerous<2.1" 如果操作系统为 Linux 或 macOS,可以使用 Python 3.11 或 3.12 以及 gdbgui v0.15.2.0。 @@ -53,3 +53,35 @@ CMake 版本升级 如果无法升级操作系统,可以使用以下命令安装推荐的 CMake 版本:``./tools/idf_tools.py install cmake``。 此变更影响所有使用系统自带 CMake 或自定义 CMake 的 ESP-IDF 用户。 + +移除 ``idf.py size --legacy`` 选项 +------------------------------------- + +``idf.py size`` 命令的 ``--legacy`` 参数已被移除,因为旧版实现已不再受支持。``ESP_IDF_SIZE_LEGACY`` 环境变量也随之失效。如需继续使用旧版选项,请使用 ESP-IDF 5.5 或更早版本。对于 ESP-IDF v6.0 及更高版本,请直接将 ``idf.py size --legacy`` 替换为 ``idf.py size``。若遇到 esp-idf-size 版本问题,请运行安装脚本更新至正确版本。 + +更改 ``idf.py size --format json`` 为 ``--format json2`` +------------------------------------------------------------ + +``--format json`` 选项已替换为 ``--format json2``。``json2`` 格式提供了更完善的结构,为每个内存区域提供明确的 ``total``、``used`` 和 ``free`` 字段,并在 ``parts`` 部分提供详细分类。迁移时,请将 ``idf.py size --format json`` 替换为 ``idf.py size --format json2``。 + +- **旧格式 (json)**:扁平结构,内存类型字段直接列出,如 ``"dram_data": 9192, "iram_text": 43295``。 +- **新格式 (json2)**:分层结构,包含一个 ``layout`` 数组来表示内存区域: + + .. code-block:: json + + { + "version": "1.1", + "layout": [ + { + "name": "DRAM", + "total": 180736, + "used": 11344, + "free": 169392, + "parts": { + ".data": {"size": 9192}, + ".bss": {"size": 2152} + } + } + ] + } + diff --git a/tools/cmake/run_size_tool.cmake b/tools/cmake/run_size_tool.cmake index df8108b57f..0be2d369c4 100644 --- a/tools/cmake/run_size_tool.cmake +++ b/tools/cmake/run_size_tool.cmake @@ -16,8 +16,8 @@ if(NOT DEFINED ENV{SIZE_OUTPUT_FORMAT} OR "$ENV{SIZE_OUTPUT_FORMAT}" STREQUAL "d # Format not passed to "idf.py size" explicitly, or this target was invoked # from make/ninja directly (without idf.py) if(DEFINED OUTPUT_JSON AND OUTPUT_JSON) - # honor the legacy OUTPUT_JSON variable, if set - list(APPEND IDF_SIZE_CMD "--format=json") + # honor the legacy OUTPUT_JSON variable, if set (use json2 format as json is no longer supported) + list(APPEND IDF_SIZE_CMD "--format=json2") endif() elseif(DEFINED ENV{SIZE_OUTPUT_FORMAT}) # specific format was requested diff --git a/tools/idf_py_actions/core_ext.py b/tools/idf_py_actions/core_ext.py index 93d34461a5..5762e0d213 100644 --- a/tools/idf_py_actions/core_ext.py +++ b/tools/idf_py_actions/core_ext.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import fnmatch import glob @@ -10,9 +10,6 @@ import shutil import subprocess import sys from typing import Any -from typing import Dict -from typing import List -from typing import Optional from urllib.error import URLError from urllib.request import Request from urllib.request import urlopen @@ -20,25 +17,25 @@ from webbrowser import open_new_tab import click from click.core import Context + from idf_py_actions.constants import GENERATORS from idf_py_actions.constants import PREVIEW_TARGETS from idf_py_actions.constants import SUPPORTED_TARGETS from idf_py_actions.constants import URL_TO_DOC from idf_py_actions.errors import FatalError from idf_py_actions.global_options import global_options +from idf_py_actions.tools import PropertyDict +from idf_py_actions.tools import TargetChoice from idf_py_actions.tools import ensure_build_directory from idf_py_actions.tools import generate_hints from idf_py_actions.tools import get_target from idf_py_actions.tools import idf_version from idf_py_actions.tools import merge_action_lists -from idf_py_actions.tools import print_warning -from idf_py_actions.tools import PropertyDict from idf_py_actions.tools import run_target -from idf_py_actions.tools import TargetChoice from idf_py_actions.tools import yellow_print -def action_extensions(base_actions: Dict, project_path: str) -> Any: +def action_extensions(base_actions: dict, project_path: str) -> Any: def build_target(target_name: str, ctx: Context, args: PropertyDict) -> None: """ Execute the target build system to build target 'target_name' @@ -49,8 +46,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: ensure_build_directory(args, ctx.info_name) run_target(target_name, args, force_progression=GENERATORS[args.generator].get('force_progression', False)) - def size_target(target_name: str, ctx: Context, args: PropertyDict, output_format: str, - output_file: str, diff_map_file: str, legacy: bool) -> None: + def size_target( + target_name: str, ctx: Context, args: PropertyDict, output_format: str, output_file: str, diff_map_file: str + ) -> None: """ Builds the app and then executes a size-related target passed in 'target_name'. `tool_error_handler` handler is used to suppress errors during the build, @@ -61,29 +59,11 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: for hint in generate_hints(stdout, stderr): yellow_print(hint) - env: Dict[str, Any] = {} - - if not legacy and output_format != 'json': - try: - import esp_idf_size.ng # noqa: F401 - except ImportError: - print_warning('WARNING: refactored esp-idf-size not installed, using legacy mode') - legacy = True - else: - # Legacy mode is used only when explicitly requested with --legacy option - # or when "--format json" option is specified. Here we enable the - # esp-idf-size refactored version with ESP_IDF_SIZE_NG env. variable. - env['ESP_IDF_SIZE_NG'] = '1' - # ESP_IDF_SIZE_FORCE_TERMINAL is set to force terminal control codes even - # if stdout is not attached to terminal. This is set to pass color codes - # from esp-idf-size to idf.py. - env['ESP_IDF_SIZE_FORCE_TERMINAL'] = '1' - - if legacy and output_format in ['json2', 'raw', 'tree']: - # These formats are supported in new version only. - # We would get error from the esp-idf-size anyway, so print error early. - raise FatalError(f'Legacy esp-idf-size does not support {output_format} format') + env: dict[str, Any] = {} + # Enforce NG mode for esp-idf-size v 1.x. After v 2.x is fully incorporated, 'ESP_IDF_SIZE_NG' can be removed. + env['ESP_IDF_SIZE_NG'] = '1' + env['ESP_IDF_SIZE_FORCE_TERMINAL'] = '1' env['SIZE_OUTPUT_FORMAT'] = output_format if output_file: env['SIZE_OUTPUT_FILE'] = os.path.abspath(output_file) @@ -93,7 +73,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: # The diff_map_file argument is a directory. Try to look for the map # file directly in it, in case it's a build directory or in one level below # if it's a project directory. - files = glob.glob(os.path.join(diff_map_file, '*.map')) or glob.glob(os.path.join(diff_map_file, '*/*.map')) + files = glob.glob(os.path.join(diff_map_file, '*.map')) or glob.glob( + os.path.join(diff_map_file, '*/*.map') + ) if not files: raise FatalError(f'No diff map file found in {diff_map_file} directory') if len(files) > 1: @@ -104,8 +86,12 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: env['SIZE_DIFF_FILE'] = diff_map_file ensure_build_directory(args, ctx.info_name) - run_target('all', args, force_progression=GENERATORS[args.generator].get('force_progression', False), - custom_error_handler=tool_error_handler) + run_target( + 'all', + args, + force_progression=GENERATORS[args.generator].get('force_progression', False), + custom_error_handler=tool_error_handler, + ) run_target(target_name, args, env=env) def list_build_system_targets(target_name: str, ctx: Context, args: PropertyDict) -> None: @@ -121,13 +107,15 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: try: import curses # noqa: F401 except ImportError: - raise FatalError('\n'.join( - ['', "menuconfig failed to import the standard Python 'curses' library.", - 'Please re-run the install script which might be able to fix the issue.'])) - if sys.version_info[0] < 3: - # The subprocess lib cannot accept environment variables as "unicode". - # This encoding step is required only in Python 2. - style = style.encode(sys.getfilesystemencoding() or 'utf-8') + raise FatalError( + '\n'.join( + [ + '', + "menuconfig failed to import the standard Python 'curses' library.", + 'Please re-run the install script which might be able to fix the issue.', + ] + ) + ) os.environ['MENUCONFIG_STYLE'] = style args.no_hints = True build_target(target_name, ctx, args) @@ -151,15 +139,16 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: except Exception: if target_name in ['clang-check', 'clang-html-report']: - raise FatalError('command "{}" requires an additional plugin "pyclang". ' - 'Please install it via "pip install --upgrade pyclang"'.format(target_name)) + raise FatalError( + f'command "{target_name}" requires an additional plugin "pyclang". ' + 'Please install it via "pip install --upgrade pyclang"' + ) - raise FatalError( - 'command "%s" is not known to idf.py and is not a %s target' % (target_name, args.generator)) + raise FatalError(f'command "{target_name}" is not known to idf.py and is not a {args.generator} target') run_target(target_name, args) - def verbose_callback(ctx: Context, param: List, value: str) -> Optional[str]: + def verbose_callback(ctx: Context, param: list, value: str) -> str | None: if not value or ctx.resilient_parsing: return None @@ -170,36 +159,39 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: def clean(action: str, ctx: Context, args: PropertyDict) -> None: if not os.path.isdir(args.build_dir): - print("Build directory '%s' not found. Nothing to clean." % args.build_dir) + print(f"Build directory '{args.build_dir}' not found. Nothing to clean.") return build_target('clean', ctx, args) def fullclean(action: str, ctx: Context, args: PropertyDict) -> None: build_dir = args.build_dir if not os.path.isdir(build_dir): - print("Build directory '%s' not found. Nothing to clean." % build_dir) + print(f"Build directory '{build_dir}' not found. Nothing to clean.") return if len(os.listdir(build_dir)) == 0: - print("Build directory '%s' is empty. Nothing to clean." % build_dir) + print(f"Build directory '{build_dir}' is empty. Nothing to clean.") return if not os.path.exists(os.path.join(build_dir, 'CMakeCache.txt')): raise FatalError( - "Directory '%s' doesn't seem to be a CMake build directory. Refusing to automatically " - "delete files in this directory. Delete the directory manually to 'clean' it." % build_dir) + f"Directory '{build_dir}' doesn't seem to be a CMake build directory. Refusing to automatically " + "delete files in this directory. Delete the directory manually to 'clean' it." + ) red_flags = ['CMakeLists.txt', '.git', '.svn'] for red in red_flags: red = os.path.join(build_dir, red) if os.path.exists(red): raise FatalError( - "Refusing to automatically delete files in directory containing '%s'. Delete files manually if you're sure." - % red) + f"Refusing to automatically delete files in directory containing '{red}'. " + "Delete files manually if you're sure." + ) if args.verbose and len(build_dir) > 1: - print('The following symlinks were identified and removed:\n%s' % '\n'.join(build_dir)) + symlinks_list = '\n'.join(build_dir) + print(f'The following symlinks were identified and removed:\n{symlinks_list}') for f in os.listdir(build_dir): # TODO: once we are Python 3 only, this can be os.scandir() f = os.path.join(build_dir, f) if args.verbose: - print('Removing: %s' % f) + print(f'Removing: {f}') if os.path.isdir(f): shutil.rmtree(f) else: @@ -211,19 +203,20 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: if d == '__pycache__': dir_to_delete = os.path.join(root, d) if args.verbose: - print('Removing: %s' % dir_to_delete) + print(f'Removing: {dir_to_delete}') shutil.rmtree(dir_to_delete) for filename in fnmatch.filter(filenames, '*.py[co]'): file_to_delete = os.path.join(root, filename) if args.verbose: - print('Removing: %s' % file_to_delete) + print(f'Removing: {file_to_delete}') os.remove(file_to_delete) def set_target(action: str, ctx: Context, args: PropertyDict, idf_target: str) -> None: - if (not args['preview'] and idf_target in PREVIEW_TARGETS): + if not args['preview'] and idf_target in PREVIEW_TARGETS: raise FatalError( - "%s is still in preview. You have to append '--preview' option after idf.py to use any preview feature." - % idf_target) + f"{idf_target} is still in preview. You have to append '--preview' option after " + 'idf.py to use any preview feature.' + ) args.define_cache_entry.append('IDF_TARGET=' + idf_target) print(f'Set Target to: {idf_target}, new sdkconfig will be created.') env = {'_IDF_PY_SET_TARGET_ACTION': '1'} @@ -232,12 +225,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: def reconfigure(action: str, ctx: Context, args: PropertyDict) -> None: ensure_build_directory(args, ctx.info_name, True) - def validate_root_options(ctx: Context, args: PropertyDict, tasks: List) -> None: + def validate_root_options(ctx: Context, args: PropertyDict, tasks: list) -> None: args.project_dir = os.path.realpath(args.project_dir) if args.build_dir is not None and args.project_dir == os.path.realpath(args.build_dir): raise FatalError( 'Setting the build directory to the project directory is not supported. Suggest dropping ' - "--build-dir option, the default is a 'build' subdirectory inside the project directory.") + "--build-dir option, the default is a 'build' subdirectory inside the project directory." + ) if args.build_dir is None: args.build_dir = os.path.join(args.project_dir, 'build') args.build_dir = os.path.realpath(args.build_dir) @@ -251,10 +245,10 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: if not version: raise FatalError('ESP-IDF version cannot be determined') - print('ESP-IDF %s' % version) + print(f'ESP-IDF {version}') sys.exit(0) - def list_targets_callback(ctx: Context, param: List, value: int) -> None: + def list_targets_callback(ctx: Context, param: list, value: int) -> None: if not value or ctx.resilient_parsing: return @@ -267,7 +261,16 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: sys.exit(0) - def show_docs(action: str, ctx: Context, args: PropertyDict, no_browser: bool, language: str, starting_page: str, version: str, target: str) -> None: + def show_docs( + action: str, + ctx: Context, + args: PropertyDict, + no_browser: bool, + language: str, + starting_page: str, + version: str, + target: str, + ) -> None: if language == 'cn': language = 'zh_CN' if not version: @@ -288,7 +291,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: except URLError: print("We can't check the link's functionality because you don't have an internet connection") if redirect_link: - print('Target', target, 'doesn\'t exist for version', version) + print('Target', target, "doesn't exist for version", version) link = '/'.join([URL_TO_DOC, language, version, starting_page or '']) if not no_browser: print('Opening documentation in the default browser:') @@ -306,7 +309,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: language = 'en' return language - def help_and_exit(action: str, ctx: Context, param: List, json_option: bool, add_options: bool) -> None: + def help_and_exit(action: str, ctx: Context, param: list, json_option: bool, add_options: bool) -> None: if json_option: output_dict = {} output_dict['target'] = get_target(param.project_dir) # type: ignore @@ -355,8 +358,10 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: }, { 'names': ['-w/-n', '--cmake-warn-uninitialized/--no-warnings'], - 'help': ('Enable CMake uninitialized variable warnings for CMake files inside the project directory. ' - "(--no-warnings is now the default, and doesn't need to be specified.)"), + 'help': ( + 'Enable CMake uninitialized variable warnings for CMake files inside the project directory. ' + "(--no-warnings is now the default, and doesn't need to be specified.)" + ), 'envvar': 'IDF_CMAKE_WARN_UNINITIALIZED', 'is_flag': True, 'default': False, @@ -399,8 +404,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'names': ['--no-hints'], 'help': 'Disable hints on how to resolve errors and logging.', 'is_flag': True, - 'default': False - } + 'default': False, + }, ], 'global_action_callbacks': [validate_root_options], } @@ -408,19 +413,25 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: # 'default' is introduced instead of simply setting 'text' as the default so that we know # if the user explicitly specified the format or not. If the format is not specified, then # the legacy OUTPUT_JSON CMake variable will be taken into account. - size_options = [{'names': ['--format', 'output_format'], - 'type': click.Choice(['default', 'text', 'csv', 'json', 'json2', 'tree', 'raw']), - 'help': 'Specify output format: text (same as "default"), csv, json, json2, tree or raw.', - 'default': 'default'}, - {'names': ['--legacy', '-l'], - 'is_flag': True, - 'default': os.environ.get('ESP_IDF_SIZE_LEGACY', '0') == '1', - 'help': 'Use legacy esp-idf-size version'}, - {'names': ['--diff', 'diff_map_file'], - 'help': ('Show the differences in comparison with another project. ' - 'Argument can be map file or project directory.')}, - {'names': ['--output-file', 'output_file'], - 'help': 'Print output to the specified file instead of to the standard output'}] + size_options = [ + { + 'names': ['--format', 'output_format'], + 'type': click.Choice(['default', 'text', 'csv', 'json2', 'tree', 'raw']), + 'help': 'Specify output format: text (same as "default"), csv, json2, tree or raw.', + 'default': 'default', + }, + { + 'names': ['--diff', 'diff_map_file'], + 'help': ( + 'Show the differences in comparison with another project. ' + 'Argument can be map file or project directory.' + ), + }, + { + 'names': ['--output-file', 'output_file'], + 'help': 'Print output to the specified file instead of to the standard output', + }, + ] build_actions = { 'actions': { @@ -437,7 +448,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'and generate build files for the main build tool.\n\n' '3. Run the main build tool (Ninja or GNU Make). ' 'By default, the build tool is automatically detected ' - 'but it can be explicitly set by passing the -G option to idf.py.\n\n'), + 'but it can be explicitly set by passing the -G option to idf.py.\n\n' + ), 'options': global_options, 'order_dependencies': [ 'reconfigure', @@ -449,7 +461,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'menuconfig': { 'callback': menuconfig, 'help': 'Run "menuconfig" project configuration tool.', - 'options': global_options + [ + 'options': global_options + + [ { 'names': ['--style', '--color-scheme', 'style'], 'help': ( @@ -460,7 +473,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: '- aquatic - a blue theme.\n\n' 'It is possible to customize these themes further' ' as it is described in the Color schemes section of the kconfiglib documentation.\n' - 'The default value is \"aquatic\".'), + 'The default value is "aquatic".' + ), 'envvar': 'MENUCONFIG_STYLE', 'default': 'aquatic', } @@ -499,13 +513,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: }, 'efuse-common-table': { 'callback': build_target, - 'help': 'Generate C-source for IDF\'s eFuse fields.', + 'help': "Generate C-source for IDF's eFuse fields.", 'order_dependencies': ['reconfigure'], 'options': global_options, }, 'efuse-custom-table': { 'callback': build_target, - 'help': 'Generate C-source for user\'s eFuse fields.', + 'help': "Generate C-source for user's eFuse fields.", 'order_dependencies': ['reconfigure'], 'options': global_options, }, @@ -534,41 +548,37 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'callback': show_docs, 'help': 'Open web browser with documentation for ESP-IDF', 'options': [ - { - 'names': ['--no-browser', '-nb'], - 'is_flag': True, - 'help': 'Don\'t open browser.' - }, + {'names': ['--no-browser', '-nb'], 'is_flag': True, 'help': "Don't open browser."}, { 'names': ['--language', '-l'], 'default': get_default_language(), 'type': click.Choice(['en', 'zh_CN', 'cn']), - 'help': 'Documentation language. Your system language by default (en or cn)' + 'help': 'Documentation language. Your system language by default (en or cn)', }, { 'names': ['--starting-page', '-sp'], - 'help': 'Documentation page (get-started, api-reference etc).' - }, - { - 'names': ['--version', '-v'], - 'help': 'Version of ESP-IDF.' + 'help': 'Documentation page (get-started, api-reference etc).', }, + {'names': ['--version', '-v'], 'help': 'Version of ESP-IDF.'}, { 'names': ['--target', '-t'], 'type': TargetChoice(SUPPORTED_TARGETS + PREVIEW_TARGETS + ['']), - 'help': 'Chip target.' - } - ] + 'help': 'Chip target.', + }, + ], }, 'save-defconfig': { 'callback': save_defconfig, 'help': 'Generate a sdkconfig.defaults with options different from the default ones', - 'options': global_options + [{ - 'names': ['--add-menu-labels'], - 'is_flag': True, - 'help': 'Add menu labels to minimal config.', - }] - } + 'options': global_options + + [ + { + 'names': ['--add-menu-labels'], + 'is_flag': True, + 'help': 'Add menu labels to minimal config.', + } + ], + }, } } @@ -582,8 +592,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: "This isn't necessary during normal usage, " 'but can be useful after adding/removing files from the source tree, ' 'or when modifying CMake cache variables. ' - "For example, \"idf.py -DNAME='VALUE' reconfigure\" " - 'can be used to set variable "NAME" in CMake cache to value "VALUE".'), + 'For example, "idf.py -DNAME=\'VALUE\' reconfigure" ' + 'can be used to set variable "NAME" in CMake cache to value "VALUE".' + ), 'options': global_options, 'order_dependencies': ['menuconfig', 'fullclean'], }, @@ -594,8 +605,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'Set the chip target to build. This will remove the ' 'existing sdkconfig file and corresponding CMakeCache and ' 'create new ones according to the new target.\nFor example, ' - "\"idf.py set-target esp32\" will select esp32 as the new chip " - 'target.'), + '"idf.py set-target esp32" will select esp32 as the new chip ' + 'target.' + ), 'arguments': [ { 'names': ['idf-target'], @@ -612,7 +624,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'Delete build output files from the build directory, ' "forcing a 'full rebuild' the next time " "the project is built. Cleaning doesn't delete " - 'CMake configuration output and some other files'), + 'CMake configuration output and some other files' + ), 'order_dependencies': ['fullclean'], }, 'fullclean': { @@ -625,7 +638,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'CMake will configure it from scratch. ' 'Note that this option recursively deletes all files ' 'in the build directory, so use with care.' - 'Project configuration is not deleted.') + 'Project configuration is not deleted.' + ), }, 'python-clean': { 'callback': python_clean, @@ -633,7 +647,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'help': ( 'Delete generated Python byte code from the IDF directory ' 'which may cause issues when switching between IDF and Python versions. ' - 'It is advised to run this target after switching versions.') + 'It is advised to run this target after switching versions.' + ), }, } } @@ -648,13 +663,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: { 'names': ['--json', 'json_option'], 'is_flag': True, - 'help': 'Print out actions in machine-readable format for selected target.' + 'help': 'Print out actions in machine-readable format for selected target.', }, { 'names': ['--add-options'], 'is_flag': True, - 'help': 'Add options about actions to machine-readable format.' - } + 'help': 'Add options about actions to machine-readable format.', + }, ], } } diff --git a/tools/idf_size.py b/tools/idf_size.py index a3cb75c7da..743ab98525 100755 --- a/tools/idf_size.py +++ b/tools/idf_size.py @@ -1,49 +1,21 @@ #!/usr/bin/env python # -# SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: Apache-2.0 # -import argparse import os import subprocess import sys if __name__ == '__main__': - # Here the argparse is used only to "peek" into arguments if - # legacy version is requested or if old json format is specified. - # In these two cases the esp_idf_size legacy version is spawned. - parser = argparse.ArgumentParser(add_help=False) - # Make the --format arg optional, so this argparse instance does not - # fail with an error and the proper underlying help is displayed. - # Note that exit_on_error is supported from python3.9, so this is - # a workaround how to make sure that the args parsing doesn't fail here if idf_size.py - # is invoked e.g. without specifying the format, like "idf_size.py --format". - parser.add_argument('--format', nargs='?') - parser.add_argument('-l', '--legacy', action='store_true', default=os.environ.get('ESP_IDF_SIZE_LEGACY', '0') == '1') + try: + import esp_idf_size # noqa: F401 - # The sys.argv is parsed with "exit_on_error", but the argparse.ArgumentError - # exception should never occur, because unknown args should be put into - # the rest variable, since the parse_known_args() method is used. - args, rest = parser.parse_known_args() + # Enforce NG mode for esp-idf-size v 1.x. After v 2.x is fully incorporated, 'ESP_IDF_SIZE_NG' can be removed. + os.environ['ESP_IDF_SIZE_NG'] = '1' + except ImportError: + print('WARNING: esp-idf-size not installed, please run the install script to install it', file=sys.stderr) + raise SystemExit(1) - if not args.legacy and args.format != 'json': - # By default start the refactored version, unless legacy version is explicitly requested with - # -l/--legacy option or if old json format is specified. - try: - import esp_idf_size.ng # noqa: F401 - except ImportError: - print('warning: refactored esp-idf-size not installed, using legacy mode', file=sys.stderr) - args.legacy = True - else: - os.environ['ESP_IDF_SIZE_NG'] = '1' - if not rest or '-h' in rest or '--help' in rest: - print(('Note: legacy esp_idf_size version can be invoked by specifying the -l/--legacy ' - 'option or by setting the ESP_IDF_SIZE_LEGACY environment variable. Additionally, the ' - 'legacy version is automatically employed when the JSON format is specified for ' - 'compatibility with previous versions.')) - - if args.format is not None: - rest = ['--format', args.format] + rest - - sys.exit(subprocess.run([sys.executable, '-m', 'esp_idf_size'] + rest).returncode) + sys.exit(subprocess.run([sys.executable, '-m', 'esp_idf_size'] + sys.argv[1:]).returncode)