我想循环遍历字符串中给出的项目列表。根据CMake的要求,项目以分号分隔。以下
cmake_minimum_required(VERSION 2.8)
FOREACH(LETTER "a;b;c")
MESSAGE("<<${LETTER}>>")
ENDFOREACH()
将字符串"a;b;c"
解释为字符串文字。相反,在首先为变量分配"a;b;c"
时,所有内容都按预期进行。
cmake_minimum_required(VERSION 2.8)
SET(MYLIST "a;b;c")
FOREACH(LETTER ${MYLIST})
MESSAGE("<<${LETTER}>>")
ENDFOREACH()
这是循环列表的推荐方法还是有更优雅的解决方案?
答案 0 :(得分:35)
你混淆的根源可能是CMake对引用字符串的特殊解释。
例如,以下所有内容都正确迭代字符串列表:
(1) foreach(LETTER a b c) [...]
(2) foreach(LETTER a;b;c) [...]
(3) set(MYLIST "a;b;c")
foreach(LETTER ${MYLIST}) [...]
唯一不起作用的情况是
(4) foreach(LETTER "a;b;c") [...]
在CMake's language manual for unquoted arguments中找到(1)
和(2)
有效的原因:
不带引号的参数内容由连续块中的所有文本组成 允许或转义的字符。 Escape序列和变量 评估参考文献。结果值除以相同的值 方式列表分为元素。每个非空元素都被赋予 命令调用作为参数。因此,一个不带引号的论点可能会 作为零个或多个参数被赋予命令调用。
请注意,这与quoted arguments不同,set
也评估转义序列和变量引用,但不进行列表扩展。这解释了(4)
失败的原因。
现在有趣的问题是为什么(3)
仍然成功。 {{3}}将接受单值和列表值参数。事实上,在结束)
或其中一个关键字CACHE
或PARENT_SCOPE
之前的所有内容都被视为值的一部分。因此,以下两个命令是等效的:
set(MYLIST "a;b;c")
set(MYLIST a;b;c)
在这两种情况下,MYLIST
的值都为a;b;c
(不含引号)。
当我们现在将${MYLIST}
扩展为另一个命令时,您可以认为它执行了一个简单的字符串替换,其值为MYLIST
,即a;b;c
。然后,生成的命令将通过引用或不引用参数的规则进行扩展。也就是说,以下内容将起作用:
foreach(LETTER ${MYLIST}) [...]
虽然这不会:
foreach(LETTER "${MYLIST}") [...]
答案 1 :(得分:0)
首先,考虑您是否在 foreach
调用中键入所有值,例如 foreach (N 1 2 3)
,或者您是否想要扩展一个变量,例如 foreach (N ${MY_NUMBER_LIST})
。
虽然已接受的答案扩展了行上的变量,使代码注入成为可能(如果变量是在脚本之外设置的),但它仍然适用于大多数情况。
但是为了安全循环变量(不扩展),请尝试以下操作:
# My dummy data.
set (_my_list "A B C")
string (REPLACE " " ";" _my_list "${_my_list}")
# Actual looping.
foreach (my_entry IN LISTS _my_list)
# All done! do something with ${my_entry}, for example:
if (NOT my_entry IN_LIST _my_other_list)
message(FATAL_ERROR "_my_list has ${my_entry} but _my_other_list does not!!")
endif()
endforeach()