Cmake string 从包含以冒号分隔的键值的字符串列表中获取键值对
Cmake string to get key value pairs from a string list containing key values separated by colon
我有一个字符串列表(输入):
set(MY_LIST "A:1;B:2;C:3")
我想使用 foreach 获取键值并将它们设置为 cmake 常量。类似于:
foreach(ITEM ${MY_LIST})
SET(<ITEM_A> <value_ofA>)
endforeach()
所以基本上我想要最终结果,但这应该使用 forloop 来实现:
SET(A "1")
SET(B "2")
SET(C "3")
如何使用 foreach 导航列表中的每个字符串并将键值对设置为 cmake 常量来实现此目的?
还不错:
cmake_minimum_required(VERSION 3.21)
set(MY_LIST "A:1;B:2;C:3;D:foo:bar")
foreach (pair IN LISTS MY_LIST)
string(FIND "${pair}" ":" pos)
if (pos LESS 1)
message(WARNING "Skipping malformed pair (no var name): ${pair}")
else ()
string(SUBSTRING "${pair}" 0 "${pos}" var)
math(EXPR pos "${pos} + 1") # Skip the separator
string(SUBSTRING "${pair}" "${pos}" -1 val)
set("${var}" "${val}")
endif ()
endforeach ()
message(STATUS "${A}")
message(STATUS "${B}")
message(STATUS "${C}")
message(STATUS "${D}")
输出为:
$ cmake -P test.cmake
-- 1
-- 2
-- 3
-- foo:bar
也可能适用于早期版本。我会及时更新。
只需使用正则表达式来拆分值。下面的代码将功能包装在一个函数中。除了创建这些变量的列表之外,它还提供添加前缀以避免保留变量名称出现问题的功能。 (对于省略了额外逻辑的简化版本,请参阅我的回答的最后一个代码片段。)
function(my_parse_values OUT_PREFIX)
set(VAR_LIST)
foreach(_PAIR IN LISTS ARGN)
if (_PAIR MATCHES "^([^:]+):(.*)$")
set("${OUT_PREFIX}${CMAKE_MATCH_1}" ${CMAKE_MATCH_2} PARENT_SCOPE)
list(APPEND VAR_LIST ${CMAKE_MATCH_1})
else()
message(FATAL_ERROR "Invalid pair: ${_PAIR}")
endif()
endforeach()
list(REMOVE_DUPLICATES VAR_LIST)
set(${OUT_PREFIX} ${VAR_LIST} PARENT_SCOPE)
endfunction()
使用示例:
set(MY_LIST "A:1;B:2;C:3")
my_parse_values(VARS ${MY_LIST})
# VARS_A with value 1,
# VARS_B with value 2,
# VARS_C with value 3 and
# list VARS with elements A, B and C
# are defined now...
foreach(_VAR IN LISTS VARS)
message("${_VAR} = ${VARS_${_VAR}}")
endforeach()
如果您不需要变量列表,并且想按原样设置变量,代码可以缩短为:
function(my_parse_values)
foreach(_PAIR IN LISTS ARGN)
if (_PAIR MATCHES "^([^:]+):(.*)$")
set(${CMAKE_MATCH_1} ${CMAKE_MATCH_2} PARENT_SCOPE)
else()
message(FATAL_ERROR "Invalid pair: ${_PAIR}")
endif()
endforeach()
endfunction()
set(MY_LIST "A:1;B:2;C:3")
my_parse_values(${MY_LIST})
message("A = ${A}")
message("B = ${B}")
message("C = ${C}")
我多次对在 CMake 中迭代多个数组元素感到沮丧。所以我创建了一个函数。以下相当长的文件可从 here 获得:
function(foreach_count_items fci_foreach_count_items_loopvar_name
fci_foreach_count_items_statevar_name)
if("${ARGC}" LESS 1)
message(FATAL_ERROR "foreach_count_items: wrong number of arguments")
endif()
set(fci_foreach_count_items_statevar
"${${fci_foreach_count_items_statevar_name}}")
set(fci_foreach_count_items_loopvar
"${${fci_foreach_count_items_loopvar_name}}")
# message(STATUS "fci_foreach_count_items_loopvar=${fci_foreach_count_items_loopvar}")
# message(STATUS "fci_foreach_count_items_statevar=${fci_foreach_count_items_statevar}")
if("${fci_foreach_count_items_statevar}" STREQUAL "")
set(fci_foreach_count_items_statevar 1)
endif()
math(EXPR count "${ARGC} - 2")
math(EXPR argc_less_one "${ARGC} - 1")
math(EXPR argc_less_two "${ARGC} - 2")
math(EXPR lastidx "${ARGC} - 1")
# message(STATUS "set(${ARGV${lastidx}} ${fci_foreach_count_items_loopvar}
# PARENT_SCOPE)")
set("${ARGV${lastidx}}" "${fci_foreach_count_items_loopvar}")
set("${ARGV${lastidx}}"
"${fci_foreach_count_items_loopvar}"
PARENT_SCOPE)
# message(STATUS "lastidx=${lastidx}") message(STATUS
# "ARGV${lastidx}=${ARGV${lastidx}}=${${ARGV${lastidx}}}")
if(fci_foreach_count_items_statevar LESS count)
foreach(i RANGE 2 ${argc_less_two} 1)
math(EXPR j "${i} + 1")
# message(STATUS "${i} ${j} | ${ARGV${i}}=${${ARGV${i}}}
# ${ARGV${j}}=${${ARGV${j}}}")
set("${ARGV${i}}" "${${ARGV${j}}}")
set("${ARGV${i}}" "${${ARGV${j}}}" PARENT_SCOPE)
endforeach()
# foreach(i RANGE ${argc_less_one}) message(STATUS "ARGV${i} = ${ARGV${i}} =
# ${${ARGV${i}}}") ndforeach()
math(EXPR fci_foreach_count_items_statevar
"${fci_foreach_count_items_statevar} + 1")
set(fci_foreach_count_items_loopvar YES)
else()
set(fci_foreach_count_items_statevar 1)
set(fci_foreach_count_items_loopvar NO)
endif()
set("${fci_foreach_count_items_statevar_name}" "${fci_foreach_count_items_statevar}" PARENT_SCOPE)
set("${fci_foreach_count_items_loopvar_name}" "${fci_foreach_count_items_loopvar}" PARENT_SCOPE)
endfunction()
允许像这样使用它:
set(mylist "A:1;B:2;C:3")
foreach(ii IN LISTS mylist)
foreach_count_items(tmp item value)
# ^^^^^^^^^^ - variable list
# ^^^ - temporary iterator
if(tmp) # when iterator is set, ignore that loop, wait for the next one
continue()
enidf()
# use item and value here
set(${item} ${value})
endforeach()
我有一个字符串列表(输入):
set(MY_LIST "A:1;B:2;C:3")
我想使用 foreach 获取键值并将它们设置为 cmake 常量。类似于:
foreach(ITEM ${MY_LIST})
SET(<ITEM_A> <value_ofA>)
endforeach()
所以基本上我想要最终结果,但这应该使用 forloop 来实现:
SET(A "1")
SET(B "2")
SET(C "3")
如何使用 foreach 导航列表中的每个字符串并将键值对设置为 cmake 常量来实现此目的?
还不错:
cmake_minimum_required(VERSION 3.21)
set(MY_LIST "A:1;B:2;C:3;D:foo:bar")
foreach (pair IN LISTS MY_LIST)
string(FIND "${pair}" ":" pos)
if (pos LESS 1)
message(WARNING "Skipping malformed pair (no var name): ${pair}")
else ()
string(SUBSTRING "${pair}" 0 "${pos}" var)
math(EXPR pos "${pos} + 1") # Skip the separator
string(SUBSTRING "${pair}" "${pos}" -1 val)
set("${var}" "${val}")
endif ()
endforeach ()
message(STATUS "${A}")
message(STATUS "${B}")
message(STATUS "${C}")
message(STATUS "${D}")
输出为:
$ cmake -P test.cmake
-- 1
-- 2
-- 3
-- foo:bar
也可能适用于早期版本。我会及时更新。
只需使用正则表达式来拆分值。下面的代码将功能包装在一个函数中。除了创建这些变量的列表之外,它还提供添加前缀以避免保留变量名称出现问题的功能。 (对于省略了额外逻辑的简化版本,请参阅我的回答的最后一个代码片段。)
function(my_parse_values OUT_PREFIX)
set(VAR_LIST)
foreach(_PAIR IN LISTS ARGN)
if (_PAIR MATCHES "^([^:]+):(.*)$")
set("${OUT_PREFIX}${CMAKE_MATCH_1}" ${CMAKE_MATCH_2} PARENT_SCOPE)
list(APPEND VAR_LIST ${CMAKE_MATCH_1})
else()
message(FATAL_ERROR "Invalid pair: ${_PAIR}")
endif()
endforeach()
list(REMOVE_DUPLICATES VAR_LIST)
set(${OUT_PREFIX} ${VAR_LIST} PARENT_SCOPE)
endfunction()
使用示例:
set(MY_LIST "A:1;B:2;C:3")
my_parse_values(VARS ${MY_LIST})
# VARS_A with value 1,
# VARS_B with value 2,
# VARS_C with value 3 and
# list VARS with elements A, B and C
# are defined now...
foreach(_VAR IN LISTS VARS)
message("${_VAR} = ${VARS_${_VAR}}")
endforeach()
如果您不需要变量列表,并且想按原样设置变量,代码可以缩短为:
function(my_parse_values)
foreach(_PAIR IN LISTS ARGN)
if (_PAIR MATCHES "^([^:]+):(.*)$")
set(${CMAKE_MATCH_1} ${CMAKE_MATCH_2} PARENT_SCOPE)
else()
message(FATAL_ERROR "Invalid pair: ${_PAIR}")
endif()
endforeach()
endfunction()
set(MY_LIST "A:1;B:2;C:3")
my_parse_values(${MY_LIST})
message("A = ${A}")
message("B = ${B}")
message("C = ${C}")
我多次对在 CMake 中迭代多个数组元素感到沮丧。所以我创建了一个函数。以下相当长的文件可从 here 获得:
function(foreach_count_items fci_foreach_count_items_loopvar_name
fci_foreach_count_items_statevar_name)
if("${ARGC}" LESS 1)
message(FATAL_ERROR "foreach_count_items: wrong number of arguments")
endif()
set(fci_foreach_count_items_statevar
"${${fci_foreach_count_items_statevar_name}}")
set(fci_foreach_count_items_loopvar
"${${fci_foreach_count_items_loopvar_name}}")
# message(STATUS "fci_foreach_count_items_loopvar=${fci_foreach_count_items_loopvar}")
# message(STATUS "fci_foreach_count_items_statevar=${fci_foreach_count_items_statevar}")
if("${fci_foreach_count_items_statevar}" STREQUAL "")
set(fci_foreach_count_items_statevar 1)
endif()
math(EXPR count "${ARGC} - 2")
math(EXPR argc_less_one "${ARGC} - 1")
math(EXPR argc_less_two "${ARGC} - 2")
math(EXPR lastidx "${ARGC} - 1")
# message(STATUS "set(${ARGV${lastidx}} ${fci_foreach_count_items_loopvar}
# PARENT_SCOPE)")
set("${ARGV${lastidx}}" "${fci_foreach_count_items_loopvar}")
set("${ARGV${lastidx}}"
"${fci_foreach_count_items_loopvar}"
PARENT_SCOPE)
# message(STATUS "lastidx=${lastidx}") message(STATUS
# "ARGV${lastidx}=${ARGV${lastidx}}=${${ARGV${lastidx}}}")
if(fci_foreach_count_items_statevar LESS count)
foreach(i RANGE 2 ${argc_less_two} 1)
math(EXPR j "${i} + 1")
# message(STATUS "${i} ${j} | ${ARGV${i}}=${${ARGV${i}}}
# ${ARGV${j}}=${${ARGV${j}}}")
set("${ARGV${i}}" "${${ARGV${j}}}")
set("${ARGV${i}}" "${${ARGV${j}}}" PARENT_SCOPE)
endforeach()
# foreach(i RANGE ${argc_less_one}) message(STATUS "ARGV${i} = ${ARGV${i}} =
# ${${ARGV${i}}}") ndforeach()
math(EXPR fci_foreach_count_items_statevar
"${fci_foreach_count_items_statevar} + 1")
set(fci_foreach_count_items_loopvar YES)
else()
set(fci_foreach_count_items_statevar 1)
set(fci_foreach_count_items_loopvar NO)
endif()
set("${fci_foreach_count_items_statevar_name}" "${fci_foreach_count_items_statevar}" PARENT_SCOPE)
set("${fci_foreach_count_items_loopvar_name}" "${fci_foreach_count_items_loopvar}" PARENT_SCOPE)
endfunction()
允许像这样使用它:
set(mylist "A:1;B:2;C:3")
foreach(ii IN LISTS mylist)
foreach_count_items(tmp item value)
# ^^^^^^^^^^ - variable list
# ^^^ - temporary iterator
if(tmp) # when iterator is set, ignore that loop, wait for the next one
continue()
enidf()
# use item and value here
set(${item} ${value})
endforeach()