From db6b31044780124e41a8ad2f1179708a90b6ce3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Neboj=C5=A1a=20Cvetkovi=C4=87?= Date: Mon, 20 Jul 2026 16:02:48 +0100 Subject: [PATCH 1/2] feat(tools): add -j/--jobs option to idf.py Add a global -j/--jobs option to idf.py that sets the number of parallel build jobs passed to the underlying build tool. Previously parallelism was only configurable via the IDF_PY_BUILD_JOBS environment variable, and only for the Ninja generator. The option applies to both Ninja and Make and defaults to IDF_PY_BUILD_JOBS when not given, so the environment variable keeps working as before. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/en/api-guides/build-system.rst | 8 +++++++- docs/zh_CN/api-guides/build-system.rst | 8 +++++++- tools/idf_py_actions/constants.py | 4 +++- tools/idf_py_actions/core_ext.py | 7 +++++++ tools/idf_py_actions/global_options.py | 2 +- tools/idf_py_actions/tools.py | 17 ++++++----------- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index bec630be8b0..738fe2f02a6 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -77,7 +77,13 @@ In the above list, the ``cmake`` command configures the project and generates bu It's not necessary to run ``cmake`` more than once. After the first build, you only need to run ``ninja`` each time. ``ninja`` will automatically re-invoke ``cmake`` if the project needs reconfiguration. -When using ``idf.py`` with the Ninja generator, you can cap the number of parallel build jobs by setting the ``IDF_PY_BUILD_JOBS`` environment variable. For example: +You can control the number of parallel build jobs passed to the underlying build tool (Ninja or Make) with the ``-j``/``--jobs`` option of ``idf.py``. For example: + +.. code-block:: bash + + idf.py -j 6 build + +The same value can be set with the ``IDF_PY_BUILD_JOBS`` environment variable, which is used as the default when ``-j``/``--jobs`` is not given: .. code-block:: bash diff --git a/docs/zh_CN/api-guides/build-system.rst b/docs/zh_CN/api-guides/build-system.rst index 2f41f4d8971..e09eacff7e3 100644 --- a/docs/zh_CN/api-guides/build-system.rst +++ b/docs/zh_CN/api-guides/build-system.rst @@ -77,7 +77,13 @@ idf.py 没有必要多次运行 ``cmake``。第一次构建后,往后每次只需运行 ``ninja`` 即可。如果项目需要重新配置,``ninja`` 会自动重新调用 ``cmake``。 -使用 Ninja 生成器配合 ``idf.py`` 时,可以通过设置环境变量 ``IDF_PY_BUILD_JOBS`` 来限制并行构建任务数。例如: +使用 ``idf.py`` 时,可以通过 ``-j``/``--jobs`` 选项来控制传递给底层构建工具(Ninja 或 Make)的并行构建任务数。例如: + +.. code-block:: bash + + idf.py -j 6 build + +也可以通过设置环境变量 ``IDF_PY_BUILD_JOBS`` 来指定该值,当未提供 ``-j``/``--jobs`` 时,该环境变量将作为默认值使用: .. code-block:: bash diff --git a/tools/idf_py_actions/constants.py b/tools/idf_py_actions/constants.py index 3c97b50affe..b21b5a4aba0 100644 --- a/tools/idf_py_actions/constants.py +++ b/tools/idf_py_actions/constants.py @@ -29,7 +29,9 @@ GENERATORS: dict[str, str | dict | list] = collections.OrderedDict( if os.name != 'nt': MAKE_CMD = 'gmake' if platform.system() == 'FreeBSD' else 'make' GENERATORS['Unix Makefiles'] = { - 'command': [MAKE_CMD, '-j', str(multiprocessing.cpu_count() + 2)], + # Make, unlike Ninja, does not parallelize by default; run_target() applies this as -j. + 'default_jobs': multiprocessing.cpu_count() + 2, + 'command': [MAKE_CMD], 'version': [MAKE_CMD, '--version'], 'dry_run': [MAKE_CMD, '-n'], 'verbose_flag': 'VERBOSE=1', diff --git a/tools/idf_py_actions/core_ext.py b/tools/idf_py_actions/core_ext.py index 24c26d9d740..08a83b25bfa 100644 --- a/tools/idf_py_actions/core_ext.py +++ b/tools/idf_py_actions/core_ext.py @@ -537,6 +537,13 @@ def action_extensions(base_actions: dict, project_path: str) -> Any: 'help': 'CMake generator.', 'type': click.Choice(GENERATORS.keys()), }, + { + 'names': ['-j', '--jobs'], + 'help': 'Number of parallel build jobs passed to the build tool (Ninja or Make).', + 'envvar': 'IDF_PY_BUILD_JOBS', + 'type': click.IntRange(min=1), + 'default': None, + }, { 'names': ['--dry-run'], 'help': "Only process arguments, but don't execute actions.", diff --git a/tools/idf_py_actions/global_options.py b/tools/idf_py_actions/global_options.py index fecc40042e9..3dcf2894566 100644 --- a/tools/idf_py_actions/global_options.py +++ b/tools/idf_py_actions/global_options.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 global_options = [{ 'names': ['-D', '--define-cache-entry'], diff --git a/tools/idf_py_actions/tools.py b/tools/idf_py_actions/tools.py index 015f536973f..7bda66f1bdd 100644 --- a/tools/idf_py_actions/tools.py +++ b/tools/idf_py_actions/tools.py @@ -667,18 +667,13 @@ def run_target( generator_cmd = list(GENERATORS[args.generator]['command']) - if args.generator == 'Ninja': - parallel_level = os.environ.get('IDF_PY_BUILD_JOBS') - if parallel_level: - try: - jobs = int(parallel_level) - except ValueError as e: - raise FatalError('Environment variable IDF_PY_BUILD_JOBS must be a positive integer') from e + # Parallel jobs from -j/--jobs (or IDF_PY_BUILD_JOBS), falling back to the generator's default. + jobs = getattr(args, 'jobs', None) + if jobs is None: + jobs = GENERATORS[args.generator].get('default_jobs') - if jobs <= 0: - raise FatalError('Environment variable IDF_PY_BUILD_JOBS must be a positive integer') - - generator_cmd += ['-j', str(jobs)] + if jobs is not None: + generator_cmd += ['-j', str(jobs)] if args.verbose: generator_cmd += [GENERATORS[args.generator]['verbose_flag']] From 27a72e4660959a4a65de79e9dffc205dc993ae14 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Fri, 31 Jul 2026 12:49:10 +0200 Subject: [PATCH 2/2] style(tools): reformat global_options.py with ruff-format This file predates the adoption of ruff-format and was never reformatted, because pre-commit only runs on the files touched by a change. GitHub PR #18871 bumps the copyright year here, which pulls the file into the hook's scope and makes check_pre_commit fail on a pre-existing formatting violation unrelated to that change. Signed-off-by: Frantisek Hrbata --- tools/idf_py_actions/global_options.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/idf_py_actions/global_options.py b/tools/idf_py_actions/global_options.py index 3dcf2894566..8d1ca5a6a8c 100644 --- a/tools/idf_py_actions/global_options.py +++ b/tools/idf_py_actions/global_options.py @@ -1,8 +1,10 @@ # SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 -global_options = [{ - 'names': ['-D', '--define-cache-entry'], - 'help': 'Create a cmake cache entry.', - 'scope': 'global', - 'multiple': True, -}] +global_options = [ + { + 'names': ['-D', '--define-cache-entry'], + 'help': 'Create a cmake cache entry.', + 'scope': 'global', + 'multiple': True, + } +]