20
20
``-DVAR_NAME:BOOL=ON`` using the ``SetProgramOptions`` method ``gen_option_list``
21
21
with the ``bash`` generator.
22
22
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`.
25
38
26
39
See CMake documentation on the `set() <https://cmake.org/cmake/help/latest/command/set.html>`_
27
40
command for more information on how fragment file entries are generated.
31
44
32
45
:Authors:
33
46
- William C. McLendon III <[email protected] >
47
+
34
48
"""
35
49
from __future__ import print_function
50
+ from enum import Enum
36
51
37
52
#import inspect
38
53
#from pathlib import Path
@@ -73,7 +88,6 @@ class ExpandVarsInTextCMake(ExpandVarsInText):
73
88
74
89
def __init__ (self ):
75
90
self .exception_control_level = 3
76
- self .exception_control_compact_warnings = True
77
91
78
92
def _fieldhandler_BASH_CMAKE (self , field ):
79
93
"""
@@ -120,7 +134,10 @@ def _fieldhandler_CMAKE_FRAGMENT_CMAKE(self, field):
120
134
# M A I N C L A S S
121
135
# ===============================
122
136
123
-
137
+ class VarType (Enum ):
138
+ """Enumeration used to check for CMake variable types in SPOC."""
139
+ CACHE = 1
140
+ NON_CACHE = 2
124
141
125
142
class SetProgramOptionsCMake (SetProgramOptions ):
126
143
"""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
183
200
"""
184
201
return None
185
202
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 :
187
204
"""
188
205
Line-item generator for ``opt-set-cmake-var`` entries when the *generator*
189
206
is set to ``bash``.
@@ -196,23 +213,50 @@ def _program_option_handler_opt_set_cmake_var_bash(self, params, value) -> str:
196
213
side-effects since :py:meth:`setprogramoptions.SetProgramOptions._gen_option_entry`
197
214
performs a deep-copy of these parameters prior to calling this.
198
215
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.
199
227
"""
200
228
varname = params [0 ]
201
229
params = params [1 : 4 ]
202
230
param_opts = self ._helper_opt_set_cmake_var_parse_parameters (params )
203
231
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
205
251
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 ]
211
254
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' ])
214
258
215
- # Cache 'known' CMake vars here.
259
+ # Save variable to the cache of 'known'/'set' cmake variables
216
260
self ._var_formatter_cache [varname ] = value
217
261
218
262
return self ._generic_program_option_handler_bash (params , value )
@@ -339,12 +383,15 @@ def _helper_opt_set_cmake_var_parse_parameters(self, params: list):
339
383
"""
340
384
default_cache_var_type = "STRING"
341
385
342
- output = {'FORCE' : False , 'PARENT_SCOPE' : False , 'TYPE' : None }
386
+ output = {'FORCE' : False , 'PARENT_SCOPE' : False , 'TYPE' : None , 'VARIANT' : None }
343
387
344
388
for option in params [: 4 ]:
345
389
if option == "FORCE" :
346
390
output ['FORCE' ] = True
347
391
# 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?
348
395
if output ['TYPE' ] is None :
349
396
output ['TYPE' ] = default_cache_var_type
350
397
elif option == "PARENT_SCOPE" :
@@ -358,6 +405,7 @@ def _helper_opt_set_cmake_var_parse_parameters(self, params: list):
358
405
if output ['FORCE' ] and output ['PARENT_SCOPE' ]:
359
406
msg = "ERROR: CMake does not allow `FORCE` and `PARENT_SCOPE` to both be used."
360
407
self .exception_control_event ("CATASTROPHIC" , ValueError , message = msg )
408
+
361
409
# Case 2: PARENT_SCOPE and CACHE will cause a CMake warning
362
410
# and the value will include the cache entries as a list:
363
411
# `set(FOO "VAL" CACHE STRING "docstring" PARENT_SCOPE)`
@@ -381,18 +429,18 @@ def _helper_opt_set_cmake_var_parse_parameters(self, params: list):
381
429
# PARENT_SCOPE forces Type-1 (i.e., non-cache var)
382
430
# - This will override CACHE, at least as of CMake 3.21.x
383
431
if output ['PARENT_SCOPE' ]:
384
- output ['VARIANT' ] = 1
432
+ output ['VARIANT' ] = VarType . NON_CACHE
385
433
386
434
# FORCE implies CACHE. If type wasn't provided then it's a STRING
387
435
elif output ['FORCE' ]:
388
- output ['VARIANT' ] = 2
436
+ output ['VARIANT' ] = VarType . CACHE
389
437
390
438
# If a TYPE is provided then it's a type-2 (CACHE) assignment.
391
439
elif output ['TYPE' ] is not None :
392
- output ['VARIANT' ] = 2
440
+ output ['VARIANT' ] = VarType . CACHE
393
441
394
442
# Otherwise, a simple set is a type-1
395
443
else :
396
- output ['VARIANT' ] = 1
444
+ output ['VARIANT' ] = VarType . NON_CACHE
397
445
398
446
return output
0 commit comments