[CMake] New type of cache variable: lists

David Cole david.cole at kitware.com
Thu Dec 8 20:59:26 EST 2011


On Thu, Dec 8, 2011 at 8:58 PM, David Cole <david.cole at kitware.com> wrote:
> 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


Well, nearly....

You'll have to double-quote the "${documentation}" inside the function
in case it is the empty string...


More information about the CMake mailing list