Цикл по списку строк

Я хотел бы зациклить список элементов, приведенных в строке. В соответствии с требованиями 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()
Другие вопросы по тегам