boards/shields: re-work handling in cmake and west
Remove the boards and shields lists from the 'usage' target output. That might have been readable at some point long ago in Zephyr's history, when only a few boards were available, but right now it's obscuring the high level targets we really want 'usage' to print. Instead, add 'boards' and 'shields' targets which the user can run to get those lists, and reference them from the 'usage' output. This makes 'usage' squintable again. We use the new list_boards.py script from the 'boards' target. Reference the 'help' target from 'usage' as well, and drop the recommendation that people run '--target help' from the 'west build --help' output for the 'west build --target' option. The canonical place to look is 'usage' now. Use the new list_boards.py code from 'west boards' as well, which allows us to add the board's directory as a format string key, in addition to its name and architecture. Keep west-completion.bash up to date. While doing that, I noticed that a bunch of references to this file refer to a stale location, so fix those too. Finally, the 'usage' output is what we print for a failed board or shield lookup, so that needs to be updated also. Handle that by invoking boards.cmake and a new shields.cmake in CMake script mode to print the relevant output. Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
parent
8bd6d08b0b
commit
0d5e6c13e9
|
@ -357,19 +357,37 @@ foreach(root ${BOARD_ROOT})
|
|||
endforeach()
|
||||
|
||||
if(NOT BOARD_DIR)
|
||||
message("No board named '${BOARD}' found")
|
||||
print_usage()
|
||||
message("No board named '${BOARD}' found.
|
||||
|
||||
Please choose one of the following boards:
|
||||
")
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DZEPHYR_BASE=${ZEPHYR_BASE}
|
||||
-DBOARD_ROOT=${BOARD_ROOT}
|
||||
-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
|
||||
-P ${ZEPHYR_BASE}/cmake/boards.cmake
|
||||
)
|
||||
unset(CACHED_BOARD CACHE)
|
||||
message(FATAL_ERROR "Invalid usage")
|
||||
message(FATAL_ERROR "Invalid BOARD; see above.")
|
||||
endif()
|
||||
|
||||
if(DEFINED SHIELD AND NOT (SHIELD-NOTFOUND STREQUAL ""))
|
||||
foreach (s ${SHIELD-NOTFOUND})
|
||||
message("No shield named '${s}' found")
|
||||
endforeach()
|
||||
print_usage()
|
||||
message("Please choose from among the following shields:")
|
||||
string(REPLACE ";" "\\;" SHIELD_LIST_ESCAPED "${SHIELD_LIST}")
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DZEPHYR_BASE=${ZEPHYR_BASE}
|
||||
-DSHIELD_LIST=${SHIELD_LIST_ESCAPED}
|
||||
-P ${ZEPHYR_BASE}/cmake/shields.cmake
|
||||
)
|
||||
unset(CACHED_SHIELD CACHE)
|
||||
message(FATAL_ERROR "Invalid usage")
|
||||
message(FATAL_ERROR "Invalid SHIELD; see above.")
|
||||
endif()
|
||||
|
||||
get_filename_component(BOARD_ARCH_DIR ${BOARD_DIR} DIRECTORY)
|
||||
|
|
|
@ -1,91 +1,19 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# List all architectures, export the list in list_var
|
||||
function(list_archs list_var)
|
||||
set(arch_root_args)
|
||||
foreach(root ${ARCH_ROOT})
|
||||
list(APPEND arch_root_args "--arch-root=${root}")
|
||||
endforeach()
|
||||
|
||||
FILE(GLOB arch_contents RELATIVE ${ZEPHYR_BASE}/arch ${ZEPHYR_BASE}/arch/*)
|
||||
set(_arch_list)
|
||||
foreach(f ${arch_contents})
|
||||
if ("${f}" STREQUAL "common")
|
||||
continue()
|
||||
endif()
|
||||
if (IS_DIRECTORY "${ZEPHYR_BASE}/arch/${f}")
|
||||
list(APPEND _arch_list "${f}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(board_root_args)
|
||||
foreach(root ${BOARD_ROOT})
|
||||
list(APPEND board_root_args "--board-root=${root}")
|
||||
endforeach()
|
||||
|
||||
# Export the arch list to the parent scope
|
||||
set(${list_var} ${_arch_list} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# List all boards for a particular arch, export the list in list_var
|
||||
function(list_boards arch list_var)
|
||||
|
||||
# Make sure we start with an empty list for each arch
|
||||
set(_boards_for_${arch} "")
|
||||
foreach(root ${BOARD_ROOT})
|
||||
set(board_arch_dir ${root}/boards/${arch})
|
||||
|
||||
# Match the _defconfig files in the board directories to make sure we are
|
||||
# finding boards, e.g. qemu_xtensa/qemu_xtensa_defconfig
|
||||
file(GLOB_RECURSE defconfigs_for_${arch}
|
||||
RELATIVE ${board_arch_dir}
|
||||
${board_arch_dir}/*_defconfig
|
||||
)
|
||||
|
||||
# The above gives a list like
|
||||
# nrf51_blenano/nrf51_blenano_defconfig;nrf51dk_nrf51422/nrf51dk_nrf51422_defconfig
|
||||
# we construct a list of board names by removing both the _defconfig
|
||||
# suffix and the path.
|
||||
foreach(defconfig_path ${defconfigs_for_${arch}})
|
||||
get_filename_component(board ${defconfig_path} NAME)
|
||||
string(REPLACE "_defconfig" "" board "${board}")
|
||||
list(APPEND _boards_for_${arch} ${board})
|
||||
endforeach()
|
||||
|
||||
endforeach()
|
||||
|
||||
# Export the board list for this arch to the parent scope
|
||||
set(${list_var} ${_boards_for_${arch}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Function to dump and optionally save to a file all architectures and boards
|
||||
# Takes the board root as a semicolon-separated list in:
|
||||
# BOARD_ROOT
|
||||
# Additional arguments:
|
||||
# file_out Filename to save the boards list. If not defined, stdout will be used
|
||||
# indent Prepend an additional indendation string to each line
|
||||
function(dump_all_boards file_out indent)
|
||||
|
||||
set(arch_list)
|
||||
list_archs(arch_list)
|
||||
|
||||
foreach(arch ${arch_list})
|
||||
list_boards(${arch} boards_for_${arch})
|
||||
endforeach()
|
||||
|
||||
if(file_out)
|
||||
file(WRITE ${file_out} "")
|
||||
endif()
|
||||
|
||||
foreach(arch ${arch_list})
|
||||
set(_arch_str "${indent}${arch}:")
|
||||
if(file_out)
|
||||
file(APPEND ${file_out} "${_arch_str}\n")
|
||||
else()
|
||||
message(${_arch_str})
|
||||
endif()
|
||||
foreach(board ${boards_for_${arch}})
|
||||
set(_board_str "${indent} ${board}")
|
||||
if(file_out)
|
||||
file(APPEND ${file_out} "${_board_str}\n")
|
||||
else()
|
||||
message(${_board_str})
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
endfunction()
|
||||
set(list_boards_commands
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/list_boards.py
|
||||
${arch_root_args} ${board_root_args}
|
||||
)
|
||||
|
||||
if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE)
|
||||
# If this file is invoked as a script directly with -P:
|
||||
|
@ -95,6 +23,7 @@ if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE)
|
|||
# some other script
|
||||
|
||||
# The options available are:
|
||||
# ARCH_ROOT: Semi-colon separated arch roots
|
||||
# BOARD_ROOT: Semi-colon separated board roots
|
||||
# FILE_OUT: Set to a file path to save the boards to a file. If not defined the
|
||||
# the contents will be printed to stdout
|
||||
|
@ -103,15 +32,9 @@ cmake_minimum_required(VERSION 3.13.1)
|
|||
set(NO_BOILERPLATE TRUE)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
# Appending Zephyr base to list of board roots, as this is also done in boilerplate.cmake.
|
||||
# But as this file was executed in script mode, it must also be done here, to give same output.
|
||||
list(APPEND BOARD_ROOT ${ZEPHYR_BASE})
|
||||
|
||||
if (NOT FILE_OUT)
|
||||
set(FILE_OUT FALSE)
|
||||
if (FILE_OUT)
|
||||
list(APPEND list_boards_commands OUTPUT_FILE "${FILE_OUT}")
|
||||
endif()
|
||||
|
||||
dump_all_boards(${FILE_OUT} "")
|
||||
|
||||
execute_process(${list_boards_commands})
|
||||
endif()
|
||||
|
||||
|
|
|
@ -1758,25 +1758,6 @@ macro(assert_exists var)
|
|||
endif()
|
||||
endmacro()
|
||||
|
||||
function(print_usage)
|
||||
if(NOT CMAKE_MAKE_PROGRAM)
|
||||
# Create dummy project, in order to obtain make program for correct usage printing.
|
||||
project(dummy_print_usage)
|
||||
endif()
|
||||
message("see usage:")
|
||||
string(REPLACE ";" " " BOARD_ROOT_SPACE_SEPARATED "${BOARD_ROOT}")
|
||||
string(REPLACE ";" " " SHIELD_LIST_SPACE_SEPARATED "${SHIELD_LIST}")
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DZEPHYR_BASE=${ZEPHYR_BASE}
|
||||
-DBOARD_ROOT_SPACE_SEPARATED=${BOARD_ROOT_SPACE_SEPARATED}
|
||||
-DSHIELD_LIST_SPACE_SEPARATED=${SHIELD_LIST_SPACE_SEPARATED}
|
||||
-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
|
||||
-P ${ZEPHYR_BASE}/cmake/usage/usage.cmake
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# 3.5. File system management
|
||||
function(check_if_directory_is_writeable dir ok)
|
||||
execute_process(
|
||||
|
|
18
cmake/shields.cmake
Normal file
18
cmake/shields.cmake
Normal file
|
@ -0,0 +1,18 @@
|
|||
if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE)
|
||||
# This file was invoked as a script directly with -P:
|
||||
# cmake -P shields.cmake
|
||||
#
|
||||
# Unlike boards.cmake, this takes no OUTPUT_FILE option, but
|
||||
# SHIELD_LIST_SPACE_SEPARATED is required.
|
||||
list(SORT SHIELD_LIST)
|
||||
foreach(shield ${SHIELD_LIST})
|
||||
message("${shield}")
|
||||
endforeach()
|
||||
else()
|
||||
# This file was included into usage.cmake.
|
||||
set(sorted_shield_list ${SHIELD_LIST})
|
||||
list(SORT sorted_shield_list)
|
||||
foreach(shield ${sorted_shield_list})
|
||||
list(APPEND sorted_shield_cmds COMMAND ${CMAKE_COMMAND} -E echo "${shield}")
|
||||
endforeach()
|
||||
endif()
|
|
@ -1,14 +1,19 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
string(REPLACE ";" " " BOARD_ROOT_SPACE_SEPARATED "${BOARD_ROOT}")
|
||||
string(REPLACE ";" " " SHIELD_LIST_SPACE_SEPARATED "${SHIELD_LIST}")
|
||||
include (${ZEPHYR_BASE}/cmake/shields.cmake)
|
||||
include (${ZEPHYR_BASE}/cmake/boards.cmake)
|
||||
|
||||
# shields.cmake and boards.cmake can be run with cmake -P for printing
|
||||
# help output on user error when settings BOARD or SHIELD, and
|
||||
# add_custom_target() is not available in script mode, so we place
|
||||
# them in here.
|
||||
add_custom_target(shields ${sorted_shield_cmds} USES_TERMINAL)
|
||||
add_custom_target(boards ${list_boards_commands} USES_TERMINAL)
|
||||
|
||||
add_custom_target(
|
||||
usage
|
||||
${CMAKE_COMMAND}
|
||||
-DZEPHYR_BASE=${ZEPHYR_BASE}
|
||||
-DBOARD_ROOT_SPACE_SEPARATED=${BOARD_ROOT_SPACE_SEPARATED}
|
||||
-DSHIELD_LIST_SPACE_SEPARATED=${SHIELD_LIST_SPACE_SEPARATED}
|
||||
-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/usage.cmake
|
||||
)
|
||||
|
|
|
@ -3,8 +3,6 @@ if(NOT DEFINED ZEPHYR_BASE)
|
|||
message(FATAL_ERROR "ZEPHYR_BASE not set")
|
||||
endif()
|
||||
|
||||
include (${ZEPHYR_BASE}/cmake/boards.cmake)
|
||||
|
||||
get_filename_component(generator ${CMAKE_MAKE_PROGRAM} NAME)
|
||||
if(${generator} STREQUAL ninja)
|
||||
set(verbose "-v")
|
||||
|
@ -12,48 +10,27 @@ else()
|
|||
set(verbose "VERBOSE=1")
|
||||
endif()
|
||||
|
||||
string(REPLACE " " ";" BOARD_ROOT "${BOARD_ROOT_SPACE_SEPARATED}")
|
||||
string(REPLACE " " ";" SHIELD_LIST "${SHIELD_LIST_SPACE_SEPARATED}")
|
||||
|
||||
message("Cleaning targets:")
|
||||
message(" clean - Remove most generated files but keep configuration and backup files")
|
||||
message(" pristine - Remove all files in the build directory")
|
||||
message("")
|
||||
message("Configuration targets:")
|
||||
message("")
|
||||
message(" menuconfig - Update configuration using an interactive configuration interface")
|
||||
message("Kconfig targets:")
|
||||
message(" menuconfig - Update .config using a console-based interface")
|
||||
message(" guiconfig - Update .config using a graphical interface")
|
||||
message("")
|
||||
message("Other generic targets:")
|
||||
message(" all - Build a zephyr application")
|
||||
message(" run - Build a zephyr application and run it if the board supports emulation")
|
||||
message(" flash - Build and flash an application")
|
||||
message(" debug - Build and debug an application using GDB")
|
||||
message(" debugserver - Build and start a GDB server (port 1234 for Qemu targets)")
|
||||
message(" flash - Run \"west flash\"")
|
||||
message(" debug - Run \"west debug\"")
|
||||
message(" debugserver - Run \"west debugserver\" (or start GDB server on port 1234 for QEMU targets)")
|
||||
message(" attach - Run \"west attach\"")
|
||||
message(" ram_report - Build and create RAM usage report")
|
||||
message(" rom_report - Build and create ROM usage report")
|
||||
message(" boards - Display supported boards")
|
||||
message(" shields - Display supported shields")
|
||||
message(" usage - Display this text")
|
||||
message("")
|
||||
message("Supported Boards:")
|
||||
message("")
|
||||
message(" To generate project files for one of the supported boards below, run:")
|
||||
message("")
|
||||
message(" $ cmake -DBOARD=<BOARD NAME> [-DSHIELD=<SHIELD NAME>] -Bpath/to/build_dir -Hpath/to/source_dir")
|
||||
message("")
|
||||
message(" or")
|
||||
message("")
|
||||
message(" $ export BOARD=<BOARD NAME>")
|
||||
message(" $ export SHIELD=<SHIELD NAME> #optional")
|
||||
message(" $ cmake -Bpath/to/build_dir -Hpath/to/source_dir")
|
||||
message("")
|
||||
dump_all_boards("" " ")
|
||||
message("")
|
||||
message("Supported Shields:")
|
||||
message("")
|
||||
set(sorted_shield_list ${SHIELD_LIST})
|
||||
list(SORT sorted_shield_list)
|
||||
foreach(shield ${sorted_shield_list})
|
||||
message(" ${shield}")
|
||||
endforeach()
|
||||
message(" help - Display all build system targets")
|
||||
message("")
|
||||
message("Build flags:")
|
||||
message("")
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from west import log
|
||||
from west.commands import WestCommand
|
||||
|
||||
from zcmake import run_cmake
|
||||
from zephyr_ext_common import ZEPHYR_CMAKE
|
||||
sys.path.append(os.fspath(Path(__file__).parent.parent))
|
||||
import list_boards
|
||||
|
||||
class Boards(WestCommand):
|
||||
|
||||
|
@ -30,23 +32,25 @@ class Boards(WestCommand):
|
|||
help=self.help,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=self.description,
|
||||
epilog=textwrap.dedent('''\
|
||||
epilog=textwrap.dedent(f'''\
|
||||
FORMAT STRINGS
|
||||
--------------
|
||||
|
||||
Boards are listed using a Python 3 format string. Arguments
|
||||
to the format string are accessed by name.
|
||||
|
||||
The default format string is:
|
||||
|
||||
"{}"
|
||||
"{default_fmt}"
|
||||
|
||||
The following arguments are available:
|
||||
|
||||
- name: board name
|
||||
- arch: board architecture
|
||||
'''.format(default_fmt)))
|
||||
- dir: directory that contains the board definition
|
||||
'''))
|
||||
|
||||
# Remember to update scripts/west-completion.bash if you add or remove
|
||||
# Remember to update west-completion.bash if you add or remove
|
||||
# flags
|
||||
parser.add_argument('-f', '--format', default=default_fmt,
|
||||
help='''Format string to use to list each board;
|
||||
|
@ -54,47 +58,18 @@ class Boards(WestCommand):
|
|||
parser.add_argument('-n', '--name', dest='name_re',
|
||||
help='''a regular expression; only boards whose
|
||||
names match NAME_RE will be listed''')
|
||||
list_boards.add_args(parser)
|
||||
|
||||
return parser
|
||||
|
||||
def do_run(self, args, unknown_args):
|
||||
cmake_args = ['-P', f'{ZEPHYR_CMAKE}/boards.cmake']
|
||||
lines = run_cmake(cmake_args, capture_output=True)
|
||||
arch_re = re.compile(r'\s*([\w-]+)\:')
|
||||
board_re = re.compile(r'\s*([\w-]+)\s*')
|
||||
arch = None
|
||||
boards = collections.OrderedDict()
|
||||
for line in lines:
|
||||
match = arch_re.match(line)
|
||||
if match:
|
||||
arch = match.group(1)
|
||||
boards[arch] = []
|
||||
continue
|
||||
match = board_re.match(line)
|
||||
if match:
|
||||
if not arch:
|
||||
log.die('Invalid board output from CMake: {}'.
|
||||
format(lines))
|
||||
board = match.group(1)
|
||||
boards[arch].append(board)
|
||||
|
||||
def do_run(self, args, _):
|
||||
if args.name_re is not None:
|
||||
name_re = re.compile(args.name_re)
|
||||
else:
|
||||
name_re = None
|
||||
|
||||
for arch in boards:
|
||||
for board in boards[arch]:
|
||||
if name_re is not None and not name_re.search(board):
|
||||
continue
|
||||
try:
|
||||
result = args.format.format(
|
||||
name=board,
|
||||
arch=arch)
|
||||
print(result)
|
||||
except KeyError as e:
|
||||
# The raised KeyError seems to just put the first
|
||||
# invalid argument in the args tuple, regardless of
|
||||
# how many unrecognizable keys there were.
|
||||
log.die('unknown key "{}" in format string "{}"'.
|
||||
format(e.args[0], args.format))
|
||||
for board in list_boards.find_boards(args):
|
||||
if name_re is not None and not name_re.search(board.name):
|
||||
continue
|
||||
log.inf(args.format.format(name=board.name, arch=board.arch,
|
||||
dir=board.dir))
|
||||
|
|
|
@ -94,7 +94,7 @@ class Build(Forceable):
|
|||
description=self.description,
|
||||
usage=BUILD_USAGE)
|
||||
|
||||
# Remember to update scripts/west-completion.bash if you add or remove
|
||||
# Remember to update west-completion.bash if you add or remove
|
||||
# flags
|
||||
|
||||
parser.add_argument('-b', '--board', help='board to build for')
|
||||
|
@ -110,8 +110,8 @@ class Build(Forceable):
|
|||
group.add_argument('--cmake-only', action='store_true',
|
||||
help="just run cmake; don't build (implies -c)")
|
||||
group.add_argument('-t', '--target',
|
||||
help='''run this build system target (try "-t usage"
|
||||
or "-t help")''')
|
||||
help='''run build system target TARGET
|
||||
(try "-t usage")''')
|
||||
group.add_argument('-o', '--build-opt', default=[], action='append',
|
||||
help='''options to pass to the build tool
|
||||
(make or ninja); may be given more than once''')
|
||||
|
|
|
@ -28,8 +28,8 @@ class Completion(WestCommand):
|
|||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=self.description)
|
||||
|
||||
# Remember to update completion/west-completion.bash if you add or
|
||||
# remove flags
|
||||
# Remember to update west-completion.bash if you add or remove
|
||||
# flags
|
||||
parser.add_argument('shell', nargs=1, choices=['bash'],
|
||||
help='''Select the shell that which the completion
|
||||
script is intended for.
|
||||
|
|
|
@ -591,8 +591,24 @@ __comp_west_boards()
|
|||
{
|
||||
local boards_args_opts="
|
||||
--format -f --name -n
|
||||
--arch-root --board-root
|
||||
"
|
||||
|
||||
case "$prev" in
|
||||
--format|-f|--name|-n)
|
||||
# We don't know how to autocomplete these.
|
||||
return
|
||||
;;
|
||||
--arch-root)
|
||||
__set_comp_dirs
|
||||
return
|
||||
;;
|
||||
--board-root)
|
||||
__set_comp_dirs
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
__set_comp $boards_args_opts
|
||||
|
|
|
@ -82,7 +82,7 @@ def add_parser_common(command, parser_adder=None, parser=None):
|
|||
help=command.help,
|
||||
description=command.description)
|
||||
|
||||
# Remember to update scripts/west-completion.bash if you add or remove
|
||||
# Remember to update west-completion.bash if you add or remove
|
||||
# flags
|
||||
|
||||
group = parser.add_argument_group('general options',
|
||||
|
|
Loading…
Reference in a new issue