doc: extensions: boards: add zephyr:board-supported-runners directive
Use runners.yaml from build metadata to gather info regarding board supported runners, store the info in the board catalog, and allow to display it as a table in a board's doc page using the .. zephyr:board-supported-runner:: directive. Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
This commit is contained in:
parent
76bf0126ff
commit
f06c26a6d0
5 changed files with 210 additions and 9 deletions
|
@ -16,6 +16,10 @@ Directives
|
|||
- ``zephyr:code-sample-listing::`` - Shows a listing of code samples found in a given category.
|
||||
- ``zephyr:board-catalog::`` - Shows a listing of boards supported by Zephyr.
|
||||
- ``zephyr:board::`` - Flags a document as being the documentation page for a board.
|
||||
- ``zephyr:board-supported-hw::`` - Shows a table of supported hardware features for all the targets
|
||||
of the board documented in the current page.
|
||||
- ``zephyr:board-supported-runners::`` - Shows a table of supported runners for the board documented
|
||||
in the current page.
|
||||
|
||||
Roles
|
||||
-----
|
||||
|
@ -58,6 +62,7 @@ __version__ = "0.2.0"
|
|||
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parents[4] / "scripts/dts/python-devicetree/src"))
|
||||
sys.path.insert(0, str(Path(__file__).parents[4] / "scripts/west_commands"))
|
||||
sys.path.insert(0, str(Path(__file__).parents[3] / "_scripts"))
|
||||
|
||||
from gen_boards_catalog import get_catalog
|
||||
|
@ -729,6 +734,9 @@ class BoardDirective(SphinxDirective):
|
|||
board_node["archs"] = board["archs"]
|
||||
board_node["socs"] = board["socs"]
|
||||
board_node["image"] = board["image"]
|
||||
board_node["supported_runners"] = board["supported_runners"]
|
||||
board_node["flash_runner"] = board["flash_runner"]
|
||||
board_node["debug_runner"] = board["debug_runner"]
|
||||
return [board_node]
|
||||
|
||||
|
||||
|
@ -992,6 +1000,121 @@ class BoardSupportedHardwareDirective(SphinxDirective):
|
|||
return result_nodes
|
||||
|
||||
|
||||
class BoardSupportedRunnersDirective(SphinxDirective):
|
||||
"""A directive for showing the supported runners of a board."""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
|
||||
def run(self):
|
||||
env = self.env
|
||||
docname = env.docname
|
||||
|
||||
matcher = NodeMatcher(BoardNode)
|
||||
board_nodes = list(self.state.document.traverse(matcher))
|
||||
if not board_nodes:
|
||||
logger.warning(
|
||||
"board-supported-runners directive must be used in a board documentation page.",
|
||||
location=(docname, self.lineno),
|
||||
)
|
||||
return []
|
||||
|
||||
if not env.app.config.zephyr_generate_hw_features:
|
||||
note = nodes.admonition()
|
||||
note += nodes.title(text="Note")
|
||||
note["classes"].append("warning")
|
||||
note += nodes.paragraph(
|
||||
text="The list of supported runners was not generated. Run a full documentation "
|
||||
"build for the required metadata to be available."
|
||||
)
|
||||
return [note]
|
||||
|
||||
board_node = board_nodes[0]
|
||||
runners = board_node["supported_runners"]
|
||||
flash_runner = board_node["flash_runner"]
|
||||
debug_runner = board_node["debug_runner"]
|
||||
|
||||
result_nodes = []
|
||||
|
||||
paragraph = nodes.paragraph()
|
||||
paragraph += nodes.Text("The ")
|
||||
paragraph += nodes.literal(text=board_node["id"])
|
||||
paragraph += nodes.Text(
|
||||
" board supports the runners and associated west commands listed below."
|
||||
)
|
||||
result_nodes.append(paragraph)
|
||||
|
||||
env_runners = env.domaindata["zephyr"]["runners"]
|
||||
commands = ["flash", "debug"]
|
||||
for runner in env_runners:
|
||||
if runner in board_node["supported_runners"]:
|
||||
for cmd in env_runners[runner].get("commands", []):
|
||||
if cmd not in commands:
|
||||
commands.append(cmd)
|
||||
|
||||
# create the table
|
||||
table = nodes.table(classes=["colwidths-given", "runners-table"])
|
||||
tgroup = nodes.tgroup(cols=len(commands) + 1) # +1 for the Runner column
|
||||
|
||||
# Add colspec for Runner column
|
||||
tgroup += nodes.colspec(colwidth=15, classes=["type"])
|
||||
# Add colspecs for command columns
|
||||
for _ in commands:
|
||||
tgroup += nodes.colspec(colwidth=15, classes=["type"])
|
||||
|
||||
thead = nodes.thead()
|
||||
row = nodes.row()
|
||||
entry = nodes.entry()
|
||||
row += entry
|
||||
headers = [*commands]
|
||||
for header in headers:
|
||||
entry = nodes.entry(classes=[header.lower()])
|
||||
entry += addnodes.literal_strong(text=header, classes=["command"])
|
||||
row += entry
|
||||
thead += row
|
||||
tgroup += thead
|
||||
|
||||
tbody = nodes.tbody()
|
||||
|
||||
# add a row for each runner
|
||||
for runner in sorted(runners):
|
||||
row = nodes.row()
|
||||
# First column - Runner name
|
||||
entry = nodes.entry()
|
||||
|
||||
xref = addnodes.pending_xref(
|
||||
"",
|
||||
refdomain="std",
|
||||
reftype="ref",
|
||||
reftarget=f"runner_{runner}",
|
||||
refexplicit=True,
|
||||
refwarn=False,
|
||||
)
|
||||
xref += nodes.Text(runner)
|
||||
entry += addnodes.literal_strong("", "", xref)
|
||||
row += entry
|
||||
|
||||
# Add columns for each command
|
||||
for command in commands:
|
||||
entry = nodes.entry()
|
||||
if command in env_runners[runner].get("commands", []):
|
||||
entry += nodes.Text("✅")
|
||||
if (command == "flash" and runner == flash_runner) or (
|
||||
command == "debug" and runner == debug_runner
|
||||
):
|
||||
entry += nodes.Text(" (default)")
|
||||
row += entry
|
||||
tbody += row
|
||||
|
||||
tgroup += tbody
|
||||
table += tgroup
|
||||
|
||||
result_nodes.append(table)
|
||||
|
||||
return result_nodes
|
||||
|
||||
|
||||
class ZephyrDomain(Domain):
|
||||
"""Zephyr domain"""
|
||||
|
||||
|
@ -1011,6 +1134,7 @@ class ZephyrDomain(Domain):
|
|||
"board-catalog": BoardCatalogDirective,
|
||||
"board": BoardDirective,
|
||||
"board-supported-hw": BoardSupportedHardwareDirective,
|
||||
"board-supported-runners": BoardSupportedRunnersDirective,
|
||||
}
|
||||
|
||||
object_types: dict[str, ObjType] = {
|
||||
|
@ -1247,6 +1371,7 @@ def load_board_catalog_into_domain(app: Sphinx) -> None:
|
|||
app.env.domaindata["zephyr"]["boards"] = board_catalog["boards"]
|
||||
app.env.domaindata["zephyr"]["vendors"] = board_catalog["vendors"]
|
||||
app.env.domaindata["zephyr"]["socs"] = board_catalog["socs"]
|
||||
app.env.domaindata["zephyr"]["runners"] = board_catalog["runners"]
|
||||
|
||||
|
||||
def setup(app):
|
||||
|
|
|
@ -15,6 +15,7 @@ import list_hardware
|
|||
import yaml
|
||||
import zephyr_module
|
||||
from gen_devicetree_rest import VndLookup
|
||||
from runners.core import ZephyrBinaryRunner
|
||||
|
||||
ZEPHYR_BASE = Path(__file__).parents[2]
|
||||
ZEPHYR_BINDINGS = ZEPHYR_BASE / "dts/bindings"
|
||||
|
@ -22,6 +23,10 @@ EDT_PICKLE_PATHS = [
|
|||
"zephyr/edt.pickle",
|
||||
"hello_world/zephyr/edt.pickle" # for board targets using sysbuild
|
||||
]
|
||||
RUNNERS_YAML_PATHS = [
|
||||
"zephyr/runners.yaml",
|
||||
"hello_world/zephyr/runners.yaml" # for board targets using sysbuild
|
||||
]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -108,20 +113,25 @@ def guess_doc_page(board_or_shield):
|
|||
return doc_file
|
||||
|
||||
|
||||
def gather_board_devicetrees(twister_out_dir):
|
||||
"""Gather EDT objects for each board from twister output directory.
|
||||
def gather_board_build_info(twister_out_dir):
|
||||
"""Gather EDT objects and runners info for each board from twister output directory.
|
||||
|
||||
Args:
|
||||
twister_out_dir: Path object pointing to twister output directory
|
||||
|
||||
Returns:
|
||||
A dictionary mapping board names to a dictionary of board targets and their EDT objects.
|
||||
The structure is: {board_name: {board_target: edt_object}}
|
||||
A tuple of two dictionaries:
|
||||
- A dictionary mapping board names to a dictionary of board targets and their EDT.
|
||||
objects.
|
||||
The structure is: {board_name: {board_target: edt_object}}
|
||||
- A dictionary mapping board names to a dictionary of board targets and their runners
|
||||
info.
|
||||
The structure is: {board_name: {board_target: runners_info}}
|
||||
"""
|
||||
board_devicetrees = {}
|
||||
|
||||
board_runners = {}
|
||||
if not twister_out_dir.exists():
|
||||
return board_devicetrees
|
||||
return board_devicetrees, board_runners
|
||||
|
||||
# Find all build_info.yml files in twister-out
|
||||
build_info_files = list(twister_out_dir.glob("*/**/build_info.yml"))
|
||||
|
@ -137,6 +147,13 @@ def gather_board_devicetrees(twister_out_dir):
|
|||
if not edt_pickle_file:
|
||||
continue
|
||||
|
||||
runners_yaml_file = None
|
||||
for runners_yaml_path in RUNNERS_YAML_PATHS:
|
||||
maybe_file = build_info_file.parent / runners_yaml_path
|
||||
if maybe_file.exists():
|
||||
runners_yaml_file = maybe_file
|
||||
break
|
||||
|
||||
try:
|
||||
with open(build_info_file) as f:
|
||||
build_info = yaml.safe_load(f)
|
||||
|
@ -155,10 +172,17 @@ def gather_board_devicetrees(twister_out_dir):
|
|||
edt = pickle.load(f)
|
||||
board_devicetrees.setdefault(board_name, {})[board_target] = edt
|
||||
|
||||
if runners_yaml_file:
|
||||
with open(runners_yaml_file) as f:
|
||||
runners_yaml = yaml.safe_load(f)
|
||||
board_runners.setdefault(board_name, {})[board_target] = (
|
||||
runners_yaml
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing build info file {build_info_file}: {e}")
|
||||
|
||||
return board_devicetrees
|
||||
return board_devicetrees, board_runners
|
||||
|
||||
|
||||
def run_twister_cmake_only(outdir):
|
||||
|
@ -174,6 +198,7 @@ def run_twister_cmake_only(outdir):
|
|||
"--all",
|
||||
"-M",
|
||||
*[arg for path in EDT_PICKLE_PATHS for arg in ('--keep-artifacts', path)],
|
||||
*[arg for path in RUNNERS_YAML_PATHS for arg in ('--keep-artifacts', path)],
|
||||
"--cmake-only",
|
||||
"--outdir", str(outdir),
|
||||
]
|
||||
|
@ -226,12 +251,13 @@ def get_catalog(generate_hw_features=False):
|
|||
systems = list_hardware.find_v2_systems(args_find_boards)
|
||||
board_catalog = {}
|
||||
board_devicetrees = {}
|
||||
board_runners = {}
|
||||
|
||||
if generate_hw_features:
|
||||
logger.info("Running twister in cmake-only mode to get Devicetree files for all boards")
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
run_twister_cmake_only(tmp_dir)
|
||||
board_devicetrees = gather_board_devicetrees(Path(tmp_dir))
|
||||
board_devicetrees, board_runners = gather_board_build_info(Path(tmp_dir))
|
||||
else:
|
||||
logger.info("Skipping generation of supported hardware features.")
|
||||
|
||||
|
@ -314,6 +340,15 @@ def get_catalog(generate_hw_features=False):
|
|||
# Store features for this specific target
|
||||
supported_features[board_target] = features
|
||||
|
||||
board_runner_info = {}
|
||||
if board.name in board_runners:
|
||||
# Assume all board targets have the same runners so only consider the runners
|
||||
# for the first board target.
|
||||
r = list(board_runners[board.name].values())[0]
|
||||
board_runner_info["runners"] = r.get("runners")
|
||||
board_runner_info["flash-runner"] = r.get("flash-runner")
|
||||
board_runner_info["debug-runner"] = r.get("debug-runner")
|
||||
|
||||
# Grab all the twister files for this board and use them to figure out all the archs it
|
||||
# supports.
|
||||
archs = set()
|
||||
|
@ -336,6 +371,10 @@ def get_catalog(generate_hw_features=False):
|
|||
"revision_default": board.revision_default,
|
||||
"supported_features": supported_features,
|
||||
"image": guess_image(board),
|
||||
# runners
|
||||
"supported_runners": board_runner_info.get("runners", []),
|
||||
"flash_runner": board_runner_info.get("flash-runner", ""),
|
||||
"debug_runner": board_runner_info.get("debug-runner", ""),
|
||||
}
|
||||
|
||||
socs_hierarchy = {}
|
||||
|
@ -344,8 +383,16 @@ def get_catalog(generate_hw_features=False):
|
|||
series = soc.series or "<no series>"
|
||||
socs_hierarchy.setdefault(family, {}).setdefault(series, []).append(soc.name)
|
||||
|
||||
available_runners = {}
|
||||
for runner in ZephyrBinaryRunner.get_runners():
|
||||
available_runners[runner.name()] = {
|
||||
"name": runner.name(),
|
||||
"commands": runner.capabilities().commands,
|
||||
}
|
||||
|
||||
return {
|
||||
"boards": board_catalog,
|
||||
"vendors": {**vnd_lookup.vnd2vendor, "others": "Other/Unknown"},
|
||||
"socs": socs_hierarchy,
|
||||
"runners": available_runners,
|
||||
}
|
||||
|
|
|
@ -1266,6 +1266,21 @@ Boards
|
|||
(``zephyr_generate_hw_features`` config option set to ``True``). If disabled, a warning message
|
||||
will be shown instead of the hardware features tables.
|
||||
|
||||
.. rst:directive:: .. zephyr:board-supported-runners::
|
||||
|
||||
This directive is used to show the supported runners for the board documented in the current
|
||||
page, including which runner is the default for flashing and debugging.
|
||||
|
||||
The directive must be used in a document that also contains a :rst:dir:`zephyr:board` directive,
|
||||
as it relies on the board information to generate the table.
|
||||
|
||||
.. note::
|
||||
|
||||
Similar to :rst:dir:`zephyr:board-supported-hw`, this directive requires hardware features
|
||||
generation to be enabled (``zephyr_generate_hw_features`` config option set to ``True``) to
|
||||
produce a complete table. If disabled, a warning message will be shown instead of the runners
|
||||
tables.
|
||||
|
||||
References
|
||||
**********
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ file declares that support properly. See :ref:`west-build-flash-debug` for
|
|||
more information on these commands.
|
||||
|
||||
.. _atmel_sam_ba_bootloader:
|
||||
.. _runner_bossac:
|
||||
|
||||
SAM Boot Assistant (SAM-BA)
|
||||
***************************
|
||||
|
@ -207,6 +208,7 @@ Windows PATH. A specific bossac executable can be used by passing the
|
|||
|
||||
|
||||
.. _linkserver-debug-host-tools:
|
||||
.. _runner_linkserver:
|
||||
|
||||
LinkServer Debug Host Tools
|
||||
****************************
|
||||
|
@ -282,6 +284,7 @@ LinkServer west runner ``--probe`` option to pass the probe index.
|
|||
will need to add a breakpoint at ``main`` or the reset handler manually.
|
||||
|
||||
.. _jlink-debug-host-tools:
|
||||
.. _runner_jlink:
|
||||
|
||||
J-Link Debug Host Tools
|
||||
***********************
|
||||
|
@ -312,6 +315,7 @@ required.
|
|||
Note that the J-Link GDB server does not yet support Zephyr RTOS-awareness.
|
||||
|
||||
.. _openocd-debug-host-tools:
|
||||
.. _runner_openocd:
|
||||
|
||||
OpenOCD Debug Host Tools
|
||||
************************
|
||||
|
@ -339,6 +343,7 @@ Check if your SoC is listed in `OpenOCD Supported Devices`_.
|
|||
- Add ``C:\Program Files\OpenOCD\bin`` to 'PATH' environment variable
|
||||
|
||||
.. _pyocd-debug-host-tools:
|
||||
.. _runner_pyocd:
|
||||
|
||||
pyOCD Debug Host Tools
|
||||
**********************
|
||||
|
@ -358,6 +363,7 @@ These debug host tools are compatible with the following debug probes:
|
|||
Check if your SoC is listed in `pyOCD Supported Devices`_.
|
||||
|
||||
.. _lauterbach-trace32-debug-host-tools:
|
||||
.. _runner_trace32:
|
||||
|
||||
Lauterbach TRACE32 Debug Host Tools
|
||||
***********************************
|
||||
|
@ -409,6 +415,7 @@ To enable Zephyr RTOS awareness follow the steps described in
|
|||
`Lauterbach TRACE32 Zephyr OS Awareness Manual`_.
|
||||
|
||||
.. _nxp-s32-debug-host-tools:
|
||||
.. _runner_nxp_s32dbg:
|
||||
|
||||
NXP S32 Debug Probe Host Tools
|
||||
******************************
|
||||
|
@ -471,6 +478,8 @@ afterwards detach the debug session:
|
|||
|
||||
west debug --tool-opt='--batch'
|
||||
|
||||
.. _runner_probe_rs:
|
||||
|
||||
probe-rs Debug Host Tools
|
||||
*************************
|
||||
|
||||
|
@ -482,7 +491,7 @@ Check `probe-rs Installation`_ for more setup details.
|
|||
|
||||
Check if your SoC is listed in `probe-rs Supported Devices`_.
|
||||
|
||||
.. _stm32cubeprog-flash-host-tools:
|
||||
.. _runner_rfp:
|
||||
|
||||
Renesas Flash Programmer (RFP) Host Tools
|
||||
*****************************************
|
||||
|
@ -503,6 +512,9 @@ to ``rfp-cli`` when flashing:
|
|||
|
||||
west flash --rfp-cli ~/Downloads/RFP_CLI_Linux_V31800_x64/linux-x64/rfp-cli
|
||||
|
||||
.. _stm32cubeprog-flash-host-tools:
|
||||
.. _runner_stm32cubeprogrammer:
|
||||
|
||||
STM32CubeProgrammer Flash Host Tools
|
||||
************************************
|
||||
|
||||
|
|
2
doc/templates/board.tmpl
vendored
2
doc/templates/board.tmpl
vendored
|
@ -29,6 +29,8 @@ to connect external components]
|
|||
Programming and Debugging
|
||||
*************************
|
||||
|
||||
.. zephyr:board-supported-runners::
|
||||
|
||||
Flashing
|
||||
========
|
||||
[How to use this board with Zephyr and how to flash a Zephyr binary on this
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue