2020``-DVAR_NAME:BOOL=ON`` using the ``SetProgramOptions`` method ``gen_option_list``
2121with the ``bash`` generator.
2222
23- In the case of bash command entries the ``FORCE`` and ``PARENT_SCOPE`` optional
24- parameters are ignored.
23+ When using the BASH generator to generate command line arguments, CMake
24+ uses the syntax ``-D<VARNAME>[:<TYPE>]=<VALUE>``. The ``TYPE`` field is optional
25+ and if left out CMake will default to a ``STRING`` type. Further, all CMake
26+ variables set via the command line using ``-D`` will be CACHE variables and each
27+ ``-D`` operation should be considered a FORCE operation too. For example,
28+ ``-DFOO:STRING=BAR`` is roughly equivalent to the CMake command:
29+ ``set(FOO CACHE STRING "docstring" FORCE)``.
30+
31+ The ``PARENT_SCOPE`` option applies only to non-cache variables and its presence
32+ will instruct CMake to make that variable non-cache. Care should be taken when
33+ using ``PARENT_SCOPE`` as combining it with the usual CACHE operations results
34+ in CMake creating a non-cached variable whose contents are the list containing
35+ ``<varname>;CACHE;<type>;doc string``. As a result, the BASH generator issues
36+ warnings with no generated command line arguments when either 1. ``PARENT_SCOPE``
37+ OR 2. solely a variable name AND variable value are passed in to `opt-set-cmake-var`.
2538
2639See CMake documentation on the `set() <https://cmake.org/cmake/help/latest/command/set.html>`_
2740command for more information on how fragment file entries are generated.
3144
3245:Authors:
3346 - William C. McLendon III <wcmclen@sandia.gov>
47+ - Evan Harvey <eharvey@sandia.gov>
3448"""
3549from __future__ import print_function
50+ from enum import Enum
3651
3752#import inspect
3853#from pathlib import Path
@@ -73,7 +88,6 @@ class ExpandVarsInTextCMake(ExpandVarsInText):
7388
7489 def __init__ (self ):
7590 self .exception_control_level = 3
76- self .exception_control_compact_warnings = True
7791
7892 def _fieldhandler_BASH_CMAKE (self , field ):
7993 """
@@ -120,7 +134,10 @@ def _fieldhandler_CMAKE_FRAGMENT_CMAKE(self, field):
120134# M A I N C L A S S
121135# ===============================
122136
123-
137+ class VarType (Enum ):
138+ """Enumeration used to check for CMake variable types in SPOC."""
139+ CACHE = 1
140+ NON_CACHE = 2
124141
125142class SetProgramOptionsCMake (SetProgramOptions ):
126143 """Extends SetProgramOptions to add in CMake option support.
@@ -183,7 +200,7 @@ def _program_option_handler_opt_set_cmake_fragment(self, params: list, value: st
183200 """
184201 return None
185202
186- def _program_option_handler_opt_set_cmake_var_bash (self , params , value ) -> str :
203+ def _program_option_handler_opt_set_cmake_var_bash (self , params : list , value : str ) -> str :
187204 """
188205 Line-item generator for ``opt-set-cmake-var`` entries when the *generator*
189206 is set to ``bash``.
@@ -196,23 +213,50 @@ def _program_option_handler_opt_set_cmake_var_bash(self, params, value) -> str:
196213 side-effects since :py:meth:`setprogramoptions.SetProgramOptions._gen_option_entry`
197214 performs a deep-copy of these parameters prior to calling this.
198215 Any changes we make are ephemeral.
216+
217+ Args:
218+ params (list): The parameters of the operation.
219+ value (str): The value of the option that is being assigned.
220+
221+ Raises:
222+ ValueError: This can potentially raise a ``ValueError`` if
223+ ``exception_control_level`` is set to 5 if there are
224+ operations that are skipped in Bash generation. If ``ecl``
225+ is less than 5 then warnings are generated to note the
226+ exclusion.
199227 """
200228 varname = params [0 ]
201229 params = params [1 : 4 ]
202230 param_opts = self ._helper_opt_set_cmake_var_parse_parameters (params )
203231
204- params = ["-D" , varname ]
232+ # Type-1 (non-cached / PARENT_SCOPE / non-typed) entries should not be
233+ # written to the set of Bash parameters.
234+ if param_opts ['VARIANT' ] == VarType .NON_CACHE :
235+ msg = f"bash generator - `{ varname } ={ value } ` skipped because"
236+ msg += f" it is a non-cached (type-1) operation."
237+ msg += f" To generate a bash arg for this consider adding FORCE or a TYPE"
238+ msg += f" and remove PARENT_SCOPE if it exists."
239+ self .exception_control_event ("WARNING" , ValueError , message = msg )
240+ return None
241+
242+ # If varname has already been assigned and this assignment
243+ # does not include FORCE then we should skip adding it to the
244+ # set of command line options.
245+ if varname in self ._var_formatter_cache and not param_opts ['FORCE' ]:
246+ msg = f"bash generator - `{ varname } ={ value } ` skipped because"
247+ msg += f" CACHE var `{ varname } ` is already set and CMake requires"
248+ msg += f" FORCE to be set to change the value."
249+ self .exception_control_event ("WARNING" , ValueError , message = msg )
250+ return None
205251
206- if param_opts ['VARIANT' ] == 1 :
207- # if PARENT_SCOPE was given to something that is typed and forced us to
208- # be a type-1 variant, then we assign the list "<value>;CACHE;<type>;<docstring>"
209- if param_opts ['TYPE' ] != None :
210- value += f";CACHE;{ param_opts ['TYPE' ]} ;"
252+ # Prepend `-D` to the parameters
253+ params = ["-D" , varname ]
211254
212- if param_opts ['VARIANT' ] == 2 and param_opts ['TYPE' ] is not None :
213- params .append (":" + param_opts ['TYPE' ])
255+ # If the type is provided then include the `:<typename>` argument.
256+ # Note: CMake defaults to STRING if not provided.
257+ params .append (":" + param_opts ['TYPE' ])
214258
215- # Cache 'known' CMake vars here.
259+ # Save variable to the cache of 'known'/'set' cmake variables
216260 self ._var_formatter_cache [varname ] = value
217261
218262 return self ._generic_program_option_handler_bash (params , value )
@@ -339,12 +383,15 @@ def _helper_opt_set_cmake_var_parse_parameters(self, params: list):
339383 """
340384 default_cache_var_type = "STRING"
341385
342- output = {'FORCE' : False , 'PARENT_SCOPE' : False , 'TYPE' : None }
386+ output = {'FORCE' : False , 'PARENT_SCOPE' : False , 'TYPE' : None , 'VARIANT' : None }
343387
344388 for option in params [: 4 ]:
345389 if option == "FORCE" :
346390 output ['FORCE' ] = True
347391 # If FORCE is found but we have no TYPE yet, set to the default.
392+ # TODO: Should we be setting the default to STRING here when FORCE
393+ # is provided with no explicit type? Future CMake versions might
394+ # someday change the default which would possibly break this?
348395 if output ['TYPE' ] is None :
349396 output ['TYPE' ] = default_cache_var_type
350397 elif option == "PARENT_SCOPE" :
@@ -358,6 +405,7 @@ def _helper_opt_set_cmake_var_parse_parameters(self, params: list):
358405 if output ['FORCE' ] and output ['PARENT_SCOPE' ]:
359406 msg = "ERROR: CMake does not allow `FORCE` and `PARENT_SCOPE` to both be used."
360407 self .exception_control_event ("CATASTROPHIC" , ValueError , message = msg )
408+
361409 # Case 2: PARENT_SCOPE and CACHE will cause a CMake warning
362410 # and the value will include the cache entries as a list:
363411 # `set(FOO "VAL" CACHE STRING "docstring" PARENT_SCOPE)`
@@ -381,18 +429,18 @@ def _helper_opt_set_cmake_var_parse_parameters(self, params: list):
381429 # PARENT_SCOPE forces Type-1 (i.e., non-cache var)
382430 # - This will override CACHE, at least as of CMake 3.21.x
383431 if output ['PARENT_SCOPE' ]:
384- output ['VARIANT' ] = 1
432+ output ['VARIANT' ] = VarType . NON_CACHE
385433
386434 # FORCE implies CACHE. If type wasn't provided then it's a STRING
387435 elif output ['FORCE' ]:
388- output ['VARIANT' ] = 2
436+ output ['VARIANT' ] = VarType . CACHE
389437
390438 # If a TYPE is provided then it's a type-2 (CACHE) assignment.
391439 elif output ['TYPE' ] is not None :
392- output ['VARIANT' ] = 2
440+ output ['VARIANT' ] = VarType . CACHE
393441
394442 # Otherwise, a simple set is a type-1
395443 else :
396- output ['VARIANT' ] = 1
444+ output ['VARIANT' ] = VarType . NON_CACHE
397445
398446 return output
0 commit comments