Spaces:
Running
on
Zero
Running
on
Zero
# 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() | |