scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
# Copyright (c) 2018 Open Source Foundries Limited.
|
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
'''Common code used by commands which execute runners.
|
|
|
|
'''
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
from os import getcwd, chdir
|
|
|
|
from subprocess import CalledProcessError
|
|
|
|
from textwrap import dedent
|
|
|
|
|
|
|
|
from .. import cmake
|
|
|
|
from .. import log
|
|
|
|
from ..runner import get_runner_cls
|
2018-05-10 00:58:03 -04:00
|
|
|
from ..runner.core import RunnerConfig
|
scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
from . import CommandContextError
|
|
|
|
|
|
|
|
|
|
|
|
def add_parser_common(parser_adder, command):
|
|
|
|
parser = parser_adder.add_parser(
|
|
|
|
command.name,
|
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
|
description=command.description)
|
|
|
|
|
2018-05-10 00:58:03 -04:00
|
|
|
group = parser.add_argument_group(title='General Options')
|
|
|
|
group.add_argument('-d', '--build-dir',
|
|
|
|
help='''Build directory to obtain runner information
|
|
|
|
from; default is the current working directory.''')
|
|
|
|
group.add_argument('-c', '--cmake-cache', default=cmake.DEFAULT_CACHE,
|
|
|
|
help='''Path to CMake cache file containing runner
|
|
|
|
configuration (this is generated by the Zephyr
|
|
|
|
build system when compiling binaries);
|
|
|
|
default: {}.
|
|
|
|
|
|
|
|
If this is a relative path, it is assumed relative to
|
|
|
|
the build directory. An absolute path can also be
|
|
|
|
given instead.'''.format(cmake.DEFAULT_CACHE))
|
|
|
|
group.add_argument('-r', '--runner',
|
|
|
|
help='''If given, overrides any cached {}
|
|
|
|
runner.'''.format(command.name))
|
|
|
|
group.add_argument('--skip-rebuild', action='store_true',
|
|
|
|
help='''If given, do not rebuild the application
|
|
|
|
before running {} commands.'''.format(command.name))
|
|
|
|
|
|
|
|
group = parser.add_argument_group(
|
|
|
|
title='Configuration overrides',
|
|
|
|
description=dedent('''\
|
|
|
|
These values usually come from the Zephyr build system itself
|
|
|
|
as stored in the CMake cache; providing these options
|
|
|
|
overrides those settings.'''))
|
|
|
|
|
|
|
|
# Important:
|
|
|
|
#
|
|
|
|
# 1. The destination variables of these options must match
|
|
|
|
# the RunnerConfig slots.
|
|
|
|
# 2. The default values for all of these must be None.
|
|
|
|
#
|
|
|
|
# This is how we detect if the user provided them or not when
|
|
|
|
# overriding values from the cached configuration.
|
|
|
|
group.add_argument('--board-dir',
|
|
|
|
help='Zephyr board directory')
|
|
|
|
group.add_argument('--kernel-elf',
|
|
|
|
help='Path to kernel binary in .elf format')
|
|
|
|
group.add_argument('--kernel-hex',
|
|
|
|
help='Path to kernel binary in .hex format')
|
|
|
|
group.add_argument('--kernel-bin',
|
|
|
|
help='Path to kernel binary in .bin format')
|
|
|
|
group.add_argument('--gdb',
|
|
|
|
help='Path to GDB, if applicable')
|
|
|
|
group.add_argument('--openocd',
|
|
|
|
help='Path to OpenOCD, if applicable')
|
|
|
|
group.add_argument(
|
|
|
|
'--openocd-search',
|
|
|
|
help='Path to add to OpenOCD search path, if applicable')
|
scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
|
|
|
|
return parser
|
|
|
|
|
|
|
|
|
|
|
|
def desc_common(command_name):
|
|
|
|
return dedent('''\
|
|
|
|
Any options not recognized by this command are passed to the
|
|
|
|
back-end {command} runner.
|
|
|
|
|
|
|
|
If you need to pass an option to a runner which has the
|
|
|
|
same name as one recognized by this command, you can
|
|
|
|
end argument parsing with a '--', like so:
|
|
|
|
|
|
|
|
west {command} --{command}-arg=value -- --runner-arg=value2
|
|
|
|
'''.format(**{'command': command_name}))
|
|
|
|
|
|
|
|
|
2018-05-10 00:58:03 -04:00
|
|
|
def cached_runner_config(cache):
|
|
|
|
'''Parse the RunnerConfig from a CMake Cache.'''
|
|
|
|
board_dir = cache['ZEPHYR_RUNNER_CONFIG_BOARD_DIR']
|
|
|
|
kernel_elf = cache['ZEPHYR_RUNNER_CONFIG_KERNEL_ELF']
|
|
|
|
kernel_hex = cache['ZEPHYR_RUNNER_CONFIG_KERNEL_HEX']
|
|
|
|
kernel_bin = cache['ZEPHYR_RUNNER_CONFIG_KERNEL_BIN']
|
|
|
|
gdb = cache.get('ZEPHYR_RUNNER_CONFIG_GDB')
|
|
|
|
openocd = cache.get('ZEPHYR_RUNNER_CONFIG_OPENOCD')
|
|
|
|
openocd_search = cache.get('ZEPHYR_RUNNER_CONFIG_OPENOCD_SEARCH')
|
|
|
|
|
|
|
|
return RunnerConfig(board_dir, kernel_elf, kernel_hex, kernel_bin,
|
|
|
|
gdb=gdb, openocd=openocd,
|
|
|
|
openocd_search=openocd_search)
|
|
|
|
|
|
|
|
|
|
|
|
def _override_config_from_namespace(cfg, namespace):
|
|
|
|
'''Override a RunnerConfig's contents with command-line values.'''
|
|
|
|
for var in cfg.__slots__:
|
|
|
|
if var in namespace:
|
|
|
|
val = getattr(namespace, var)
|
|
|
|
if val is not None:
|
|
|
|
setattr(cfg, var, val)
|
|
|
|
|
|
|
|
|
scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
def do_run_common(command, args, runner_args, cached_runner_var):
|
|
|
|
command_name = command.name
|
|
|
|
build_dir = args.build_dir or getcwd()
|
|
|
|
|
|
|
|
if not args.skip_rebuild:
|
|
|
|
try:
|
|
|
|
cmake.run_build(build_dir)
|
|
|
|
except CalledProcessError:
|
|
|
|
if args.build_dir:
|
|
|
|
log.die('cannot run {}, build in {} failed'.format(
|
|
|
|
command_name, args.build_dir))
|
|
|
|
else:
|
|
|
|
log.die('cannot run {}; no --build-dir given and build in '
|
|
|
|
'current directory {} failed'.format(command_name,
|
|
|
|
build_dir))
|
|
|
|
|
|
|
|
# Temporary hack: we need to ensure we're running from the build
|
|
|
|
# directory for now. Otherwise, the BuildConfiguration objects
|
|
|
|
# that get created by the runners look for .config in the wrong
|
|
|
|
# places.
|
|
|
|
chdir(build_dir)
|
|
|
|
|
2018-05-10 00:58:03 -04:00
|
|
|
# Runner creation, phase 1.
|
|
|
|
#
|
|
|
|
# Get the default runner name from the cache, allowing a command
|
|
|
|
# line override. Get the ZephyrBinaryRunner class by name, and
|
|
|
|
# make sure it supports the command.
|
|
|
|
|
scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
# TODO: build this by joining with build_dir once the above chdir
|
|
|
|
# goes away.
|
|
|
|
cache_file = args.cmake_cache
|
|
|
|
cache = cmake.CMakeCache(cache_file)
|
|
|
|
board = cache['CACHED_BOARD']
|
|
|
|
available = cache.get_list('ZEPHYR_RUNNERS')
|
|
|
|
if not available:
|
|
|
|
log.wrn('No cached runners are available in', cache_file)
|
|
|
|
runner = args.runner or cache.get(cached_runner_var)
|
|
|
|
|
|
|
|
if runner is None:
|
|
|
|
raise CommandContextError(dedent("""
|
|
|
|
No {} runner available for {}. Please either specify one
|
|
|
|
manually, or check your board's documentation for
|
|
|
|
alternative instructions.""".format(command_name, board)))
|
|
|
|
|
|
|
|
log.inf('Using runner:', runner)
|
|
|
|
if runner not in available:
|
|
|
|
log.wrn('Runner {} is not configured for use with {}, '
|
|
|
|
'this may not work'.format(runner, board))
|
|
|
|
runner_cls = get_runner_cls(runner)
|
|
|
|
if command_name not in runner_cls.capabilities().commands:
|
|
|
|
log.die('Runner {} does not support command {}'.format(
|
|
|
|
runner, command_name))
|
|
|
|
|
2018-05-10 00:58:03 -04:00
|
|
|
# Runner creation, phase 2.
|
|
|
|
#
|
|
|
|
# At this point, the common options above are already parsed in
|
|
|
|
# 'args', and unrecognized arguments are in 'runner_args'.
|
|
|
|
#
|
|
|
|
# - Pull the RunnerConfig out of the cache
|
|
|
|
# - Override cached values with applicable command-line options
|
|
|
|
|
|
|
|
cfg = cached_runner_config(cache)
|
|
|
|
_override_config_from_namespace(cfg, args)
|
|
|
|
|
|
|
|
# Runner creation, phase 3.
|
|
|
|
#
|
|
|
|
# - Pull out cached runner arguments, and append command-line
|
|
|
|
# values (which should override the cache)
|
|
|
|
# - Construct a runner-specific argument parser to handle cached
|
|
|
|
# values plus overrides given in runner_args
|
|
|
|
# - Parse arguments and create runner instance from final
|
|
|
|
# RunnerConfig and parsed arguments.
|
|
|
|
|
scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
cached_runner_args = cache.get_list(
|
|
|
|
'ZEPHYR_RUNNER_ARGS_{}'.format(cmake.make_c_identifier(runner)))
|
|
|
|
assert isinstance(runner_args, list), runner_args
|
2018-05-10 00:58:03 -04:00
|
|
|
# If the user passed -- to force the parent argument parser to stop
|
|
|
|
# parsing, it will show up here, and needs to be filtered out.
|
|
|
|
runner_args = [arg for arg in runner_args if arg != '--']
|
|
|
|
final_runner_args = cached_runner_args + runner_args
|
scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
parser = argparse.ArgumentParser(prog=runner)
|
|
|
|
runner_cls.add_parser(parser)
|
2018-05-10 00:58:03 -04:00
|
|
|
parsed_args, unknown = parser.parse_known_args(args=final_runner_args)
|
|
|
|
if unknown:
|
|
|
|
raise CommandContextError('Runner', runner,
|
|
|
|
'received unknown arguments', unknown)
|
|
|
|
runner = runner_cls.create(cfg, parsed_args)
|
scripts: west: add flash, debug, debugserver commands
When run without any arguments, the commands work the same way that
their CMake equivalents do. For example, if using the Ninja CMake
generator, these are equivalent:
west flash <----> ninja flash
west debug <----> ninja debug
west debugserver <----> ninja debugserver
Like CMake's build tool mode, you can also run them from any directory
in the system by passing the path to the build directory using
--build-dir (-d):
west flash -d build/my-board
The commands will run the CMake-generated build system, so they keep
dependencies up to date and users don't have to manually compile
binaries between running CMake and using this tool.
The commands also support important use cases that CMake can't:
1) Any arguments not handled by 'west flash' et al. are passed to the
underlying runner. For example, if the runner supports --gdb-port,
the default can be overridden like so:
west debugserver --gdb-port=1234
Command processing by the 'west' command can also be halted using
'--'; anything after that point (even if it's an option recognized
by the west command) will be passed to the runner. Example:
west debug -- --this-option-goes-to-the-debug-runner=foo
2) Any runner supported by the board can be selected at runtime using
the -r (--runner) option. For example, if the board's flash runner
defaults to nrfjprog but jlink is supported as well, it can be
selected with:
west flash -r jlink
3) The runner configuration can be persisted elsewhere, edited
offline, and selected at runtime, using --cmake-cache (-c):
west flash -c /home/me/some/other/CMakeCache.txt
Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
2018-05-09 18:16:30 -04:00
|
|
|
runner.run(command_name)
|