123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- # Copyright 2018 (c) Foundries.io.
- #
- # SPDX-License-Identifier: Apache-2.0
- '''Common definitions for building Zephyr applications.
- This provides some default settings and convenience wrappers for
- building Zephyr applications needed by multiple commands.
- See build.py for the build command itself.
- '''
- import zcmake
- import os
- from pathlib import Path
- from west import log
- from west.configuration import config
- from west.util import escapes_directory
- DEFAULT_BUILD_DIR = 'build'
- '''Name of the default Zephyr build directory.'''
- DEFAULT_CMAKE_GENERATOR = 'Ninja'
- '''Name of the default CMake generator.'''
- FIND_BUILD_DIR_DESCRIPTION = '''\
- If the build directory is not given, the default is {}/ unless the
- build.dir-fmt configuration variable is set. The current directory is
- checked after that. If either is a Zephyr build directory, it is used.
- '''.format(DEFAULT_BUILD_DIR)
- def _resolve_build_dir(fmt, guess, cwd, **kwargs):
- # Remove any None values, we do not want 'None' as a string
- kwargs = {k: v for k, v in kwargs.items() if v is not None}
- # Check if source_dir is below cwd first
- source_dir = kwargs.get('source_dir')
- if source_dir:
- if escapes_directory(cwd, source_dir):
- kwargs['source_dir'] = os.path.relpath(source_dir, cwd)
- else:
- # no meaningful relative path possible
- kwargs['source_dir'] = ''
- try:
- return fmt.format(**kwargs)
- except KeyError:
- if not guess:
- return None
- # Guess the build folder by iterating through all sub-folders from the
- # root of the format string and trying to resolve. If resolving fails,
- # proceed to iterate over subfolders only if there is a single folder
- # present on each iteration.
- parts = Path(fmt).parts
- b = Path('.')
- for p in parts:
- # default to cwd in the first iteration
- curr = b
- b = b.joinpath(p)
- try:
- # if fmt is an absolute path, the first iteration will always
- # resolve '/'
- b = Path(str(b).format(**kwargs))
- except KeyError:
- # Missing key, check sub-folders and match if a single one exists
- while True:
- if not curr.exists():
- return None
- dirs = [f for f in curr.iterdir() if f.is_dir()]
- if len(dirs) != 1:
- return None
- curr = dirs[0]
- if is_zephyr_build(str(curr)):
- return str(curr)
- return str(b)
- def find_build_dir(dir, guess=False, **kwargs):
- '''Heuristic for finding a build directory.
- The default build directory is computed by reading the build.dir-fmt
- configuration option, defaulting to DEFAULT_BUILD_DIR if not set. It might
- be None if the build.dir-fmt configuration option is set but cannot be
- resolved.
- If the given argument is truthy, it is returned. Otherwise, if
- the default build folder is a build directory, it is returned.
- Next, if the current working directory is a build directory, it is
- returned. Finally, the default build directory is returned (may be None).
- '''
- if dir:
- build_dir = dir
- else:
- cwd = os.getcwd()
- default = config.get('build', 'dir-fmt', fallback=DEFAULT_BUILD_DIR)
- default = _resolve_build_dir(default, guess, cwd, **kwargs)
- log.dbg('config dir-fmt: {}'.format(default), level=log.VERBOSE_EXTREME)
- if default and is_zephyr_build(default):
- build_dir = default
- elif is_zephyr_build(cwd):
- build_dir = cwd
- else:
- build_dir = default
- log.dbg('build dir: {}'.format(build_dir), level=log.VERBOSE_EXTREME)
- if build_dir:
- return os.path.abspath(build_dir)
- else:
- return None
- def is_zephyr_build(path):
- '''Return true if and only if `path` appears to be a valid Zephyr
- build directory.
- "Valid" means the given path is a directory which contains a CMake
- cache with a 'ZEPHYR_BASE' or 'ZEPHYR_TOOLCHAIN_VARIANT' variable.
- (The check for ZEPHYR_BASE introduced sometime after Zephyr 2.4 to
- fix https://github.com/zephyrproject-rtos/zephyr/issues/28876; we
- keep support for the second variable around for compatibility with
- versions 2.2 and earlier, which didn't have ZEPHYR_BASE in cache.
- The cached ZEPHYR_BASE was added in
- https://github.com/zephyrproject-rtos/zephyr/pull/23054.)
- '''
- try:
- cache = zcmake.CMakeCache.from_build_dir(path)
- except FileNotFoundError:
- cache = {}
- if 'ZEPHYR_BASE' in cache or 'ZEPHYR_TOOLCHAIN_VARIANT' in cache:
- log.dbg(f'{path} is a zephyr build directory',
- level=log.VERBOSE_EXTREME)
- return True
- log.dbg(f'{path} is NOT a valid zephyr build directory',
- level=log.VERBOSE_EXTREME)
- return False
|