Skip to content
Browse files

west: runners: Guess build folder

When using a build folder format with build.dir-fmt that includes any
parameters that need resolving, the west runners cannot find the folder
since the required information (board, source dir or app) is not
Add a very simple heuristic to support the case where a build folder
starts with a hardcoded prefix (for example 'build/') and a single build
is present under that prefix.
The heuristic is gated behind a new configuration option:

Signed-off-by: Carles Cufi <>
  • Loading branch information...
carlescufi authored and nashif committed Jun 17, 2019
1 parent 2192f1d commit 41f1f648f63928f6691abe3384bbc2ccb0fd2075
@@ -219,6 +219,16 @@ You can :ref:`configure <west-config-cmd>` ``west build`` using these options.
- String, default ``Ninja``. The `CMake Generator`_ to use to create a
build system. (To set a generator for a single build, see the
:ref:`above example <west-building-generator>`)
* - ``build.guess-dir``
- String, instructs west whether to try to guess what build folder to use
when ``build.dir-fmt`` is in use and not enough information is available
to resolve the build folder name. Can take these values:

- ``never`` (default): Never try to guess, bail out instead and
require the user to provide a build folder with ``-d``.
- ``runners``: Try to guess the folder when using any of the 'runner'
commands. These are typically all commands that invoke an external
tool, such as ``flash`` and ``debug``.
* - ``build.pristine``
- String. Controls the way in which ``west build`` may clean the build
folder before building. Can take the following values:
@@ -12,6 +12,7 @@

import zcmake
import os
from pathlib import Path
from west import log
from west.configuration import config
from west.util import escapes_directory
@@ -28,7 +29,7 @@
checked, in that order. If one is a Zephyr build directory, it is used.

def _resolve_build_dir(fmt, cwd, **kwargs):
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
@@ -40,9 +41,38 @@ def _resolve_build_dir(fmt, cwd, **kwargs):
# no meaningful relative path possible
kwargs['source_dir'] = ''

return fmt.format(**kwargs)
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)
# 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:
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, **kwargs):
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
@@ -60,12 +90,8 @@ def find_build_dir(dir, **kwargs):
cwd = os.getcwd()
default = config.get('build', 'dir-fmt', fallback=DEFAULT_BUILD_DIR)
default = _resolve_build_dir(default, cwd, **kwargs)
log.dbg('config dir-fmt: {}'.format(default),
except KeyError:
default = None
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):
@@ -19,6 +19,7 @@
from build_helpers import find_build_dir, is_zephyr_build, \
from west.commands import CommandError
from west.configuration import config

from runners import get_runner_cls, ZephyrBinaryRunner, MissingProgram

@@ -170,7 +171,9 @@ def _build_dir(args, die_if_none=True):
if args.build_dir:
return args.build_dir

dir = find_build_dir(None)
guess = config.get('build', 'guess-dir', fallback='never')
guess = True if guess == 'runners' else False
dir = find_build_dir(None, guess)

if dir and is_zephyr_build(dir):
return dir

0 comments on commit 41f1f64

Please sign in to comment.
You can’t perform that action at this time.