Цикл по списку строк
Я хотел бы зациклить список элементов, приведенных в строке. В соответствии с требованиями 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()
Это рекомендуемый способ зацикливания списка или есть более элегантное решение?
2 ответа
Источником вашей путаницы, вероятно, является специфическая интерпретация цитируемых строк в 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") [...]
Причина по которой (1)
а также (2)
работа найдена в руководстве по языку CMake для аргументов без кавычек:
Содержимое аргумента без кавычек состоит из всего текста в непрерывном блоке разрешенных или экранированных символов. Обе последовательности Escape и переменные ссылки оцениваются. Полученное значение делится таким же образом, как списки делятся на элементы. Каждый непустой элемент передается для вызова команды в качестве аргумента. Поэтому аргумент без кавычек может быть дан для вызова команды как ноль или более аргументов.
Обратите внимание, что это отличается от аргументов в кавычках, которые также оценивают Escape-последовательности и ссылки на переменные, но не выполняют расширение списка. Это объясняет почему (4)
выходит из строя.
Интересный вопрос сейчас почему (3)
все еще удается. set
будет принимать как одно значение, так и список значений аргументов. На самом деле все до закрытия )
или одно из ключевых слов 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}") [...]
Во-первых, подумайте, вводите ли вы все значения в
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()