77
88from west import log
99from west import cmake
10+ from west .configuration import config
1011from west .build import DEFAULT_CMAKE_GENERATOR , is_zephyr_build
1112
1213from zephyr_ext_common import find_build_dir , Forceable , BUILD_DIR_DESCRIPTION
5253 cmake_opt Extra options to pass to CMake; implies -c
5354'''
5455
56+ class AlwaysIfMissing (argparse .Action ):
57+
58+ def __call__ (self , parser , namespace , values , option_string = None ):
59+ setattr (namespace , self .dest , values or 'always' )
5560
5661class Build (Forceable ):
5762
@@ -89,7 +94,7 @@ def do_add_parser(self, parser_adder):
8994 formatter_class = argparse .RawDescriptionHelpFormatter ,
9095 description = self .description ,
9196 usage = '''west build [-h] [-b BOARD] [-d BUILD_DIR]
92- [-t TARGET] [-c] [-f] [source_dir]
97+ [-t TARGET] [-p {auto, always, never}] [- c] [-f] [source_dir]
9398 -- [cmake_opt [cmake_opt ...]]''' )
9499
95100 # Remember to update scripts/west-completion.bash if you add or remove
@@ -106,6 +111,17 @@ def do_add_parser(self, parser_adder):
106111 parser .add_argument ('-t' , '--target' ,
107112 help = '''Override the build system target (e.g.
108113 'clean', 'pristine', etc.)''' )
114+ parser .add_argument ('-p' , '--pristine' , choices = ['auto' , 'always' ,
115+ 'never' ], action = AlwaysIfMissing , nargs = '?' ,
116+ help = '''Control whether the pristine target is run
117+ before building if a build system is present in the
118+ build dir. --pristine is the same as
119+ --pristine=always. If set to auto, the pristine
120+ target will be run only if required based on the
121+ existing build system and the options provided.
122+ This allows for reusing a build folder even if it
123+ contains build files for a different board or
124+ application.''' )
109125 parser .add_argument ('-c' , '--cmake' , action = 'store_true' ,
110126 help = 'Force CMake to run' )
111127 self .add_force_arg (parser )
@@ -127,10 +143,29 @@ def do_run(self, args, remainder):
127143 self .args .cmake_opts ))
128144 self ._sanity_precheck ()
129145 self ._setup_build_dir ()
146+
147+ if args .pristine is not None :
148+ pristine = args .pristine
149+ else :
150+ # Load the pristine={auto, always, never} configuration value
151+ pristine = config .get ('build' , 'pristine' , fallback = 'never' )
152+ if pristine not in ['auto' , 'always' , 'never' ]:
153+ log .wrn ('treating unknown build.pristine value "{}" as "never"' .
154+ format (pristine ))
155+ pristine = 'never'
156+ self .auto_pristine = (pristine == 'auto' )
157+
158+ log .dbg ('pristine: {} auto_pristine: {}' .format (pristine ,
159+ self .auto_pristine ))
130160 if is_zephyr_build (self .build_dir ):
131- self ._update_cache ()
132- if self .args .cmake or self .args .cmake_opts :
161+ if pristine == 'always' :
162+ log .inf ('Making build dir {} pristine' .format (self .build_dir ))
163+ self ._run_build ('pristine' )
133164 self .run_cmake = True
165+ else :
166+ self ._update_cache ()
167+ if self .args .cmake or self .args .cmake_opts :
168+ self .run_cmake = True
134169 else :
135170 self .run_cmake = True
136171 self ._setup_source_dir ()
@@ -154,8 +189,7 @@ def do_run(self, args, remainder):
154189 self ._sanity_check ()
155190 self ._update_cache ()
156191
157- extra_args = ['--target' , args .target ] if args .target else []
158- cmake .run_build (self .build_dir , extra_args = extra_args )
192+ self ._run_build (args .target )
159193
160194 def _parse_remainder (self , remainder ):
161195 self .args .source_dir = None
@@ -226,10 +260,7 @@ def _setup_source_dir(self):
226260 source_dir = os .getcwd ()
227261 self .source_dir = os .path .abspath (source_dir )
228262
229- def _sanity_check (self ):
230- # Sanity check the build configuration.
231- # Side effect: may update cmake_cache attribute.
232- log .dbg ('sanity checking the build' , level = log .VERBOSE_EXTREME )
263+ def _sanity_check_source_dir (self ):
233264 if self .source_dir == self .build_dir :
234265 # There's no forcing this.
235266 log .die ('source and build directory {} cannot be the same; '
@@ -249,6 +280,13 @@ def _sanity_check(self):
249280 'want to build? (Use -s SOURCE_DIR to specify '
250281 'the application source directory)' .
251282 format (srcrel = srcrel ))
283+
284+ def _sanity_check (self ):
285+ # Sanity check the build configuration.
286+ # Side effect: may update cmake_cache attribute.
287+ log .dbg ('sanity checking the build' , level = log .VERBOSE_EXTREME )
288+ self ._sanity_check_source_dir ()
289+
252290 self .check_force (
253291 is_zephyr_build (self .build_dir ) or self .args .board ,
254292 'this looks like a new or clean build, please provide --board' )
@@ -263,15 +301,16 @@ def _sanity_check(self):
263301 if self .args .source_dir else None )
264302 cached_abs = os .path .abspath (cached_app ) if cached_app else None
265303
304+ log .dbg ('pristine:' , self .auto_pristine , level = log .VERBOSE_EXTREME )
266305 # If the build directory specifies a source app, make sure it's
267306 # consistent with --source-dir.
268307 apps_mismatched = (source_abs and cached_abs and
269308 source_abs != cached_abs )
270309 self .check_force (
271- not apps_mismatched ,
310+ not apps_mismatched or self . auto_pristine ,
272311 'Build directory "{}" is for application "{}", but source '
273- 'directory "{}" was specified; please clean it or use --build-dir '
274- 'to set another build directory' .
312+ 'directory "{}" was specified; please clean it, use --pristine, '
313+ 'or use --build-dir to set another build directory' .
275314 format (self .build_dir , cached_abs , source_abs ))
276315 if apps_mismatched :
277316 self .run_cmake = True # If they insist, we need to re-run cmake.
@@ -280,19 +319,40 @@ def _sanity_check(self):
280319 # command line.
281320 cached_board = self .cmake_cache .get ('CACHED_BOARD' )
282321 log .dbg ('CACHED_BOARD:' , cached_board , level = log .VERBOSE_EXTREME )
283- self .check_force (cached_board or self .args .board ,
322+ # If app_mismatched and pristine are true we will run pristine on the
323+ # build, invalidating the cached board. Whenever we run pristine we
324+ # require the user to provide all the require inputs again.
325+ self .check_force ((cached_board and
326+ not (apps_mismatched and self .auto_pristine ))
327+ or self .args .board ,
284328 'Cached board not defined, please provide --board' )
285329
286330 # Check consistency between cached board and --board.
287331 boards_mismatched = (self .args .board and cached_board and
288332 self .args .board != cached_board )
289333 self .check_force (
290- not boards_mismatched ,
334+ not boards_mismatched or self . auto_pristine ,
291335 'Build directory {} targets board {}, but board {} was specified. '
292- '(Clean the directory or use --build-dir to specify a different '
293- 'one.)' .
336+ '(Clean the directory, use --pristine, or use --build-dir to '
337+ 'specify a different one.)' .
294338 format (self .build_dir , cached_board , self .args .board ))
295339
340+ if self .auto_pristine and (apps_mismatched or boards_mismatched ):
341+ log .inf ('Making build dir {} pristine' .format (self .build_dir ))
342+ self ._run_build ('pristine' )
343+ self .cmake_cache = None
344+ log .dbg ('run_cmake:' , True , level = log .VERBOSE_EXTREME )
345+ self .run_cmake = True
346+
347+ # Tricky corner-case: The user has not specified a build folder but
348+ # there was one in the CMake cache. Since this is going to be
349+ # invalidated, reset to CWD and re-run the basic tests.
350+ if ((boards_mismatched and not apps_mismatched ) and
351+ (not source_abs and cached_abs )):
352+ self ._setup_source_dir ()
353+ self ._sanity_check_source_dir ()
354+
355+
296356 def _run_cmake (self , cmake_opts ):
297357 if not self .run_cmake :
298358 log .dbg ('not running cmake; build system is present' )
@@ -312,3 +372,7 @@ def _run_cmake(self, cmake_opts):
312372 if cmake_opts :
313373 final_cmake_args .extend (cmake_opts )
314374 cmake .run_cmake (final_cmake_args )
375+
376+ def _run_build (self , target ):
377+ extra_args = ['--target' , target ] if target else []
378+ cmake .run_build (self .build_dir , extra_args = extra_args )
0 commit comments