blob: a54978ffc315c1da93304609b91c374779418e62 [file] [log] [blame]
Carles Cufi31bdad52019-04-26 21:53:02 +02001# Copyright 2018 (c) Foundries.io.
2#
3# SPDX-License-Identifier: Apache-2.0
4
5'''Common definitions for building Zephyr applications.
6
7This provides some default settings and convenience wrappers for
8building Zephyr applications needed by multiple commands.
9
10See build.py for the build command itself.
11'''
12
Jan Van Winkel4d975db2019-05-04 14:44:56 +020013import zcmake
Carles Cufi31bdad52019-04-26 21:53:02 +020014import os
Carles Cufi41f1f642019-06-17 11:47:11 +020015from pathlib import Path
Carles Cufi31bdad52019-04-26 21:53:02 +020016from west import log
Carles Cufi98980c62019-06-05 16:04:29 +020017from west.configuration import config
18from west.util import escapes_directory
Carles Cufi31bdad52019-04-26 21:53:02 +020019
20DEFAULT_BUILD_DIR = 'build'
21'''Name of the default Zephyr build directory.'''
22
23DEFAULT_CMAKE_GENERATOR = 'Ninja'
24'''Name of the default CMake generator.'''
25
Carles Cufi98980c62019-06-05 16:04:29 +020026FIND_BUILD_DIR_DESCRIPTION = '''\
Martí Bolívar6e4c2b92020-06-25 12:58:58 -070027If the build directory is not given, the default is {}/ unless the
Martí Bolívareb95bed2020-02-10 06:40:29 -080028build.dir-fmt configuration variable is set. The current directory is
29checked after that. If either is a Zephyr build directory, it is used.
Carles Cufi98980c62019-06-05 16:04:29 +020030'''.format(DEFAULT_BUILD_DIR)
Carles Cufi31bdad52019-04-26 21:53:02 +020031
Carles Cufi41f1f642019-06-17 11:47:11 +020032def _resolve_build_dir(fmt, guess, cwd, **kwargs):
Carles Cufi98980c62019-06-05 16:04:29 +020033 # Remove any None values, we do not want 'None' as a string
34 kwargs = {k: v for k, v in kwargs.items() if v is not None}
35 # Check if source_dir is below cwd first
36 source_dir = kwargs.get('source_dir')
37 if source_dir:
38 if escapes_directory(cwd, source_dir):
39 kwargs['source_dir'] = os.path.relpath(source_dir, cwd)
40 else:
41 # no meaningful relative path possible
42 kwargs['source_dir'] = ''
Carles Cufi31bdad52019-04-26 21:53:02 +020043
Carles Cufi41f1f642019-06-17 11:47:11 +020044 try:
45 return fmt.format(**kwargs)
46 except KeyError:
47 if not guess:
48 return None
Carles Cufi98980c62019-06-05 16:04:29 +020049
Carles Cufi41f1f642019-06-17 11:47:11 +020050 # Guess the build folder by iterating through all sub-folders from the
51 # root of the format string and trying to resolve. If resolving fails,
52 # proceed to iterate over subfolders only if there is a single folder
53 # present on each iteration.
54 parts = Path(fmt).parts
55 b = Path('.')
56 for p in parts:
57 # default to cwd in the first iteration
58 curr = b
59 b = b.joinpath(p)
60 try:
61 # if fmt is an absolute path, the first iteration will always
62 # resolve '/'
63 b = Path(str(b).format(**kwargs))
64 except KeyError:
65 # Missing key, check sub-folders and match if a single one exists
66 while True:
Carles Cufi4a504442019-09-06 15:18:41 +020067 if not curr.exists():
68 return None
Carles Cufi41f1f642019-06-17 11:47:11 +020069 dirs = [f for f in curr.iterdir() if f.is_dir()]
70 if len(dirs) != 1:
71 return None
72 curr = dirs[0]
73 if is_zephyr_build(str(curr)):
74 return str(curr)
75 return str(b)
76
77def find_build_dir(dir, guess=False, **kwargs):
Carles Cufi31bdad52019-04-26 21:53:02 +020078 '''Heuristic for finding a build directory.
79
Carles Cufi98980c62019-06-05 16:04:29 +020080 The default build directory is computed by reading the build.dir-fmt
81 configuration option, defaulting to DEFAULT_BUILD_DIR if not set. It might
82 be None if the build.dir-fmt configuration option is set but cannot be
83 resolved.
84 If the given argument is truthy, it is returned. Otherwise, if
85 the default build folder is a build directory, it is returned.
86 Next, if the current working directory is a build directory, it is
87 returned. Finally, the default build directory is returned (may be None).
88 '''
89
Carles Cufi31bdad52019-04-26 21:53:02 +020090 if dir:
91 build_dir = dir
92 else:
93 cwd = os.getcwd()
Carles Cufi98980c62019-06-05 16:04:29 +020094 default = config.get('build', 'dir-fmt', fallback=DEFAULT_BUILD_DIR)
Carles Cufi41f1f642019-06-17 11:47:11 +020095 default = _resolve_build_dir(default, guess, cwd, **kwargs)
96 log.dbg('config dir-fmt: {}'.format(default), level=log.VERBOSE_EXTREME)
Carles Cufi98980c62019-06-05 16:04:29 +020097 if default and is_zephyr_build(default):
Carles Cufi49c4b1c2019-06-03 12:43:38 +020098 build_dir = default
99 elif is_zephyr_build(cwd):
Carles Cufi31bdad52019-04-26 21:53:02 +0200100 build_dir = cwd
101 else:
Carles Cufi98980c62019-06-05 16:04:29 +0200102 build_dir = default
103 log.dbg('build dir: {}'.format(build_dir), level=log.VERBOSE_EXTREME)
104 if build_dir:
105 return os.path.abspath(build_dir)
106 else:
107 return None
Carles Cufi31bdad52019-04-26 21:53:02 +0200108
109def is_zephyr_build(path):
110 '''Return true if and only if `path` appears to be a valid Zephyr
111 build directory.
112
113 "Valid" means the given path is a directory which contains a CMake
Martí Bolívarf752c5e2020-10-06 16:36:24 -0700114 cache with a 'ZEPHYR_BASE' or 'ZEPHYR_TOOLCHAIN_VARIANT' variable.
115
116 (The check for ZEPHYR_BASE introduced sometime after Zephyr 2.4 to
117 fix https://github.com/zephyrproject-rtos/zephyr/issues/28876; we
118 keep support for the second variable around for compatibility with
119 versions 2.2 and earlier, which didn't have ZEPHYR_BASE in cache.
120 The cached ZEPHYR_BASE was added in
121 https://github.com/zephyrproject-rtos/zephyr/pull/23054.)
Carles Cufi31bdad52019-04-26 21:53:02 +0200122 '''
123 try:
Jan Van Winkel4d975db2019-05-04 14:44:56 +0200124 cache = zcmake.CMakeCache.from_build_dir(path)
Carles Cufi31bdad52019-04-26 21:53:02 +0200125 except FileNotFoundError:
126 cache = {}
127
Martí Bolívarf752c5e2020-10-06 16:36:24 -0700128 if 'ZEPHYR_BASE' in cache or 'ZEPHYR_TOOLCHAIN_VARIANT' in cache:
129 log.dbg(f'{path} is a zephyr build directory',
Carles Cufi31bdad52019-04-26 21:53:02 +0200130 level=log.VERBOSE_EXTREME)
131 return True
Martí Bolívarf752c5e2020-10-06 16:36:24 -0700132
133 log.dbg(f'{path} is NOT a valid zephyr build directory',
134 level=log.VERBOSE_EXTREME)
135 return False