diff --git a/doc/develop/modules.rst b/doc/develop/modules.rst index ff8f3781d45fb..352edfb963fd5 100644 --- a/doc/develop/modules.rst +++ b/doc/develop/modules.rst @@ -1050,6 +1050,25 @@ requirement files in the ``scripts`` directory of the module. - scripts/requirements-build.txt - scripts/requirements-doc.txt + +.. _modules-runners: + +External Runners +================ + +If a module has out of tree boards that require custom :ref:`runners `, +then it can add a list to its ``zephyr/module.yml`` file, for example: + + +.. code-block:: yaml + + runners: + - file: scripts/my-runner.py + + +Each file entry is imported when executing ``west flash`` or ``west debug`` and +subclasses of the ``ZephyrBinaryRunner`` are registered for use. + Module Inclusion ================ diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index c45a4551843e9..2b7dd3ecd3ba6 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -779,6 +779,19 @@ To view all available options Renode supports, use:: west simulate --runner=renode --renode-help +Out of tree runners +******************* + +:ref:`Zephyr modules ` can have external runners discovered by adding python +files in their :ref:`module.yml `. Create an external runner class by +inheriting from ``ZephyrBinaryRunner`` and implement all abstract methods. + +.. note:: + + Support for custom out-of-tree runners makes the ``runners.core`` module part of + the public API and backwards incompatible changes need to undergo the + :ref:`deprecation process `. + Hacking ******* @@ -786,11 +799,6 @@ This section documents the ``runners.core`` module used by the flash and debug commands. This is the core abstraction used to implement support for these features. -.. warning:: - - These APIs are provided for reference, but they are more "shared code" used - to implement multiple extension commands than a stable API. - Developers can add support for new ways to flash and debug Zephyr programs by implementing additional runners. To get this support into upstream Zephyr, the runner should be added into a new or existing ``runners`` module, and imported diff --git a/scripts/west_commands/run_common.py b/scripts/west_commands/run_common.py index adfd2922fb98d..e5492ad2f7b89 100644 --- a/scripts/west_commands/run_common.py +++ b/scripts/west_commands/run_common.py @@ -6,6 +6,7 @@ '''Common code used by commands which execute runners. ''' +import importlib.util import re import argparse import logging @@ -28,7 +29,8 @@ from runners.core import BuildConfiguration import yaml -from zephyr_ext_common import ZEPHYR_SCRIPTS +import zephyr_module +from zephyr_ext_common import ZEPHYR_BASE, ZEPHYR_SCRIPTS # Runners depend on edtlib. Make sure the copy in the tree is # available to them before trying to import any. @@ -107,6 +109,13 @@ class SocBoardFilesProcessing: priority: int = IGNORED_RUN_ONCE_PRIORITY yaml: object = None +def import_from_path(module_name, file_path): + spec = importlib.util.spec_from_file_location(module_name, file_path) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + def command_verb(command): return "flash" if command.name == "flash" else "debug" @@ -197,6 +206,14 @@ def do_run_common(command, user_args, user_runner_args, domain_file=None): dump_context(command, user_args, user_runner_args) return + # Import external module runners + for module in zephyr_module.parse_modules(ZEPHYR_BASE, command.manifest): + runners_ext = module.meta.get("runners", []) + for runner in runners_ext: + import_from_path( + module.meta.get("name", "runners_ext"), Path(module.project) / runner["file"] + ) + build_dir = get_build_dir(user_args) if not user_args.skip_rebuild: rebuild(command, build_dir, user_args) diff --git a/scripts/zephyr_module.py b/scripts/zephyr_module.py index ae2c35cc62d18..22369aa8295b1 100755 --- a/scripts/zephyr_module.py +++ b/scripts/zephyr_module.py @@ -174,6 +174,15 @@ type: seq sequence: - type: str + runners: + required: false + type: seq + sequence: + - type: map + mapping: + file: + required: true + type: str ''' MODULE_YML_PATH = PurePath('zephyr/module.yml')