Когда следует обертывать переменные с помощью ${...} в CMake?

Интересно, почему часто переменные в CMake обернуты знаком доллара и фигурными скобками. Например, я видел этот вызов в учебнике CMake.

include_directories(${PROJECT_BINARY_DIR})

Но из того, что я пробовал, это делает то же самое.

include_directories(PROJECT_BINARY_DIR)

Когда требуется упаковка с ${...} и что это значит? Почему переменные часто обертываются с этим, даже если это не имеет значения?

Ответы

Ответ 1

Цитата документация CMake:

Ссылка на переменную имеет форму ${variable_name} и оценивается внутри аргумента с кавычками или без кавычек. Ссылка на переменные заменяется значением переменной или пустой строкой, если переменная не установлена.

Другими словами, запись PROJECT_BINARY_DIR в буквальном смысле относится к строке "PROJECT_BINARY_DIR". Инкапсуляция в ${...} дает вам содержимое переменной с именем PROJECT_BINARY_DIR.

Рассмотрим:

set(FOO "Hello there!")
message(FOO)     # prints FOO
message(${FOO})  # prints Hello there!

Как вы уже догадались, include_directories(PROJECT_BINARY_DIR) просто пытается добавить подкаталог имени PROJECT_BINARY_DIR в каталоги include. В большинстве систем сборки, если такой каталог не существует, он просто игнорирует команду, которая могла бы обмануть вас в впечатлении, что она работает так, как ожидалось.

Популярный источник замешательства исходит из того, что if() не требует явного разыменования переменных:

set(FOO TRUE)
if(FOO)
    message("Foo was set!")
endif()

Снова документация объясняет это поведение:

if(<constant>)

Истинно, если константа равна 1, ON, YES, TRUE, Y или ненулевому числу. False, если константа равна 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, пустая строка или заканчивается в суффиксе -NOTFOUND. Именованные логические константы нечувствительны к регистру. Если аргумент не является одной из этих констант, он рассматривается как переменная.

if(<variable>)

Истинно, если переменная определяется значением, которое не является ложной константой. В противном случае. (Примечание: макросы не являются переменными.)

В частности, можно найти такие странные примеры, как:

unset(BLA)
set(FOO "BLA")
if(FOO)
    message("if(<variable>): True")
else()
    message("if(<variable>): False")
endif()
if(${FOO})
    message("if(<constant>): True")
else()
    message("if(<constant>): False")
endif()

который примет ветвь TRUE в переменном случае, а ветвь FALSE - в постоянном случае. Это связано с тем, что в постоянном случае CMake будет искать переменную BLA для выполнения проверки (которая не определена, поэтому мы попадаем в ветвь FALSE).