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