Olga
Initial commit
5f9d349
# Copyright (C) 2020, Inria
# GRAPHDECO research group, https://team.inria.fr/graphdeco
# All rights reserved.
#
# This software is free for non-commercial, research and evaluation use
# under the terms of the LICENSE.md file.
#
# For inquiries contact [email protected] and/or [email protected]
if(NOT WIN32 OR __parse_arguments_multi_cmake_INCLUDED__)
return()
else()
set(__parse_arguments_multi_cmake_INCLUDED__ ON)
endif()
## This macro allow to process repeating multi value args from a given function which use cmake_parse_arguments module.
##
## cmake_parse_arguments multi args standard behavior:
## function(foo)
## cmake_parse_arguments(arg "" "" "MULTI" ${ARGN})
## foreach(item IN LISTS arg_MULTI)
## message(STATUS "${item}")
## endforeach()
## endfunction()
## foo(MULTI x y MULTI z w)
## The above code outputs 'z' and 'w'. It originally expected it to output all of 'x' 'y' 'z' 'w'.
##
## Using this macro inside a function which want to handle repeating multi args values
## will recursively iterate onto the multi tags list to process each sub list.
## It take as 1st argument the subTag flag to separate sub list from the main multi list.
## It take as 2nd argument the nameList of the main multi list (the multiValuesArgs from cmake_parse_arguments: here it is MULTI in the example)
## and that's why it is important that it should be a macro and not a function (to get access to external variable).
## Then you give the content of this list allowing to be processed by the macro.
##
## parse_arguments_multi macro call a parse_arguments_multi_function which do actually the process from the given sub-list.
## By default this function only print infos about what variables you are trying to pass/process (only verbose messages),
## but, by overloading this cmake function, you will be able to externalize the process of your multi argument list.
##
## Usage (into a function) :
## parse_arguments_multi(<multiArgsSubTag> <multiArgsList> <multiArgsListContent>
## [NEED_RESULTS <multiArgsListSize>] [EXTRAS_FLAGS <...> <...> ...]
## )
##
## Simple usage example [user point of view]:
## foo(MULTI
## SUB_MULTI x y
## SUB_MULTI z w
## )
##
## Simple usage example [inside a function]:
## function(foo)
## cmake_parse_arguments(arg "" "" "MULTI" ${ARGN})
## include(parse_arguments_multi)
## function(parse_arguments_multi_function )
## #message("I'm an overloaded cmake function used by parse_arguments_multi")
## #message("I'm processing first part of my sub list: ${ARGN}")
## message("ARGV0=${ARGV0}")
## message("ARGV1=${ARGV1}")
## endfunction()
## parse_arguments_multi(SUB_MULTI arg_MULTI ${arg_MULTI}) ## this function will process recusively items of the sub-list [default print messages]
## endfunction()
##
## Will print:
## ARGV0=z
## ARGV1=w
## ARGV0=x
## ARGV1=y
##
## WARNING : DO NEVER ADD EXTRA THINGS TO parse_arguments_multi MACRO :
## parse_arguments_multi(SUB_MULTI arg_MULTI ${arg_MULTI} EXTRAS foo bar SOMTHING) => will failed !!
## use EXTRAS_FLAGS instead !!
##
## Advanced usage example [user point of view]:
## bar(C:/prout/test.exe VERBOSE
## PLUGINS
## PLUGIN_PATH_NAME x PLUGIN_PATH_DEST w
## PLUGIN_PATH_NAME a b PLUGIN_PATH_DEST y
## PLUGIN_PATH_NAME c
## )
##
## Advanced usage example [inside a function]:
## function(bar execFilePathName)
## cmake_parse_arguments(arg "VERBOSE" "" "PLUGINS" ${ARGN})
##
## include(parse_arguments_multi)
## function(parse_arguments_multi_function results)
## cmake_parse_arguments(pamf "VERBOSE" "PLUGIN_PATH_DEST;EXEC_PATH" "" ${ARGN}) ## EXEC_PATH is for internal use
## message("")
## message("I'm an overloaded cmake function used by parse_arguments_multi from install_runtime function")
## message("I'm processing first part of my sub list: ${ARGN}")
## message("PLUGIN_PATH_NAME = ${pamf_UNPARSED_ARGUMENTS}")
## message(pamf_VERBOSE = ${pamf_VERBOSE})
## message("pamf_PLUGIN_PATH_DEST = ${pamf_PLUGIN_PATH_DEST}")
## message(pamf_EXEC_PATH = ${pamf_EXEC_PATH})
## if(NOT ${pamf_PLUGIN_PATH_DEST})
## set(pamf_PLUGIN_PATH_DEST ${pamf_EXEC_PATH})
## endif()
## foreach(plugin ${pamf_UNPARSED_ARGUMENTS})
## get_filename_component(pluginName ${plugin} NAME)
## list(APPEND pluginsList ${pamf_PLUGIN_PATH_DEST}/${pluginName})
## endforeach()
## set(${results} ${pluginsList} PARENT_SCOPE)
## endfunction()
##
## if(arg_VERBOSE)
## list(APPEND extra_flags_to_add VERBOSE) ## here we transmit the VERNOSE flag
## endif()
## get_filename_component(EXEC_PATH ${execFilePathName} PATH) ## will be the default value if PLUGIN_PATH_DEST option is not provided
## list(APPEND extra_flags_to_add EXEC_PATH ${EXEC_PATH})
## list(LENGTH arg_PLUGINS arg_PLUGINS_count)
## parse_arguments_multi(PLUGIN_PATH_NAME arg_PLUGINS ${arg_PLUGINS}
## NEED_RESULTS ${arg_PLUGINS_count} ## this is used to check when we are in the first loop (in order to reset parse_arguments_multi_results)
## EXTRAS_FLAGS ${extra_flags_to_add} ## this is used to allow catching VERBOSE and PLUGIN_PATH_DEST flags of our overloaded function
## )
## endfunction()
## message(parse_arguments_multi_results = ${parse_arguments_multi_results}) ## list of the whole pluginsList
## #Will print w/x;a/y;b/y;C:/prout/c
##
## NOTE that here, since our overloaded function need to provide a result list, we use the other parse_arguments_multi_function signature (the which one with a results arg)
##
function(parse_arguments_multi_function_default) ## used in case of you want to reset the default behavior of this function process
message("[default function] parse_arguments_multi_function(ARGC=${ARGC} ARGV=${ARGV} ARGN=${ARGN})")
message("This function is used by parse_arguments_multi and have to be overloaded to process sub list of multi values args")
endfunction()
function(parse_arguments_multi_function ) ## => the function to overload
parse_arguments_multi_function_default(${ARGN})
endfunction()
## first default signature above
##------------------------------
## second results signature behind
function(parse_arguments_multi_function_default result) ## used in case of you want to reset the default behavior of this function process
message("[default function] parse_arguments_multi_function(ARGC=${ARGC} ARGV=${ARGV} ARGN=${ARGN})")
message("This function is used by parse_arguments_multi and have to be overloaded to process sub list of muluti values args")
endfunction()
function(parse_arguments_multi_function result) ## => the function to overload
parse_arguments_multi_function_default(result ${ARGN})
endfunction()
## => the macro to use inside your function which use cmake_parse_arguments
# NOTE: entry point of parse_arguments_multi, which is called from win3rdPart)
macro(parse_arguments_multi multiArgsSubTag multiArgsList #<${multiArgsList}> the content of the list
)
# message (STATUS "")
# message(STATUS "calling parse_arguemnts_multi defined in parse_arguments_multi.cmake:141")
# message(STATUS "multiArgsSubTag = ${multiArgsSubTag}") # CHECK_CACHED_VAR
# message(STATUS "multiArgsList = ${multiArgsList}") # it contains the name of the variable which is holding the list i.e w3p_MULTI_SET
# message(STATUS "value of ${multiArgsList} = ${${multiArgsList}}") # a semicolon separated list of values passed to SET or MULTISET keyword in win3rdParty
# message(STATUS "actual values ARGN = ${ARGN}") # the same as ${${multiArgsList}}
## INFO
## starting from CMake 3.5 cmake_parse_arguments is not a module anymore and now is a native CMake command.
## the behaviour is different though
## In CMake 3.4, if you pass multiple times a multi_value_keyword, CMake returns the values of the LAST match
## In CMake 3.5 and above, CMake returns the whole list of values that were following that multi_value_keyword
## example:
## cmake_parse_arguments(
## <prefix>
## "" # options
## "" # one value keywords
## "MY_MULTI_VALUE_TAG"
## MY_MULTI_VALUE_TAG value1 value2
## MY_MULTI_VALUE_TAG value3 value4
## MY_MULTI_VALUE_TAG value5 value6
## )
## result in CMake 3.4
## <prefix>_MY_MULTI_VALUE_TAG = "value5;value6"
##
## result in CMake 3.8
## <prefix>_MY_MULTI_VALUE_TAG = "value5;value6"
#include(CMakeParseArguments) #module CMakeParseArguments is obsolete since cmake 3.5
# cmake_parse_arguments (<prefix> <options> <one_value_keywords> <multi_value_keywords> args)
# <options> : options (flags) pass to the macro
# <one_value_keywords> : options that neeed a value
# <multi_value_keywords> : options that neeed more than one value
cmake_parse_arguments(_pam "" "NEED_RESULTS" "${multiArgsSubTag};EXTRAS_FLAGS" ${ARGN})
## multiArgsList is the name of the list used by the multiValuesOption flag from the cmake_parse_arguments of the user function
## that's why we absolutly need to use MACRO here (and also for passing parse_arguments_multi_results when NEED_RESULTS flag is set)
## for debugging
#message("")
#message("[parse_arguments_multi] => ARGN = ${ARGN}")
#message("_pam_NEED_RESULTS=${_pam_NEED_RESULTS}")
#message("_pam_EXTRAS_FLAGS=${_pam_EXTRAS_FLAGS}")
# foreach(var ${_pam_${multiArgsSubTag}})
# message("arg=${var}")
# endforeach()
if (${CMAKE_VERSION} VERSION_GREATER "3.5")
# lets make ${_pam_${multiArgsSubTag}} behave as it is in version 3.4
# that means, cmake_parse_arguments should have only the last values of a multi set for a given keyword
# message("")
# message("values in multiArgsList")
# foreach(val ${${multiArgsList}})
# message(STATUS ${val})
# endforeach()
# message("end values in multiArgsList")
set(lastIndexFound OFF)
list(LENGTH ${multiArgsList} argnLength)
# message(${argnLength})
math(EXPR argnLength "${argnLength}-1") # make last index a valid one
set(recordIndex 0)
set(records "") # clear records list
set(record0 "") # clear first record list
foreach(iter RANGE ${argnLength})
list(GET ${multiArgsList} ${iter} value)
# message(STATUS "index=${iter} value=${value}")
if (${value} STREQUAL ${multiArgsSubTag})
if (lastIndexFound)
list(APPEND records ${recordIndex}) # records store the list NAMES
math(EXPR recordIndex "${recordIndex}+1")
set(record${recordIndex} "") # clear record list
else ()
set(lastIndexFound ON)
endif()
set(lastIndex ${iter})
else ()
if (lastIndexFound)
# message(${value})
list(APPEND record${recordIndex} ${value})
endif()
endif()
endforeach()
# save the last list of values
if (lastIndexFound)
list(APPEND records ${recordIndex}) # records store the list NAMES
endif()
# set multiArgsList to make it behave like CMake 3.4
# message("")
# message("using my records")
foreach(recordName ${records})
# message(${recordName})
# foreach(value ${record${recordName}})
# message(${value})
# endforeach()
# message("")
set(_pam_${multiArgsSubTag} ${record${recordName}})
endforeach()
# message(${_pam_${multiArgsSubTag}})
# message("")
# message("using argn")
# foreach(value ${ARGN})
# message(${value})
# endforeach()
endif() # end if cmake > 3.5
# message("values with pam ${_pam_${multiArgsSubTag}}")
## check and init
list(LENGTH ${multiArgsList} globalListCount) # GLUT_TRACE: globalListCound=16 in CMake3.4 and CMake3.8
# message(STATUS "nr items in multiArgsList: ${globalListCount}")
math(EXPR globalListCount "${globalListCount}-1") ## because it will contain [multiArgsSubTag + ${multiArgsList}]
if(_pam_NEED_RESULTS)
if(${globalListCount} EQUAL ${_pam_NEED_RESULTS})
## first time we enter into this macro (because we call it recursively)
unset(parse_arguments_multi_results)
endif()
endif()
## process the part of the multi agrs list
## ${ARGN} shouldn't be passed to the function in order to avoid missmatch size list ${multiArgsList} and _pam_${multiArgsSubTag}
## if you want to pass extra internal flags from your function to this callback, use EXTRAS_FLAGS
if(_pam_NEED_RESULTS)
parse_arguments_multi_function(parse_arguments_multi_function_result ${_pam_${multiArgsSubTag}} ${_pam_EXTRAS_FLAGS})
list(APPEND parse_arguments_multi_results ${parse_arguments_multi_function_result})
else()
# message(STATUS "about to call parse_arguments_multi_function in parse_arguments_multi.cmake:177 ${_pam_${multiArgsSubTag}} and extra flags ${_pam_EXTRAS_FLAGS}")
parse_arguments_multi_function(${_pam_${multiArgsSubTag}} ${_pam_EXTRAS_FLAGS})
endif()
## remove just processed items from the main list to process (multiArgsList)
list(REVERSE ${multiArgsList})
list(LENGTH _pam_${multiArgsSubTag} subTagListCount)
unset(ids)
foreach(id RANGE ${subTagListCount})
list(APPEND ids ${id})
endforeach()
list(REMOVE_AT ${multiArgsList} ${ids})
list(REVERSE ${multiArgsList})
## test if remain sub multi list to process (recursive call) or finish the process
list(LENGTH ${multiArgsList} mainTagListCount)
if(${mainTagListCount} GREATER 1)
## do not pass ${ARGN} just because it will re pass the initial 2 inputs args and we wont as they was consumed (in order to avoir conflicts)
# message(STATUS "about to call a parse_arguments_multi but without knowing where the definition is going to be taken from")
parse_arguments_multi(${multiArgsSubTag} ${multiArgsList} ${${multiArgsList}}
NEED_RESULTS ${_pam_NEED_RESULTS} EXTRAS_FLAGS ${_pam_EXTRAS_FLAGS}
)
endif()
endmacro()