Constraining Values with ComboBoxes in CMake (cmake-gui)

November 28, 2010

In cmake-gui, a list of CMake “options” and “cache entries” are presented to the developer building your project so they can make adjustments to various aspects of your project’s build. For example, a common option is BUILD_SHARED_LIBS . If set to ON , then add_library  calls default to producing shared libraries. Otherwise, add_library  calls default to producing static libraries. This option appears in cmake-gui as a checkbox.

Using the CMake “option” command, it is trivial to add new options to your project. The cmake-gui is tuned to present these options as checkbox controls: checked means the option is ON , unchecked means it is OFF . Other types of cache entries may also appear in cmake-gui. Using the CACHE  form of the cmake SET  command, you may add cache entries for file names, directory names, or arbitrary strings. Each type of entry has its corresponding type of control: the file names have a browse-for-file control, the directory names have a browse-for-directory control, and the string entries have a free form text editing control.

Sometimes, as a the developer of a CMakeLists.txt file, you would like to present a cache entry whose potential values are restricted to a well-known set of strings. Similar to a list of “enum” values for you C++-heads. With CMake 2.8 and later, it is now possible to present this elegantly with a drop-down combo box appearing for each such cache entry in cmake-gui.

Starting with CMake 2.8.0, we extended the set_property command to enable adding properties to CMake CACHE  variables. Specifically, we added a STRINGS  property, with the specific intent of providing a container for a list of the possible values that an otherwise free-form STRING  cache entry was allowed to have. Then we also extended cmake-gui to be aware of this new property, and to use it to populate a drop-down combo box when a user wants to edit the cache entry’s value.

So here’s how it works: for each cache entry that you want to constrain to some set of values, define it as usual with a default value as a STRING  cache variable, for example:

set(BaseName "binary" CACHE STRING "BaseName chosen by the user at CMake configure time")

Now, after defining the cache entry with its initial default value, define the set of strings to which its value should be constrained:

set_property(CACHE BaseName PROPERTY STRINGS binary octal decimal hexadecimal)

After the set_property call, cmake-gui knows to present a drop-down combo box for editing the “BaseName” cache entry, and it knows that the four valid choices for this entry that it should present are binary, octal, decimal and hexadecimal.

The example code presented at the end demonstrates using various techniques to define the list. There is even one technique allowing the user to edit the list of values as a free form STRING  entry, and then use those edits on subsequent configures to present (now different) choices in the drop-down combo box for another entry. Whether this technique is wise or not remains to be seen. (I am of the firm opinion that it is probably unwise, in general, but I present it here anyway for completeness, and because it may be useful for some use case that I’m just not thinking of right  now…)

For completeness, I should also mention that there is no code in cmake itself to enforce the constraint that a cache entry must have one of the values mentioned in its corresponding STRINGS property. After editing by cmake-gui, the edited cache entry will have one of the listed values, but if a user runs cmake -Dentry=blah  then the entry will have value blah regardless of the listed values in the STRINGS  property. If you wish to have fully bulletproof, “this value must be in this list” validation, then you must write code in your CMakeLists.txt file to enforce it.

What follows is a CMakeLists.txt file that demonstrates using the STRINGS  cache property for various cache entries to achieve a constrained “limited list of choices” in cmake-gui. Save it and give it a test drive with cmake-gui, it’s neato-keen.

##############################################################################
#
# The "set_property(CACHE" capability first appeared in CMake version 2.8.0.
# This file will yield a configure-time error with CMake 2.6.4 and earlier...
#
# See also:
#   http://cmake.org/cmake/help/cmake-2-8-docs.html#property:STRINGS
#   http://cmake.org/cmake/help/cmake-2-8-docs.html#command:set
#
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
project(ChoicesChoices)

#
# The "set_property(CACHE" capability first appeared in CMake version 2.8.0.
# This file will yield a configure-time error with CMake 2.6.4 and earlier...
#

#
# Demonstrate using fixed/programmatically-defined/invisible-to-the-user lists
# to fill drop-down combo boxes in cmake-gui (the "values" used for
# the STRINGS property are either simply hard-coded, local, or of CACHE type
# INTERNAL)
#

#
# hard-coded
#
set(BaseName "binary" CACHE STRING
  "BaseName chosen by the user at CMake configure time")

set_property(CACHE BaseName PROPERTY STRINGS binary octal decimal hexadecimal)

message(STATUS "BaseName='${BaseName}'")

#
# local variable
#
set(Language "English" CACHE STRING
  "Language chosen by the user at CMake configure time")

set(LanguageValues
  "English;Spanish;German;French;Chinese;Japanese;Korean;Hebrew;Arabic;Other")

set_property(CACHE Language PROPERTY STRINGS ${LanguageValues})

message(STATUS "Language='${Language}'")

#
# CACHE INTERNAL
#
set(WrapperLanguage "python" CACHE STRING
  "WrapperLanguage chosen by the user at CMake configure time")

set(WrapperLanguageValues "c#;java;lua;perl;php;python;ruby;tcl" CACHE INTERNAL
  "List of possible values for the Language cache variable")

set_property(CACHE WrapperLanguage PROPERTY STRINGS ${WrapperLanguageValues})

message(STATUS "WrapperLanguage='${WrapperLanguage}'")

#
# Demonstrate using a variable/user-modifiable list to fill a drop-down combo
# box in cmake-gui (the "Values" variable used for the STRINGS property is type
# STRING)
#

set(Color "Red" CACHE STRING
  "Color chosen by the user at CMake configure time")

set(ColorValues "Red;Orange;Yellow;Green;Blue;Violet" CACHE STRING
  "List of possible values for the Color cache variable")

set_property(CACHE Color PROPERTY STRINGS ${ColorValues})

message(STATUS "Color='${Color}'")

 

6 comments to Constraining Values with ComboBoxes in CMake (cmake-gui)

  1. Hi,
    Thank you for this post. I tried implementing this combobox functionality in my cmakelist but it is not working.
    Here is a peace of code I have maybe you find a problem with it.

    set(SOLVER “AGMG” CACHE STRING “Solver type AGMG|TRILINOS”)
    set_property(CACHE SOLVER PROPERTY STRINGS “AGMG” “TRILINOS”)

    Thanks

    1. The problem is that this article is using the wrong quoutes “AGMG” won’t work, instead it must be “AGMG”. Is easy to miss this detail!!

    2. BEWARE: Due to the formatting of this webpage, the qoutes are wrongly rendered as it chances quoutes by opening and closing quoutes. CMake will not complain but it will not write to the cache the variable’s value if you simply copy and paste into the CMakeLists.txt the examples of this blog. To solve this CHANGE THE QUOTES BY HAND.

    3. BEWARE: Due to the formatting of this webpage, the qoutes are wrongly rendered (it chances quoutes by opening or closing quoutes). CMake will not complain but it will not write to the cache the variable’s value if you simply copy and paste into the CMakeLists.txt the examples of this blog. To solve this CHANGE THE QUOTES BY HAND IN YOUR CMakeLists.txt file!!!!!!

  2. I just tried that in a simple project and it worked fine. Maybe try removing your cache first. Or, see if it works in a minimal CMakeLists.txt file first. A better place for discussion of topics like this is the CMake mailing list.

  3. Wow, only stumbled over this by accident when building someone else’s project with ccmake and looked up how this is done. At first I thought this is a new (as of 2021) feature when I didn’t see the keyword STRINGS in the documentation of set_property but the post here is already 10 years old – too bad I didn’t know of it last week when the perfect use case passed by me in code review and is now deployed …

Leave a Reply