129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
# 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 not given, the default build directory ({}/ unless the
|
|
build.dir-fmt configuration variable is set) and the current directory are
|
|
checked, in that order. If one 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_TOOLCHAIN_VARIANT' key.
|
|
'''
|
|
try:
|
|
cache = zcmake.CMakeCache.from_build_dir(path)
|
|
except FileNotFoundError:
|
|
cache = {}
|
|
|
|
if 'ZEPHYR_TOOLCHAIN_VARIANT' in cache:
|
|
log.dbg('{} is a zephyr build directory'.format(path),
|
|
level=log.VERBOSE_EXTREME)
|
|
return True
|
|
else:
|
|
log.dbg('{} is NOT a valid zephyr build directory'.format(path),
|
|
level=log.VERBOSE_EXTREME)
|
|
return False
|