| # Copyright 2026 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Incoming transition for Zephyr applications.""" |
| |
| load("@zephyr-bazel//:naming.bzl", "get_zc_repo_name") |
| load("@zephyr_index//:index.bzl", "PACKAGE_TO_BOARDS", "REPO_NAME_TO_CANONICAL") |
| |
| def resolve_board_id(platform_label, pkg, pkg_boards, package_to_boards): |
| """Resolves the Zephyr board ID from the platform label and context discovery index. |
| |
| Args: |
| platform_label: The user requested platform label. |
| pkg: The resolved package path. |
| pkg_boards: Boards mapped to that package. |
| package_to_boards: The global boards configuration index dict. |
| |
| Returns: |
| The resolved board_id or None. |
| """ |
| board_id = None |
| |
| # Construct candidates list: (candidate_pkg, candidate_boards) |
| # First candidate is the current package |
| candidates = [(pkg, pkg_boards)] |
| |
| # Add sub-packages as fallback candidates |
| prefix = pkg + "/" |
| for sub_pkg, sub_pkg_boards in package_to_boards.items(): |
| if sub_pkg.startswith(prefix): |
| candidates.append((sub_pkg, sub_pkg_boards)) |
| |
| # Run resolution rules on candidates |
| for cand_pkg, cand_boards in candidates: |
| # Default Shortcut |
| if not board_id and platform_label.name == "default" and len(cand_boards) == 1: |
| board_id = cand_boards[0] |
| |
| # Explicit Match (with default SoC resolution for HWM v2) |
| if not board_id and platform_label.name in cand_boards: |
| prefix_b = platform_label.name + "/" |
| qualified_variants = [b for b in cand_boards if b.startswith(prefix_b)] |
| if qualified_variants: |
| # Resolve to the first qualified variant (default SoC) |
| board_id = qualified_variants[0] |
| else: |
| board_id = platform_label.name |
| |
| # SoC/Variant Match (e.g. :nrf52833 for board nrf52833dk) |
| if not board_id and cand_boards: |
| for b in cand_boards: |
| if b.endswith("/" + platform_label.name): |
| board_id = b |
| break |
| # Handle board/soc/variant where board == soc, simplified to board_variant (e.g. qemu_malta_be) |
| parts = b.split("/") |
| if len(parts) == 3 and parts[0] == parts[1]: |
| short_name = parts[0] + "_" + parts[2] |
| if short_name == platform_label.name: |
| board_id = b |
| break |
| |
| # Fallback: if exactly one BASE board exists, assume it's board/soc |
| if not board_id: |
| base_boards = [b for b in cand_boards if "/" not in b] |
| if len(base_boards) == 1: |
| board_id = base_boards[0] + "/" + platform_label.name |
| |
| if board_id: |
| break |
| return board_id |
| |
| def _zephyr_transition_impl(settings, attr): |
| platforms = settings["//command_line_option:platforms"] |
| if not platforms: |
| return {} |
| |
| platform_label = platforms[0] |
| |
| # If already transitioned, do nothing. |
| # Check both the old zc_ pattern and the new canonical Bzlmod pattern. |
| if platform_label.workspace_name and ("zc_" in platform_label.workspace_name or "+zephyr_setup+" in platform_label.workspace_name): |
| return {} |
| |
| # Resolve package path as used in PACKAGE_TO_BOARDS |
| pkg = str(platform_label).split(":")[0] |
| if pkg.startswith("//"): |
| pkg = "@@" + pkg |
| |
| if not pkg.endswith("//"): |
| pkg = pkg.rstrip("/") |
| pkg_boards = PACKAGE_TO_BOARDS.get(pkg, None) |
| |
| if pkg_boards == None: |
| # This platform is not in a package that contains Zephyr boards. |
| # Bypass the transition and let Bazel handle it. |
| return {} |
| |
| board_id = resolve_board_id(platform_label, pkg, pkg_boards, PACKAGE_TO_BOARDS) |
| |
| if not board_id: |
| fail("Unknown Zephyr board: %s. Valid boards in %s: %s" % (platform_label, pkg, pkg_boards)) |
| |
| repo_name = get_zc_repo_name(attr.app_label, board_id) |
| canonical_repo = REPO_NAME_TO_CANONICAL.get(repo_name) |
| if not canonical_repo: |
| fail(""" |
| Board combination '%s' for app '%s' was filtered out by heuristics. |
| To fix this, you can either: |
| 1. Add a .conf or .overlay file for this board under the 'boards/' directory of the app. |
| 2. Add the board to the 'manual_boards' attribute of 'zephyr_setup.env' in MODULE.bazel |
| """ % (board_id, attr.app_label)) |
| |
| return {"//command_line_option:platforms": ["%s//:platform" % canonical_repo]} |
| |
| zephyr_transition = transition( |
| implementation = _zephyr_transition_impl, |
| inputs = ["//command_line_option:platforms"], |
| outputs = ["//command_line_option:platforms"], |
| ) |