def _dump_one_runner_info(cache, args, build_dir, indent): runner = args.runner cls = get_runner_cls(runner) if cache is None: _dump_runner_opt_help(runner, cls) _dump_runner_caps(cls, '') return available = runner in cache.get_list('ZEPHYR_RUNNERS') cfg = cached_runner_config(build_dir, cache) log.inf('Build directory:', colorize=True) log.inf(INDENT + build_dir) log.inf('Board:', colorize=True) log.inf(INDENT + cache['CACHED_BOARD']) log.inf('CMake cache:', colorize=True) log.inf(INDENT + cache.cache_file) log.inf(runner, 'is available:', 'yes' if available else 'no', colorize=True) _dump_runner_opt_help(runner, cls) _dump_runner_config(cfg, '', indent) if available: _dump_runner_cached_opts(cache, runner, '', indent) _dump_runner_caps(cls, '') if not available: log.wrn('Runner', runner, 'is not configured in this build.')
def sign(self, command, build_dir, bcfg, formats): if not formats: return args = command.args b = pathlib.Path(build_dir) cache = CMakeCache.from_build_dir(build_dir) tool_path = self.find_imgtool(command, args) # The vector table offset is set in Kconfig: vtoff = self.get_cfg(command, bcfg, 'CONFIG_TEXT_SECTION_OFFSET') # Flash device write alignment and the partition's slot size # come from devicetree: flash = self.edt_flash_node(b, cache) align, addr, size = self.edt_flash_params(flash) runner_config = cached_runner_config(build_dir, cache) if 'bin' in formats: in_bin = runner_config.bin_file if not in_bin: log.die("can't find unsigned .bin to sign") else: in_bin = None if 'hex' in formats: in_hex = runner_config.hex_file if not in_hex: log.die("can't find unsigned .hex to sign") else: in_hex = None log.banner('image configuration:') log.inf('partition offset: {0} (0x{0:x})'.format(addr)) log.inf('partition size: {0} (0x{0:x})'.format(size)) log.inf('text section offset: {0} (0x{0:x})'.format(vtoff)) # Base sign command. # # We provide a default --version in case the user is just # messing around and doesn't want to set one. It will be # overridden if there is a --version in args.tool_args. sign_base = [tool_path, 'sign', '--version', '0.0.0+0', '--align', str(align), '--header-size', str(vtoff), '--slot-size', str(size)] sign_base.extend(args.tool_args) log.banner('signed binaries:') if in_bin: out_bin = args.sbin or str(b / 'zephyr' / 'zephyr.signed.bin') sign_bin = sign_base + [in_bin, out_bin] log.inf('bin: {}'.format(out_bin)) log.dbg(quote_sh_list(sign_bin)) subprocess.check_call(sign_bin) if in_hex: out_hex = args.shex or str(b / 'zephyr' / 'zephyr.signed.hex') sign_hex = sign_base + [in_hex, out_hex] log.inf('hex: {}'.format(out_hex)) log.dbg(quote_sh_list(sign_hex)) subprocess.check_call(sign_hex)
def sign(self, args): cache = cmake.CMakeCache.from_build_dir(args.build_dir) runner_config = cached_runner_config(args.build_dir, cache) bcfg = BuildConfiguration(args.build_dir) # Build a signed .bin if args.gen_bin and runner_config.bin_file: sign_bin = self.sign_cmd(args, bcfg, runner_config.bin_file, args.sbin) log.dbg(quote_sh_list(sign_bin)) subprocess.check_call(sign_bin) # Build a signed .hex if args.gen_hex and runner_config.hex_file: sign_hex = self.sign_cmd(args, bcfg, runner_config.hex_file, args.shex) log.dbg(quote_sh_list(sign_hex)) subprocess.check_call(sign_hex)
def sign(self, command, build_dir, bcfg, formats): args = command.args if args.tool_path: command.check_force( shutil.which(args.tool_path), '--tool-path {}: not an executable'.format(args.tool_path)) tool_path = args.tool_path else: tool_path = shutil.which('imgtool') if not tool_path: log.die( 'imgtool not found; either install it', '(e.g. "pip3 install imgtool") or provide --tool-path') align, vtoff, slot_size = [ self.get_cfg(command, bcfg, x) for x in ('DT_FLASH_WRITE_BLOCK_SIZE', 'CONFIG_TEXT_SECTION_OFFSET', 'DT_FLASH_AREA_IMAGE_0_SIZE') ] log.dbg('build config: --align={}, --header-size={}, --slot-size={}'. format(align, vtoff, slot_size)) # Base sign command. # # We provide a default --version in case the user is just # messing around and doesn't want to set one. It will be # overridden if there is a --version in args.tool_args. sign_base = [tool_path, 'sign', '--version', '0.0.0+0'] if align: sign_base.extend(['--align', str(align)]) else: log.wrn('expected nonzero flash alignment, but ' 'DT_FLASH_WRITE_BLOCK_SIZE={} ' "in build directory's ({}) device tree".format( align, build_dir)) if vtoff: sign_base.extend(['--header-size', str(vtoff)]) else: log.wrn('expected nonzero header size, but ' 'CONFIG_TEXT_SECTION_OFFSET={} ' "in build directory's ({}) .config".format( vtoff, build_dir)) if slot_size: sign_base.extend(['--slot-size', str(slot_size)]) else: log.wrn('expected nonzero slot size, but ' 'DT_FLASH_AREA_IMAGE_0_SIZE={} ' "in build directory's ({}) device tree".format( slot_size, build_dir)) b = pathlib.Path(build_dir) cache = cmake.CMakeCache.from_build_dir(build_dir) runner_config = cached_runner_config(build_dir, cache) # Build a signed .bin if 'bin' in formats and runner_config.bin_file: out_bin = args.sbin or str(b / 'zephyr' / 'zephyr.signed.bin') log.inf('Generating:', out_bin) sign_bin = (sign_base + args.tool_args + [runner_config.bin_file, out_bin]) log.dbg(quote_sh_list(sign_bin)) subprocess.check_call(sign_bin) # Build a signed .hex if 'hex' in formats and runner_config.hex_file: out_hex = args.shex or str(b / 'zephyr' / 'zephyr.signed.hex') log.inf('Generating:', out_hex) sign_hex = (sign_base + args.tool_args + [runner_config.hex_file, out_hex]) log.dbg(quote_sh_list(sign_hex)) subprocess.check_call(sign_hex)
def _dump_context(command, args, runner_args, cached_runner_var): build_dir = _build_dir(args, die_if_none=False) # Try to figure out the CMake cache file based on the build # directory or an explicit argument. if build_dir is not None: cache_file = path.abspath( path.join(build_dir, args.cmake_cache or cmake.DEFAULT_CACHE)) elif args.cmake_cache: cache_file = path.abspath(args.cmake_cache) else: cache_file = None # Load the cache itself, if possible. if cache_file is None: log.wrn('No build directory (--build-dir) or CMake cache ' '(--cache-file) given or found; output will be limited') cache = None else: try: cache = cmake.CMakeCache(cache_file) except Exception: log.die('Cannot load cache {}.'.format(cache_file)) # If we have a build directory, try to ensure build artifacts are # up to date. If that doesn't work, still try to print information # on a best-effort basis. if build_dir and not args.skip_rebuild: try: cmake.run_build(build_dir) except CalledProcessError: msg = 'Failed re-building application; cannot load context. ' if args.build_dir: msg += 'Is {} the right --build-dir?'.format(args.build_dir) else: msg += textwrap.dedent('''\ Use --build-dir (-d) to specify a build directory; the one used was {}.'''.format(build_dir)) log.die('\n'.join( textwrap.wrap(msg, initial_indent='', subsequent_indent=INDENT, break_on_hyphens=False))) if cache is None: _dump_no_context_info(command, args) if not args.runner: return if args.runner: # Just information on one runner was requested. _dump_one_runner_info(cache, args, build_dir, INDENT) return board = cache['CACHED_BOARD'] all_cls = { cls.name(): cls for cls in ZephyrBinaryRunner.get_runners() if command.name in cls.capabilities().commands } available = [r for r in cache.get_list('ZEPHYR_RUNNERS') if r in all_cls] available_cls = {r: all_cls[r] for r in available if r in all_cls} default_runner = cache.get(cached_runner_var) cfg = cached_runner_config(build_dir, cache) log.inf('All Zephyr runners which support {}:'.format(command.name), colorize=True) for line in util.wrap(', '.join(all_cls.keys()), INDENT): log.inf(line) log.inf('(Not all may work with this build, see available runners below.)', colorize=True) if cache is None: log.warn('Missing or invalid CMake cache {}; there is no context.', 'Use --build-dir to specify the build directory.') return log.inf('Build directory:', colorize=True) log.inf(INDENT + build_dir) log.inf('Board:', colorize=True) log.inf(INDENT + board) log.inf('CMake cache:', colorize=True) log.inf(INDENT + cache_file) if not available: # Bail with a message if no runners are available. msg = ('No runners available for {}. ' 'Consult the documentation for instructions on how to run ' 'binaries on this target.').format(board) for line in util.wrap(msg, ''): log.inf(line, colorize=True) return log.inf('Available {} runners:'.format(command.name), colorize=True) log.inf(INDENT + ', '.join(available)) log.inf('Additional options for available', command.name, 'runners:', colorize=True) for runner in available: _dump_runner_opt_help(runner, all_cls[runner]) log.inf('Default {} runner:'.format(command.name), colorize=True) log.inf(INDENT + default_runner) _dump_runner_config(cfg, '', INDENT) log.inf('Runner-specific information:', colorize=True) for runner in available: log.inf('{}{}:'.format(INDENT, runner), colorize=True) _dump_runner_cached_opts(cache, runner, INDENT * 2, INDENT * 3) _dump_runner_caps(available_cls[runner], INDENT * 2) if len(available) > 1: log.inf('(Add -r RUNNER to just print information about one runner.)', colorize=True)
def do_run_common(command, args, runner_args, cached_runner_var): if args.context: _dump_context(command, args, runner_args, cached_runner_var) return command_name = command.name build_dir = _build_dir(args) 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)) # 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. cache_file = path.join(build_dir, args.cmake_cache or cmake.DEFAULT_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( textwrap.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)) # 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(build_dir, 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. cached_runner_args = cache.get_list('ZEPHYR_RUNNER_ARGS_{}'.format( cmake.make_c_identifier(runner))) assert isinstance(runner_args, list), runner_args # 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 parser = argparse.ArgumentParser(prog=runner) runner_cls.add_parser(parser) 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) runner.run(command_name)
def do_run_common(command, args, runner_args, cached_runner_var): if args.context: _dump_context(command, args, runner_args, cached_runner_var) return command_name = command.name build_dir = _build_dir(args) if not args.skip_rebuild: _banner('west {}: rebuilding'.format(command_name)) 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)) # 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. cache_file = path.join(build_dir, args.cmake_cache or cmake.DEFAULT_CACHE) try: cache = cmake.CMakeCache(cache_file) except FileNotFoundError: log.die('no CMake cache found (expected one at {})'.format(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: log.die('No', command_name, 'runner available for board', board, '({} is not in the cache).'.format(cached_runner_var), "Check your board's documentation for instructions.") _banner('west {}: using runner {}'.format(command_name, 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)) # Runner creation, phase 2. # # At this point, the common options above are already parsed in # 'args', and unrecognized arguments are in 'runner_args'. # # - Set up runner logging to delegate to west. # - Pull the RunnerConfig out of the cache # - Override cached values with applicable command-line options logger = logging.getLogger('runners') logger.setLevel(LOG_LEVEL) logger.addHandler(WestLogHandler()) cfg = cached_runner_config(build_dir, 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. cached_runner_args = cache.get_list('ZEPHYR_RUNNER_ARGS_{}'.format( cmake.make_c_identifier(runner))) assert isinstance(runner_args, list), runner_args # 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 parser = argparse.ArgumentParser(prog=runner) runner_cls.add_parser(parser) parsed_args, unknown = parser.parse_known_args(args=final_runner_args) if unknown: log.die('Runner', runner, 'received unknown arguments:', unknown) runner = runner_cls.create(cfg, parsed_args) try: runner.run(command_name) except ValueError as ve: log.err(str(ve), fatal=True) dump_traceback() raise CommandError(1) except MissingProgram as e: log.die('required program', e.filename, 'not found; install it or add its location to PATH')