blob: 2b2e3083bf6f5e4f05c89fac212f5984f45f598e [file] [log] [blame]
Marti Bolivarab822642019-01-23 08:31:06 -07001# Copyright (c) 2018 Foundries.io
2#
3# SPDX-License-Identifier: Apache-2.0
4
5import argparse
6import os
Mikkel Jakobsen98eb3162020-03-04 15:14:43 +01007import pathlib
Martí Bolívar0186ead2019-12-09 11:05:11 -08008import shlex
Torsten Rasmussenef3c5e52020-06-08 21:09:15 +02009import sys
Marti Bolivarab822642019-01-23 08:31:06 -070010
11from west import log
Carles Cufib7c75912019-04-14 21:52:45 +020012from west.configuration import config
Jan Van Winkel4d975db2019-05-04 14:44:56 +020013from zcmake import DEFAULT_CMAKE_GENERATOR, run_cmake, run_build, CMakeCache
Marti Bolivar69099e32019-05-04 13:16:15 -060014from build_helpers import is_zephyr_build, find_build_dir, \
Carles Cufi98980c62019-06-05 16:04:29 +020015 FIND_BUILD_DIR_DESCRIPTION
Marti Bolivar8c447992019-01-30 13:53:40 -070016
Carles Cufi31bdad52019-04-26 21:53:02 +020017from zephyr_ext_common import Forceable
Marti Bolivar8c447992019-01-30 13:53:40 -070018
Carles Cufib7101772019-02-21 15:58:19 +010019_ARG_SEPARATOR = '--'
Marti Bolivarab822642019-01-23 08:31:06 -070020
Marti Bolivar1f5e6d82019-05-01 16:48:04 -060021BUILD_USAGE = '''\
22west build [-h] [-b BOARD] [-d BUILD_DIR]
23 [-t TARGET] [-p {auto, always, never}] [-c] [--cmake-only]
Marti Bolivar3a486a82019-05-04 13:32:36 -060024 [-n] [-o BUILD_OPT] [-f]
25 [source_dir] -- [cmake_opt [cmake_opt ...]]
Marti Bolivar1f5e6d82019-05-01 16:48:04 -060026'''
27
Martí Bolívar6e4c2b92020-06-25 12:58:58 -070028BUILD_DESCRIPTION = f'''\
Marti Bolivarab822642019-01-23 08:31:06 -070029Convenience wrapper for building Zephyr applications.
30
Martí Bolívar6e4c2b92020-06-25 12:58:58 -070031{FIND_BUILD_DIR_DESCRIPTION}
32
Carles Cufib7101772019-02-21 15:58:19 +010033positional arguments:
Martí Bolívar6e4c2b92020-06-25 12:58:58 -070034 source_dir application source directory
35 cmake_opt extra options to pass to cmake; implies -c
36 (these must come after "--" as shown above)
Carles Cufib7101772019-02-21 15:58:19 +010037'''
Marti Bolivarab822642019-01-23 08:31:06 -070038
Martí Bolívar6e4c2b92020-06-25 12:58:58 -070039PRISTINE_DESCRIPTION = """\
40A "pristine" build directory is empty. The -p option controls
41whether the build directory is made pristine before the build
42is done. A bare '--pristine' with no value is the same as
43--pristine=always. Setting --pristine=auto uses heuristics to
44guess if a pristine build may be necessary."""
45
Marti Bolivare6873b82019-06-02 22:48:52 -060046def _banner(msg):
47 log.inf('-- west build: ' + msg, colorize=True)
48
Marti Bolivard1595032019-05-04 13:14:28 -060049def config_get(option, fallback):
50 return config.get('build', option, fallback=fallback)
51
52def config_getboolean(option, fallback):
53 return config.getboolean('build', option, fallback=fallback)
54
Carles Cufib7c75912019-04-14 21:52:45 +020055class AlwaysIfMissing(argparse.Action):
56
Marti Bolivar69099e32019-05-04 13:16:15 -060057 def __call__(self, parser, namespace, values, option_string=None):
58 setattr(namespace, self.dest, values or 'always')
Marti Bolivarab822642019-01-23 08:31:06 -070059
Marti Bolivar8c447992019-01-30 13:53:40 -070060class Build(Forceable):
Marti Bolivarab822642019-01-23 08:31:06 -070061
62 def __init__(self):
63 super(Build, self).__init__(
64 'build',
Marti Bolivar808028b2019-01-28 10:45:02 -070065 # Keep this in sync with the string in west-commands.yml.
Marti Bolivarab822642019-01-23 08:31:06 -070066 'compile a Zephyr application',
67 BUILD_DESCRIPTION,
Carles Cufib7101772019-02-21 15:58:19 +010068 accepts_unknown_args=True)
Marti Bolivarab822642019-01-23 08:31:06 -070069
70 self.source_dir = None
71 '''Source directory for the build, or None on error.'''
72
73 self.build_dir = None
74 '''Final build directory used to run the build, or None on error.'''
75
76 self.created_build_dir = False
77 '''True if the build directory was created; False otherwise.'''
78
79 self.run_cmake = False
80 '''True if CMake was run; False otherwise.
81
82 Note: this only describes CMake runs done by this command. The
83 build system generated by CMake may also update itself due to
84 internal logic.'''
85
86 self.cmake_cache = None
87 '''Final parsed CMake cache for the build, or None on error.'''
88
89 def do_add_parser(self, parser_adder):
90 parser = parser_adder.add_parser(
91 self.name,
92 help=self.help,
93 formatter_class=argparse.RawDescriptionHelpFormatter,
Carles Cufib7101772019-02-21 15:58:19 +010094 description=self.description,
Marti Bolivar1f5e6d82019-05-01 16:48:04 -060095 usage=BUILD_USAGE)
Marti Bolivarab822642019-01-23 08:31:06 -070096
Martí Bolívar0d5e6c12020-12-09 15:53:00 -080097 # Remember to update west-completion.bash if you add or remove
Marti Bolivarab822642019-01-23 08:31:06 -070098 # flags
99
Martí Bolívar6e4c2b92020-06-25 12:58:58 -0700100 parser.add_argument('-b', '--board', help='board to build for')
Carles Cufib7101772019-02-21 15:58:19 +0100101 # Hidden option for backwards compatibility
102 parser.add_argument('-s', '--source-dir', help=argparse.SUPPRESS)
Marti Bolivarab822642019-01-23 08:31:06 -0700103 parser.add_argument('-d', '--build-dir',
Martí Bolívar6e4c2b92020-06-25 12:58:58 -0700104 help='build directory to create or use')
Marti Bolivar8c447992019-01-30 13:53:40 -0700105 self.add_force_arg(parser)
Martí Bolívar6e4c2b92020-06-25 12:58:58 -0700106
107 group = parser.add_argument_group('cmake and build tool')
108 group.add_argument('-c', '--cmake', action='store_true',
109 help='force a cmake run')
110 group.add_argument('--cmake-only', action='store_true',
111 help="just run cmake; don't build (implies -c)")
112 group.add_argument('-t', '--target',
Martí Bolívar0d5e6c12020-12-09 15:53:00 -0800113 help='''run build system target TARGET
114 (try "-t usage")''')
Martí Bolívar6e4c2b92020-06-25 12:58:58 -0700115 group.add_argument('-o', '--build-opt', default=[], action='append',
116 help='''options to pass to the build tool
117 (make or ninja); may be given more than once''')
118 group.add_argument('-n', '--just-print', '--dry-run', '--recon',
119 dest='dry_run', action='store_true',
120 help="just print build commands; don't run them")
121
122 group = parser.add_argument_group('pristine builds',
123 PRISTINE_DESCRIPTION)
124 group.add_argument('-p', '--pristine', choices=['auto', 'always',
125 'never'], action=AlwaysIfMissing, nargs='?',
126 help='pristine build folder setting')
127
Marti Bolivarab822642019-01-23 08:31:06 -0700128 return parser
129
Carles Cufib7101772019-02-21 15:58:19 +0100130 def do_run(self, args, remainder):
Marti Bolivarab822642019-01-23 08:31:06 -0700131 self.args = args # Avoid having to pass them around
Marti Bolivar8b9b7e72019-05-23 09:31:31 -0600132 self.config_board = config_get('board', None)
Marti Bolivara1ef6962019-05-01 17:06:15 -0600133 log.dbg('args: {} remainder: {}'.format(args, remainder),
134 level=log.VERBOSE_EXTREME)
Carles Cufib7101772019-02-21 15:58:19 +0100135 # Store legacy -s option locally
136 source_dir = self.args.source_dir
137 self._parse_remainder(remainder)
138 if source_dir:
139 if self.args.source_dir:
140 log.die("source directory specified twice:({} and {})".format(
141 source_dir, self.args.source_dir))
142 self.args.source_dir = source_dir
143 log.dbg('source_dir: {} cmake_opts: {}'.format(self.args.source_dir,
Marti Bolivara1ef6962019-05-01 17:06:15 -0600144 self.args.cmake_opts),
145 level=log.VERBOSE_EXTREME)
Marti Bolivarab822642019-01-23 08:31:06 -0700146 self._sanity_precheck()
147 self._setup_build_dir()
Carles Cufib7c75912019-04-14 21:52:45 +0200148
149 if args.pristine is not None:
150 pristine = args.pristine
151 else:
152 # Load the pristine={auto, always, never} configuration value
Martí Bolívarc19c6fb2021-01-15 09:17:01 -0800153 pristine = config_get('pristine', 'never')
Carles Cufib7c75912019-04-14 21:52:45 +0200154 if pristine not in ['auto', 'always', 'never']:
Marti Bolivar69099e32019-05-04 13:16:15 -0600155 log.wrn(
156 'treating unknown build.pristine value "{}" as "never"'.
157 format(pristine))
Carles Cufib7c75912019-04-14 21:52:45 +0200158 pristine = 'never'
159 self.auto_pristine = (pristine == 'auto')
160
161 log.dbg('pristine: {} auto_pristine: {}'.format(pristine,
Marti Bolivara1ef6962019-05-01 17:06:15 -0600162 self.auto_pristine),
163 level=log.VERBOSE_VERY)
Marti Bolivarab822642019-01-23 08:31:06 -0700164 if is_zephyr_build(self.build_dir):
Carles Cufib7c75912019-04-14 21:52:45 +0200165 if pristine == 'always':
Carles Cufi3a88dce2019-04-18 16:46:12 +0200166 self._run_pristine()
Marti Bolivarab822642019-01-23 08:31:06 -0700167 self.run_cmake = True
Carles Cufib7c75912019-04-14 21:52:45 +0200168 else:
169 self._update_cache()
Marti Bolivar1f5e6d82019-05-01 16:48:04 -0600170 if (self.args.cmake or self.args.cmake_opts or
171 self.args.cmake_only):
Carles Cufib7c75912019-04-14 21:52:45 +0200172 self.run_cmake = True
Marti Bolivarab822642019-01-23 08:31:06 -0700173 else:
174 self.run_cmake = True
Carles Cufi98980c62019-06-05 16:04:29 +0200175 self.source_dir = self._find_source_dir()
Marti Bolivarab822642019-01-23 08:31:06 -0700176 self._sanity_check()
177
Marti Bolivar88fb8ba2019-05-04 13:14:57 -0600178 board, origin = self._find_board()
179 self._run_cmake(board, origin, self.args.cmake_opts)
Marti Bolivar1f5e6d82019-05-01 16:48:04 -0600180 if args.cmake_only:
181 return
182
Marti Bolivarab822642019-01-23 08:31:06 -0700183 self._sanity_check()
184 self._update_cache()
185
Carles Cufib7c75912019-04-14 21:52:45 +0200186 self._run_build(args.target)
Marti Bolivarab822642019-01-23 08:31:06 -0700187
Marti Bolivar88fb8ba2019-05-04 13:14:57 -0600188 def _find_board(self):
189 board, origin = None, None
Marti Bolivar88fb8ba2019-05-04 13:14:57 -0600190 if self.cmake_cache:
191 board, origin = (self.cmake_cache.get('CACHED_BOARD'),
192 'CMakeCache.txt')
193 elif self.args.board:
194 board, origin = self.args.board, 'command line'
195 elif 'BOARD' in os.environ:
196 board, origin = os.environ['BOARD'], 'env'
Marti Bolivar8b9b7e72019-05-23 09:31:31 -0600197 elif self.config_board is not None:
198 board, origin = self.config_board, 'configfile'
Marti Bolivar88fb8ba2019-05-04 13:14:57 -0600199 return board, origin
200
Carles Cufib7101772019-02-21 15:58:19 +0100201 def _parse_remainder(self, remainder):
202 self.args.source_dir = None
203 self.args.cmake_opts = None
204 try:
205 # Only one source_dir is allowed, as the first positional arg
206 if remainder[0] != _ARG_SEPARATOR:
207 self.args.source_dir = remainder[0]
208 remainder = remainder[1:]
209 # Only the first argument separator is consumed, the rest are
210 # passed on to CMake
211 if remainder[0] == _ARG_SEPARATOR:
212 remainder = remainder[1:]
Ulf Magnusson5d307c92019-09-02 15:35:56 +0200213 if remainder:
Carles Cufib7101772019-02-21 15:58:19 +0100214 self.args.cmake_opts = remainder
215 except IndexError:
216 return
217
Marti Bolivarab822642019-01-23 08:31:06 -0700218 def _sanity_precheck(self):
219 app = self.args.source_dir
220 if app:
Marti Bolivar8c447992019-01-30 13:53:40 -0700221 self.check_force(
222 os.path.isdir(app),
223 'source directory {} does not exist'.format(app))
224 self.check_force(
225 'CMakeLists.txt' in os.listdir(app),
226 "{} doesn't contain a CMakeLists.txt".format(app))
Marti Bolivarab822642019-01-23 08:31:06 -0700227
228 def _update_cache(self):
229 try:
Carles Cufi31bdad52019-04-26 21:53:02 +0200230 self.cmake_cache = CMakeCache.from_build_dir(self.build_dir)
Marti Bolivarab822642019-01-23 08:31:06 -0700231 except FileNotFoundError:
232 pass
233
234 def _setup_build_dir(self):
235 # Initialize build_dir and created_build_dir attributes.
Marti Bolivar8c447992019-01-30 13:53:40 -0700236 # If we created the build directory, we must run CMake.
Marti Bolivarab822642019-01-23 08:31:06 -0700237 log.dbg('setting up build directory', level=log.VERBOSE_EXTREME)
Carles Cufi98980c62019-06-05 16:04:29 +0200238 # The CMake Cache has not been loaded yet, so this is safe
Ulf Magnusson89efaed2019-09-05 13:44:09 +0200239 board, _ = self._find_board()
Carles Cufi98980c62019-06-05 16:04:29 +0200240 source_dir = self._find_source_dir()
241 app = os.path.split(source_dir)[1]
242 build_dir = find_build_dir(self.args.build_dir, board=board,
243 source_dir=source_dir, app=app)
244 if not build_dir:
245 log.die('Unable to determine a default build folder. Check '
246 'your build.dir-fmt configuration option')
Marti Bolivarab822642019-01-23 08:31:06 -0700247
248 if os.path.exists(build_dir):
249 if not os.path.isdir(build_dir):
250 log.die('build directory {} exists and is not a directory'.
251 format(build_dir))
252 else:
253 os.makedirs(build_dir, exist_ok=False)
254 self.created_build_dir = True
255 self.run_cmake = True
256
257 self.build_dir = build_dir
258
Carles Cufi98980c62019-06-05 16:04:29 +0200259 def _find_source_dir(self):
Marti Bolivarab822642019-01-23 08:31:06 -0700260 # Initialize source_dir attribute, either from command line argument,
261 # implicitly from the build directory's CMake cache, or using the
262 # default (current working directory).
263 log.dbg('setting up source directory', level=log.VERBOSE_EXTREME)
264 if self.args.source_dir:
265 source_dir = self.args.source_dir
266 elif self.cmake_cache:
Marti Bolivaracda2572019-04-10 17:09:17 -0600267 source_dir = self.cmake_cache.get('CMAKE_HOME_DIRECTORY')
Marti Bolivarab822642019-01-23 08:31:06 -0700268 if not source_dir:
Marti Bolivaracda2572019-04-10 17:09:17 -0600269 # This really ought to be there. The build directory
270 # must be corrupted somehow. Let's see what we can do.
271 log.die('build directory', self.build_dir,
272 'CMake cache has no CMAKE_HOME_DIRECTORY;',
273 'please give a source_dir')
Marti Bolivarab822642019-01-23 08:31:06 -0700274 else:
275 source_dir = os.getcwd()
Carles Cufi98980c62019-06-05 16:04:29 +0200276 return os.path.abspath(source_dir)
Marti Bolivarab822642019-01-23 08:31:06 -0700277
Carles Cufib7c75912019-04-14 21:52:45 +0200278 def _sanity_check_source_dir(self):
Marti Bolivarab822642019-01-23 08:31:06 -0700279 if self.source_dir == self.build_dir:
280 # There's no forcing this.
281 log.die('source and build directory {} cannot be the same; '
282 'use --build-dir {} to specify a build directory'.
283 format(self.source_dir, self.build_dir))
284
285 srcrel = os.path.relpath(self.source_dir)
Marti Bolivar8c447992019-01-30 13:53:40 -0700286 self.check_force(
287 not is_zephyr_build(self.source_dir),
288 'it looks like {srcrel} is a build directory: '
289 'did you mean --build-dir {srcrel} instead?'.
290 format(srcrel=srcrel))
291 self.check_force(
292 'CMakeLists.txt' in os.listdir(self.source_dir),
293 'source directory "{srcrel}" does not contain '
294 'a CMakeLists.txt; is this really what you '
295 'want to build? (Use -s SOURCE_DIR to specify '
296 'the application source directory)'.
297 format(srcrel=srcrel))
Carles Cufib7c75912019-04-14 21:52:45 +0200298
299 def _sanity_check(self):
300 # Sanity check the build configuration.
301 # Side effect: may update cmake_cache attribute.
302 log.dbg('sanity checking the build', level=log.VERBOSE_EXTREME)
303 self._sanity_check_source_dir()
304
Marti Bolivarab822642019-01-23 08:31:06 -0700305 if not self.cmake_cache:
306 return # That's all we can check without a cache.
307
Martí Bolívar877fc592020-04-10 15:39:55 -0700308 if "CMAKE_PROJECT_NAME" not in self.cmake_cache:
309 # This happens sometimes when a build system is not
310 # completely generated due to an error during the
311 # CMake configuration phase.
312 self.run_cmake = True
313
Marti Bolivarab822642019-01-23 08:31:06 -0700314 cached_app = self.cmake_cache.get('APPLICATION_SOURCE_DIR')
315 log.dbg('APPLICATION_SOURCE_DIR:', cached_app,
316 level=log.VERBOSE_EXTREME)
317 source_abs = (os.path.abspath(self.args.source_dir)
318 if self.args.source_dir else None)
319 cached_abs = os.path.abspath(cached_app) if cached_app else None
Marti Bolivar8c447992019-01-30 13:53:40 -0700320
Carles Cufib7c75912019-04-14 21:52:45 +0200321 log.dbg('pristine:', self.auto_pristine, level=log.VERBOSE_EXTREME)
Mikkel Jakobsen98eb3162020-03-04 15:14:43 +0100322
Marti Bolivar8c447992019-01-30 13:53:40 -0700323 # If the build directory specifies a source app, make sure it's
324 # consistent with --source-dir.
325 apps_mismatched = (source_abs and cached_abs and
Mikkel Jakobsen98eb3162020-03-04 15:14:43 +0100326 pathlib.PurePath(source_abs) != pathlib.PurePath(cached_abs))
327
Marti Bolivar8c447992019-01-30 13:53:40 -0700328 self.check_force(
Carles Cufib7c75912019-04-14 21:52:45 +0200329 not apps_mismatched or self.auto_pristine,
Marti Bolivar8c447992019-01-30 13:53:40 -0700330 'Build directory "{}" is for application "{}", but source '
Carles Cufib7c75912019-04-14 21:52:45 +0200331 'directory "{}" was specified; please clean it, use --pristine, '
332 'or use --build-dir to set another build directory'.
Marti Bolivar8c447992019-01-30 13:53:40 -0700333 format(self.build_dir, cached_abs, source_abs))
Mikkel Jakobsen98eb3162020-03-04 15:14:43 +0100334
Marti Bolivar8c447992019-01-30 13:53:40 -0700335 if apps_mismatched:
Marti Bolivarab822642019-01-23 08:31:06 -0700336 self.run_cmake = True # If they insist, we need to re-run cmake.
337
Marti Bolivar8b9b7e72019-05-23 09:31:31 -0600338 # If CACHED_BOARD is not defined, we need some other way to
339 # find the board.
Marti Bolivarab822642019-01-23 08:31:06 -0700340 cached_board = self.cmake_cache.get('CACHED_BOARD')
341 log.dbg('CACHED_BOARD:', cached_board, level=log.VERBOSE_EXTREME)
Marti Bolivar8b9b7e72019-05-23 09:31:31 -0600342 # If apps_mismatched and self.auto_pristine are true, we will
343 # run pristine on the build, invalidating the cached
344 # board. In that case, we need some way of getting the board.
Carles Cufib7c75912019-04-14 21:52:45 +0200345 self.check_force((cached_board and
346 not (apps_mismatched and self.auto_pristine))
Marti Bolivar8b9b7e72019-05-23 09:31:31 -0600347 or self.args.board or self.config_board or
348 os.environ.get('BOARD'),
349 'Cached board not defined, please provide it '
350 '(provide --board, set default with '
351 '"west config build.board <BOARD>", or set '
352 'BOARD in the environment)')
Marti Bolivarab822642019-01-23 08:31:06 -0700353
Marti Bolivar8c447992019-01-30 13:53:40 -0700354 # Check consistency between cached board and --board.
355 boards_mismatched = (self.args.board and cached_board and
356 self.args.board != cached_board)
357 self.check_force(
Carles Cufib7c75912019-04-14 21:52:45 +0200358 not boards_mismatched or self.auto_pristine,
Marti Bolivar8c447992019-01-30 13:53:40 -0700359 'Build directory {} targets board {}, but board {} was specified. '
Carles Cufib7c75912019-04-14 21:52:45 +0200360 '(Clean the directory, use --pristine, or use --build-dir to '
361 'specify a different one.)'.
Marti Bolivar8c447992019-01-30 13:53:40 -0700362 format(self.build_dir, cached_board, self.args.board))
Marti Bolivarab822642019-01-23 08:31:06 -0700363
Carles Cufib7c75912019-04-14 21:52:45 +0200364 if self.auto_pristine and (apps_mismatched or boards_mismatched):
Carles Cufi3a88dce2019-04-18 16:46:12 +0200365 self._run_pristine()
Carles Cufib7c75912019-04-14 21:52:45 +0200366 self.cmake_cache = None
367 log.dbg('run_cmake:', True, level=log.VERBOSE_EXTREME)
368 self.run_cmake = True
369
370 # Tricky corner-case: The user has not specified a build folder but
371 # there was one in the CMake cache. Since this is going to be
372 # invalidated, reset to CWD and re-run the basic tests.
373 if ((boards_mismatched and not apps_mismatched) and
Marti Bolivar69099e32019-05-04 13:16:15 -0600374 (not source_abs and cached_abs)):
Carles Cufi98980c62019-06-05 16:04:29 +0200375 self.source_dir = self._find_source_dir()
Carles Cufib7c75912019-04-14 21:52:45 +0200376 self._sanity_check_source_dir()
377
Marti Bolivar88fb8ba2019-05-04 13:14:57 -0600378 def _run_cmake(self, board, origin, cmake_opts):
Marti Bolivar88fb8ba2019-05-04 13:14:57 -0600379 if board is None and config_getboolean('board_warn', True):
380 log.wrn('This looks like a fresh build and BOARD is unknown;',
381 "so it probably won't work. To fix, use",
382 '--board=<your-board>.')
383 log.inf('Note: to silence the above message, run',
384 "'west config build.board_warn false'")
385
Marti Bolivarab822642019-01-23 08:31:06 -0700386 if not self.run_cmake:
Marti Bolivarab822642019-01-23 08:31:06 -0700387 return
388
Marti Bolivare6873b82019-06-02 22:48:52 -0600389 _banner('generating a build system')
390
Marti Bolivar88fb8ba2019-05-04 13:14:57 -0600391 if board is not None and origin != 'CMakeCache.txt':
392 cmake_opts = ['-DBOARD={}'.format(board)]
393 else:
394 cmake_opts = []
395 if self.args.cmake_opts:
396 cmake_opts.extend(self.args.cmake_opts)
397
Martí Bolívar0186ead2019-12-09 11:05:11 -0800398 user_args = config_get('cmake-args', None)
399 if user_args:
400 cmake_opts.extend(shlex.split(user_args))
401
Carles Cufi3c6584d2019-04-14 21:51:16 +0200402 # Invoke CMake from the current working directory using the
403 # -S and -B options (officially introduced in CMake 3.13.0).
404 # This is important because users expect invocations like this
405 # to Just Work:
Marti Bolivarab822642019-01-23 08:31:06 -0700406 #
407 # west build -- -DOVERLAY_CONFIG=relative-path.conf
Torsten Rasmussenef3c5e52020-06-08 21:09:15 +0200408 final_cmake_args = ['-DWEST_PYTHON={}'.format(sys.executable),
409 '-B{}'.format(self.build_dir),
Carles Cufi3c6584d2019-04-14 21:51:16 +0200410 '-S{}'.format(self.source_dir),
Marti Bolivarbbe890a2019-05-01 16:53:32 -0600411 '-G{}'.format(config_get('generator',
412 DEFAULT_CMAKE_GENERATOR))]
Marti Bolivarab822642019-01-23 08:31:06 -0700413 if cmake_opts:
414 final_cmake_args.extend(cmake_opts)
Marti Bolivar8465cf22019-05-01 17:24:23 -0600415 run_cmake(final_cmake_args, dry_run=self.args.dry_run)
Carles Cufib7c75912019-04-14 21:52:45 +0200416
Carles Cufi3a88dce2019-04-18 16:46:12 +0200417 def _run_pristine(self):
Marti Bolivare6873b82019-06-02 22:48:52 -0600418 _banner('making build dir {} pristine'.format(self.build_dir))
Carles Cufi3a88dce2019-04-18 16:46:12 +0200419 if not is_zephyr_build(self.build_dir):
Marti Bolivar69099e32019-05-04 13:16:15 -0600420 log.die('Refusing to run pristine on a folder that is not a '
421 'Zephyr build system')
Carles Cufi3a88dce2019-04-18 16:46:12 +0200422
Torsten Rasmussene819fa42020-03-10 14:52:35 +0100423 cache = CMakeCache.from_build_dir(self.build_dir)
Torsten Rasmussen774103d2021-01-18 10:56:25 +0100424
425 app_src_dir = cache.get('APPLICATION_SOURCE_DIR')
426 app_bin_dir = cache.get('APPLICATION_BINARY_DIR')
427
428 cmake_args = [f'-DBINARY_DIR={app_bin_dir}',
429 f'-DSOURCE_DIR={app_src_dir}',
430 '-P', cache['ZEPHYR_BASE'] + '/cmake/pristine.cmake']
Marti Bolivar8465cf22019-05-01 17:24:23 -0600431 run_cmake(cmake_args, cwd=self.build_dir, dry_run=self.args.dry_run)
Carles Cufi3a88dce2019-04-18 16:46:12 +0200432
Carles Cufib7c75912019-04-14 21:52:45 +0200433 def _run_build(self, target):
Marti Bolivare6873b82019-06-02 22:48:52 -0600434 if target:
435 _banner('running target {}'.format(target))
Martí Bolívar34a59162020-03-05 14:20:18 -0800436 elif self.run_cmake:
Marti Bolivare6873b82019-06-02 22:48:52 -0600437 _banner('building application')
Carles Cufib7c75912019-04-14 21:52:45 +0200438 extra_args = ['--target', target] if target else []
Marti Bolivar3a486a82019-05-04 13:32:36 -0600439 if self.args.build_opt:
440 extra_args.append('--')
441 extra_args.extend(self.args.build_opt)
Marti Bolivar0396b6e2019-05-06 18:10:35 -0600442 if self.args.verbose:
443 self._append_verbose_args(extra_args,
444 not bool(self.args.build_opt))
Marti Bolivar8465cf22019-05-01 17:24:23 -0600445 run_build(self.build_dir, extra_args=extra_args,
446 dry_run=self.args.dry_run)
Marti Bolivar0396b6e2019-05-06 18:10:35 -0600447
448 def _append_verbose_args(self, extra_args, add_dashes):
449 # These hacks are only needed for CMake versions earlier than
450 # 3.14. When Zephyr's minimum version is at least that, we can
451 # drop this nonsense and just run "cmake --build BUILD -v".
452 self._update_cache()
453 if not self.cmake_cache:
454 return
455 generator = self.cmake_cache.get('CMAKE_GENERATOR')
456 if not generator:
457 return
458 # Substring matching is for things like "Eclipse CDT4 - Ninja".
459 if 'Ninja' in generator:
460 if add_dashes:
461 extra_args.append('--')
462 extra_args.append('-v')
463 elif generator == 'Unix Makefiles':
464 if add_dashes:
465 extra_args.append('--')
466 extra_args.append('VERBOSE=1')