[cmake-developers] Is GET_OPTION_VALUE() a good name ?

Alexander Neundorf neundorf at kde.org
Mon Aug 9 17:27:04 EDT 2010


On Monday 09 August 2010, Alexander Neundorf wrote:
> On Monday 09 August 2010, Brad King wrote:
> > On 08/07/2010 03:41 PM, Alexander Neundorf wrote:
> > > # Call the function, if the keyword is present the value(s) following
> > > it will # be returned in _FAIL_MESSAFE/_VERSION_VAR/_REQUIRED_VARS:
> > > FPHSA_GET_OPTION_VALUE("FAIL_MESSAGE" _FAIL_MESSAGE  ALL_ARGS _KEYWORDS
> > > FALSE) FPHSA_GET_OPTION_VALUE("VERSION_VAR"  _VERSION_VAR   ALL_ARGS
> > > _KEYWORDS FALSE) FPHSA_GET_OPTION_VALUE("REQUIRED_VARS" _REQUIRED_VARS
> > > ALL_ARGS _KEYWORDS TRUE)
> >
> > I think a better name would be something like
> > "cmake_get_keyword_argument".
>
> Ok.
>
> > This interface requires the same argument lists to be traversed many
> > times.
>
> Not completely.
> It stops when it has finished the arguments for one keyword and it also
> removes the stuff it consumed from the list, so the list gets shorter each
> call.
>
> > I think we should be using a macro like PARSE_ARGUMENTS from Boost's
> > CMake build system (see below).  This is its interface documentation:
> >
> > # The PARSE_ARGUMENTS macro will take the arguments of another macro and
> > # define several variables. The first argument to PARSE_ARGUMENTS is a
> > # prefix to put on all variables it creates. The second argument is a
> > # list of names, and the third argument is a list of options. Both of
> > # these lists should be quoted. The rest of PARSE_ARGUMENTS are
> > # arguments from another macro to be parsed.
> > #
> > #     PARSE_ARGUMENTS(prefix arg_names options arg1 arg2...)
>
> The last time I looked at some similar function (was it also in boost ?) it
> didn't seem powerful enough.
> I'll have a look.

Ok, attached you can find a CMakeParseArguments.cmake.
Docs are still missing.
The interface is similar to the one from boost, but not identical.
With this version you can specify options (no values following), single-value 
arguments (0..1 value following) and multi-value arguments (0..n values 
following).
This has the advantage that the function can also report the arguments which 
it didn't know.
This is done in ${prefix}_UNPARSED_ARGUMENTS.

It runs once over ARGN, but the option and argument names have to checked on 
each iteration, I think this can't be avoided (and is also the case in the 
macro from Boost).

Alex

P.S.
Is this the current version: 
http://calder.sdml.cs.kent.edu/trac/origin/browser/trunk/cmake/BoostUtils.cmake ?
It seems to have a bug, an option doesn't seem to terminate the collecting of 
values of the previous argument (but I didn't test).
-------------- next part --------------
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
  return()
endif()
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)


function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
  foreach(arg_name ${_singleArgNames} ${_multiArgNames})
    set(${prefix}_${arg_name})
  endforeach(arg_name)

  foreach(option ${_optionNames})
    set(${prefix}_${option} FALSE)
  endforeach(option)

  set(${prefix}_UNPARSED_ARGUMENTS)

  set(insideValues FALSE)
  set(currentArgName)

  foreach(currentArg ${ARGN})
    list(FIND _optionNames "${currentArg}" optionIndex)  # ... then this marks the end of the arguments belonging to this keyword
    list(FIND _singleArgNames "${currentArg}" singleArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
    list(FIND _multiArgNames "${currentArg}" multiArgIndex)  # ... then this marks the end of the arguments belonging to this keyword

    if(${optionIndex} EQUAL -1  AND  ${singleArgIndex} EQUAL -1  AND  ${multiArgIndex} EQUAL -1)
      if(insideValues)
        if("${insideValues}" STREQUAL "SINGLE")
          set(${prefix}_${currentArgName} ${currentArg})
          set(insideValues FALSE)
        elseif("${insideValues}" STREQUAL "MULTI")
          list(APPEND ${prefix}_${currentArgName} ${currentArg})
        endif()
      else(insideValues)
        list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
      endif(insideValues)
    else()
      if(NOT ${optionIndex} EQUAL -1)
        set(${prefix}_${currentArg} TRUE)
        set(insideValues FALSE)
      elseif(NOT ${singleArgIndex} EQUAL -1)
        set(currentArgName ${currentArg})
        set(${prefix}_${currentArgName})
        set(insideValues "SINGLE")
      elseif(NOT ${multiArgIndex} EQUAL -1)
        set(currentArgName ${currentArg})
        set(${prefix}_${currentArgName})
        set(insideValues "MULTI")
      endif()
    endif()

  endforeach(currentArg)

  foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
    set(${prefix}_${arg_name}  ${${prefix}_${arg_name}} PARENT_SCOPE)
  endforeach(arg_name)
  set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)

endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs)
-------------- next part --------------
cmake_minimum_required(VERSION 2.6)

include(CMakeParseArguments)

cmake_parse_arguments(FOO "APPEND;PREPEND" "FILENAME;WHAT;INFO" "NAMES;WORDS"
  BLUB APPEND FILENAME foo.txt xyz WHAT INFO "This is info" NAMES a.txt b.txt c.txt)

macro(print_var _var)
  message(STATUS "${_var} = \"${${_var}}\"")
endmacro(print_var _var)

print_var(FOO_APPEND)
print_var(FOO_PREPEND)
print_var(FOO_FILENAME)
print_var(FOO_WHAT)
print_var(FOO_INFO)
print_var(FOO_NAMES)
print_var(FOO_WORDS)
print_var(FOO_UNPARSED_ARGUMENTS)


More information about the cmake-developers mailing list