[CMake] New type of cache variable: lists

David Cole david.cole at kitware.com
Thu Dec 8 20:58:22 EST 2011


On Thu, Dec 8, 2011 at 8:27 PM, Robert Dailey <rcdailey at gmail.com> wrote:
> Thanks, glad you like the idea.
>
> I've seen the word "choice" used in many scenarios where the user is given a
> list to pick from, so it seemed like an appropriate name.
>
> You also make a great point about someone already using the word "choice"
> globally. However, keep in mind it is the integrity of the language we are
> talking about here. This decision will forever be locked into CMake, so the
> name you choose must be appropriate and self-documenting. Granted it will be
> unfortunate that "choice" will possibly cause conflicts with user code, but
> the design of the CMake language takes precedence IMHO.
>
> For the limited scope of projects this would affect, I would have CMake post
> a conflict warning that detects when the user has defined a conflicting
> global variable named "choice" and post a warning or error in the output.
> After a few minor versions, you can remove this check, but it will at least
> make it very clear to the users that they simply need to go in and rename
> their variables, functions, or macros. Just some food for thought. I'd much
> rather take this approach than be forced to give this new feature an ugly
> name. I honestly think "choice" is the best name, I can't think of a better
> one.
>
> Think about it and let me know what you decide. I don't know much about
> these CMake-language functions you speak of, but it would be interesting to
> learn about them. Are they covered in detail in the reference documentation,
> or the wiki?
>
> ---------
> Robert Dailey
>
>
>
> On Thu, Dec 8, 2011 at 6:00 PM, David Cole <david.cole at kitware.com> wrote:
>>
>> On Thu, Dec 8, 2011 at 5:43 PM, Robert Dailey <rcdailey at gmail.com> wrote:
>> > On Thu, Dec 8, 2011 at 3:53 PM, David Cole <david.cole at kitware.com>
>> > wrote:
>> >>
>> >> The 4th argument to SET (when CACHE is used) is the *type* of the
>> >> cache entry itself. I will not call a cache entry a LIST when it is
>> >> not actually a list.
>> >>
>> >> Nor will I accept that the 2nd argument to set should be anything
>> >> other than the actual value that the cache entry ends up with after
>> >> the set call.
>> >>
>> >> Those are the two things I have problems with in your proposal.
>> >>
>> >> One thing that you can do right now, with no changes to CMake, is
>> >> write a CMake-language function as a wrapper that "does the right
>> >> thing" with a list and a cache entry and its default value and setting
>> >> its existing STRINGS property. As a side benefit, you can make the
>> >> signature be whatever you want it to be...
>> >>
>> >> Of course, if we can come to an agreement about a good way to push
>> >> this into the built-in set command, that would be ideal.
>> >>
>> >> But I find myself in a rather inflexible mood regarding my two points
>> >> above.
>> >>
>> >>
>> >> Still willing to listen, but not budging yet,
>> >
>> >
>> > I agree with your points. I honestly don't think set() is the right tool
>> > for
>> > the job though. There is already a mechanic in CMake to more
>> > conveniently
>> > set boolean cache variables with the option() command. Likewise, I think
>> > we
>> > should have one for lists, called choice():
>> >
>> > choice( BaseName "binary;octal;decimal;hexidecimal" "documentation" 0 )
>> >
>> > Parameter 1 is the destination variable, which will be stored in the
>> > cache
>> > as a STRING type
>> > Parameter 2 is the tuple, or list of choices for the user.
>> > Parameter 3 is the documentation string
>> > Parameter 4 (optional) is the index of an element in the tuple that
>> > shall be
>> > used as the default value. If omitted, the first item in the list will
>> > be
>> > used.
>> >
>> > Concerning parameter 4, this might be eliminated completely since I see
>> > no
>> > reason why you can't just re-order the list to keep the default item as
>> > the
>> > first item in the list.
>> >
>> > What do you think about this?
>>
>> Personally, I like the idea of a whole separate function much better
>> than cramming it into the already way-overloaded "set".
>>
>> Not sure if "choice" is a good name, though. One of the problems with
>> introducing new function names at the top level like that is we have
>> no idea if the name is already used in an existing project as a
>> function or macro in some CMakeLists files. So we can't be cavalier
>> about deciding to add new top level built-in commands.
>>
>> You could certainly implement this as a CMake-language function in
>> terms of the existing set and STRINGS cache entry property. (And by
>> giving this advice, I almost guarantee that somebody will do so...)
>>
>> I'm gonna sleep on this now. :-)
>>
>>
>> David
>
>


http://cmake.org/cmake/help/cmake-2-8-docs.html#command:function


Here's a CMake-language function named "choice" that does what I think
you were suggesting:


function(choice varname choices documentation)
  if("${varname}" STREQUAL "" OR "${choices}" STREQUAL "")
    message(FATAL_ERROR "choice function requires varname and choices values")
  endif()

  set(default_index ${ARGV3})
  if(NOT default_index)
    set(default_index 0)
  endif()

  list(GET choices ${default_index} default_value)

  set(${varname} ${default_value} CACHE STRING ${documentation})
  set_property(CACHE ${varname} PROPERTY STRINGS ${choices})
endfunction()



Here's the CMakeLists file from my blog post, modified to use the
choice function above...
( http://www.kitware.com/blog/home/post/82 )


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


function(choice varname choices documentation)
  if("${varname}" STREQUAL "" OR "${choices}" STREQUAL "")
    message(FATAL_ERROR "choice function requires varname and choices values")
  endif()

  set(default_index ${ARGV3})
  if(NOT default_index)
    set(default_index 0)
  endif()

  list(GET choices ${default_index} default_value)

  set(${varname} ${default_value} CACHE STRING ${documentation})
  set_property(CACHE ${varname} PROPERTY STRINGS ${choices})
endfunction()


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

choice(BaseName "binary;octal;decimal;hexadecimal" "BaseName chosen by
the user at CMake configure time")

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

choice(Language "${LanguageValues}" "Language chosen by the user at
CMake configure time")

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

choice(WrapperLanguage "${WrapperLanguageValues}" "WrapperLanguage
chosen by the user at CMake configure time" 5)

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

choice(Color "${ColorValues}" "Color chosen by the user at CMake
configure time")

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



Something for you to use if you like in the interim before we decide
what to do as a built-in CMake command.


Cheers,
David


More information about the CMake mailing list