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

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

Not really. If your configuration flags depend on each other, CMakeDependentOption 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.

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.

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

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 ()

Thanks for the suggestion.

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

@tbacarrot I have another suggestion/idea: Use a function + cmake_language(CALL) to handle the config variants and their implementation separately. Could look something like this:

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.

Thanks @petwu .