Cmake string从包含用冒号分隔的键值的字符串列表中获取键值对



我有一个字符串列表(输入(:

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中迭代多个数组元素时,我多次感到沮丧。所以我创建了一个函数。以下相当长的文件可从这里获得:

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()

最新更新