# How to handle more than 10 config flags in if statement?

**URL:** <https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800>\
**Category:** Code\
**Created:** [July 21, 2021, 9:17am UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800 "2021-07-21T09:17:59Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![tbacarrot](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/d9b06d/32.png) [@tbacarrot](https://discourse.cmake.org/u/tbacarrot)\
**Post date:** [July 21, 2021, 9:17am UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/1 "2021-07-21T09:17:59Z")

</div>

Hi all,

In my project, an execution step is controlled by about 10 ~ 15 config flags. Currently I implement a piece of ugly code as shown below:

```
 if (CONFIG_A OR
     CONFIG_B OR
     CONFIG_C OR
     CONFIG_D OR
     ...
     CONFIG_X)
         some code here
 endif()

```

Can I ask for your suggestion to improve the code above? Any “Modern CMake” style to handle this case?  
Any suggestion is welcome!

Best regards  
David Hu

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [July 21, 2021, 12:29pm UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/2 "2021-07-21T12:29:21Z")

</div>

Not really. If your configuration flags depend on each other, [`CMakeDependentOption`](https://cmake.org/cmake/help/latest/module/CMakeDependentOption.html) might be able to help wrangle them at “declaration” time at least (usually works better for `AND` chains though). But if it really is “any of these _n_ things”, there’s not much available AFAIK.

---

<div class="post-metadata">

**Author:** ![tbacarrot](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/d9b06d/32.png) [@tbacarrot](https://discourse.cmake.org/u/tbacarrot)\
**Post date:** [July 21, 2021, 2:46pm UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/3 "2021-07-21T14:46:01Z")

</div>

Thanks Ben!

Those config flags share the same prefix, for example `CONFIG_TEST_XXX`.  
Can CMake support to check if any config flag with prefix `CONFIG_TEST_` is `ON`?  
If it can be implemented, perhaps it can help shorten the long `if ()` statement.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [July 21, 2021, 3:00pm UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/4 "2021-07-21T15:00:00Z")

</div>

No, CMake has no such metaprogramming facilities. Possibly this if you can stomach it:

```cmake
set(options A B C)
set(conditional)
foreach (option IN LISTS options)
  list(APPEND conditional "COMMON_PREFIX_${option}")
endforeach ()
# (ab)use the list representation
string(REPLACE ";" ";OR;" conditional "${conditional}")
if (${conditional})
  # code that should work for any `option` being true
endif ()

```

---

<div class="post-metadata">

**Author:** ![tbacarrot](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/d9b06d/32.png) [@tbacarrot](https://discourse.cmake.org/u/tbacarrot)\
**Post date:** [July 22, 2021, 1:46am UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/5 "2021-07-22T01:46:47Z")

</div>

Thanks for the suggestion.

Perhaps `if ()` looks more straightforward. 😛  
I will try to live with the long `if ()`.

---

<div class="post-metadata">

**Author:** ![petwu](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petwu/32/1399_2.png) [@petwu](https://discourse.cmake.org/u/petwu)\
**Post date:** [July 22, 2021, 10:06am UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/6 "2021-07-22T10:06:19Z")

</div>

@tbacarrot I have another suggestion/idea: Use a function + [cmake\_language(CALL)](https://cmake.org/cmake/help/latest/command/cmake_language.html) to handle the config variants and their implementation separately. Could look something like this:

```cmake
function(my_config_variant)
  # args
  cmake_parse_arguments(_ARG "" "PREFIX;CALL" "WHEN;CALL_ARGS" ${ARGN})
  if(_ARG_PREFIX)
    string(REGEX REPLACE "[A-Za-z0-9_/.+-]+" "${_ARG_PREFIX}\\0" _ARG_WHEN "${_ARG_WHEN}")
  endif()
  # some regex magic to transform the WHEN argument to a valid if condition
  string(REGEX REPLACE "\\(;" "(" _ARG_WHEN "${_ARG_WHEN}")
  string(REGEX REPLACE ";\\)" ")" _ARG_WHEN "${_ARG_WHEN}")
  string(REGEX REPLACE "!;?" "NOT;" _ARG_WHEN "${_ARG_WHEN}")
  string(REPLACE "&&" "AND" _ARG_WHEN "${_ARG_WHEN}")
  string(REPLACE "||" "OR" _ARG_WHEN "${_ARG_WHEN}")
  # check condition and call implementing function/macro
  if(${_ARG_WHEN})
    cmake_language(CALL ${_ARG_CALL} ${_ARG_CALL_ARGS})
  endif()
endfunction()

# config options
option(MY_CONF_A "" ON)
option(MY_CONF_B "" OFF)
option(MY_CONF_C "" ON)

# config variants implementation
function(my_conf_1_impl)
  # my_conf_1 implementation ...
endfunction()
function(my_conf_2_impl)
  # my_conf_2 implementation ...
endfunction()
# ...

# config variants
my_config_variant(
  PREFIX MY_CONF_
  WHEN A && B && C # -> false
  CALL my_conf_1_impl
)
my_config_variant(
  PREFIX MY_CONF_
  WHEN (A && B) || C # -> true
  CALL my_conf_2_impl
)
my_config_variant(
  PREFIX MY_CONF_
  WHEN A || C # -> true
  CALL my_conf_3_impl
)
my_config_variant(
  PREFIX MY_CONF_
  WHEN !B # -> true
  CALL my_conf_4_impl
)

```

Depending on your use case (how many/complex config variants you have) this may help to express your config variants in a more concise way than some mile-long if-elseif-else construct. Also you could bundle all the conditions for your variants in one place whereas with if statements you have to search for them at the beginning of every branch with all the implementation in between.

Though, for a small number of config variants I would stick with straightforward if statements.

---

<div class="post-metadata">

**Author:** ![tbacarrot](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/d9b06d/32.png) [@tbacarrot](https://discourse.cmake.org/u/tbacarrot)\
**Post date:** [July 26, 2021, 1:54am UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/7 "2021-07-26T01:54:39Z")

</div>

Thanks @petwu .

---

<div class="post-metadata">

**Author:** ![tbacarrot](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/d9b06d/32.png) [@tbacarrot](https://discourse.cmake.org/u/tbacarrot)\
**Post date:** [September 6, 2021, 5:15am UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/8 "2021-09-06T05:15:23Z")

</div>

Sorry for picking this up again.  
I currently implement a search of those configs to see if any of them is set. The basic idea is:

- Those flags are passed in via `cmake -D` in build command
- Those flags are all prefixed with (assumed) `ABC_`

So I search those configs with `ABC_` prefix in the cache like the code below

```auto
get_cmake_property(CACHE_VARS CACHE_VARIABLES)

foreach(CACHE_VAR ${CACHE_VARS})
    string(REGEX MATCH "^ABC.*" _FOUND "${CACHE_VAR}")
    if (_FOUND AND "${${CACHE_VAR}}")
        set(ABC_FLAG ON)
        break()
    endif()
endforeach()

```

It works well. But my friend told me that `CACHE_VARIABLES` is “intended for debugging purpose”, according to [https://cmake.org/cmake/help/v3.21/prop\_dir/CACHE\_VARIABLES.html](https://cmake.org/cmake/help/v3.21/prop_dir/CACHE_VARIABLES.html).

Is it proper to use `CACHE_VARIABLES` in cmake code, not for debug purpose only? Is there any risk that `CACHE_VARIABLES` may be deprecated later?

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [September 6, 2021, 2:18pm UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/9 "2021-09-06T14:18:08Z")

</div>

`CACHE_VARIABLES` isn’t likely to be deprecated, but someone doing a misspelling of `-DABC_SOME_WRONG_FLAG=ON` will be caught up here. It is intended for debugging and using it for logic just has unintended consequences. I think an explicit list is just better.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [September 6, 2021, 9:09pm UTC](https://discourse.cmake.org/t/how-to-handle-more-than-10-config-flags-in-if-statement/3800/10 "2021-09-06T21:09:50Z")

</div>

You also shouldn’t assume that the variable will be a cache variable. Projects may set them as regular non-cache variables and that should work too (not saying that’s always a thing you want to support, but in general, code shouldn’t care whether a variable is set as cache or non-cache unless there is a very specific reason to differentiate between the two).
