1#!/usr/bin/env python3 2 3# Copyright (c) 2020 Nordic Semiconductor ASA 4# SPDX-License-Identifier: Apache-2.0 5 6import argparse 7from collections import defaultdict 8import itertools 9from pathlib import Path 10from typing import NamedTuple 11 12ZEPHYR_BASE = Path(__file__).resolve().parents[1] 13 14# 15# This is shared code between the build system's 'boards' target 16# and the 'west boards' extension command. If you change it, make 17# sure to test both ways it can be used. 18# 19# (It's done this way to keep west optional, making it possible to run 20# 'ninja boards' in a build directory without west installed.) 21# 22 23class Board(NamedTuple): 24 name: str 25 arch: str 26 dir: Path 27 28def board_key(board): 29 return board.name 30 31def find_arch2boards(args): 32 arch2board_set = find_arch2board_set(args) 33 return {arch: sorted(arch2board_set[arch], key=board_key) 34 for arch in arch2board_set} 35 36def find_boards(args): 37 return sorted(itertools.chain(*find_arch2board_set(args).values()), 38 key=board_key) 39 40def find_arch2board_set(args): 41 arches = sorted(find_arches(args)) 42 ret = defaultdict(set) 43 44 for root in itertools.chain([ZEPHYR_BASE], args.board_roots): 45 for arch, boards in find_arch2board_set_in(root, arches).items(): 46 ret[arch] |= boards 47 48 return ret 49 50def find_arches(args): 51 arch_set = find_arches_in(ZEPHYR_BASE) 52 53 for root in args.arch_roots: 54 arch_set |= find_arches_in(root) 55 56 return arch_set 57 58def find_arches_in(root): 59 ret = set() 60 arch = root / 'arch' 61 common = arch / 'common' 62 63 if not arch.is_dir(): 64 return ret 65 66 for maybe_arch in arch.iterdir(): 67 if not maybe_arch.is_dir() or maybe_arch == common: 68 continue 69 ret.add(maybe_arch.name) 70 71 return ret 72 73def find_arch2board_set_in(root, arches): 74 ret = defaultdict(set) 75 boards = root / 'boards' 76 77 for arch in arches: 78 if not (boards / arch).is_dir(): 79 continue 80 81 for maybe_board in (boards / arch).iterdir(): 82 if not maybe_board.is_dir(): 83 continue 84 for maybe_defconfig in maybe_board.iterdir(): 85 file_name = maybe_defconfig.name 86 if file_name.endswith('_defconfig'): 87 board_name = file_name[:-len('_defconfig')] 88 ret[arch].add(Board(board_name, arch, maybe_board)) 89 90 return ret 91 92def parse_args(): 93 parser = argparse.ArgumentParser() 94 add_args(parser) 95 return parser.parse_args() 96 97def add_args(parser): 98 # Remember to update west-completion.bash if you add or remove 99 # flags 100 parser.add_argument("--arch-root", dest='arch_roots', default=[], 101 type=Path, action='append', 102 help='''add an architecture root (ZEPHYR_BASE is 103 always present), may be given more than once''') 104 parser.add_argument("--board-root", dest='board_roots', default=[], 105 type=Path, action='append', 106 help='''add a board root (ZEPHYR_BASE is always 107 present), may be given more than once''') 108 109def dump_boards(arch2boards): 110 for arch, boards in arch2boards.items(): 111 print(f'{arch}:') 112 for board in boards: 113 print(f' {board.name}') 114 115if __name__ == '__main__': 116 dump_boards(find_arch2boards(parse_args())) 117