Я всегда думаю, что если вы хотите сравнить две строки (но не переменные), все, что вам нужно сделать, это процитировать ее так:
if("${A}" STREQUAL "some string")
но теперь я узнаю, что этот код иногда печатает oops
:
cmake_minimum_required(VERSION 2.8)
if("d" STREQUAL "")
message("oops...")
endif()
Может быть, это ошибка (потому что она печатает с Xcode, но не с make)?
Или есть некоторые специальные переменные?
- cmake: 2.8.12, 2.8.11.2
- xcode: 4.6.2, 5.0.1
Обновление
Существует команда string без описанных проблем:
string(COMPARE EQUAL "${A}" "" result)
if(result)
message("...")
endif()
Обновление 2
Поведение, которое я ожидал, реализовано с CMake 3.1.0 (см. CMP0054).
Вывод теста 3.0.2 :
CMake version: 3.0.2
Quoted test
Surprise!
Unquoted test
Surprise!
Вывод теста 3.1.0 :
CMake version: 3.1.0
Quoted test
OK
Unquoted test
Surprise!
Ответ 1
Вы столкнулись с довольно раздражающим поведением "это не ошибка, а особенность" CMake. Как описано в документации если команда:
The if command was written very early in CMake history, predating the ${}
variable evaluation syntax, and for convenience evaluates variables named
by its arguments as shown in the above signatures.
Ну, удобство оказалось неудобством. В вашем примере строка "d"
рассматривается как переменная с именем d
командой if
. Если переменная d
определяется как пустая строка, оператор сообщения будет печатать "oops...", например:
set (d "")
if("d" STREQUAL "")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
Это может дать неожиданные результаты для таких утверждений, как
if("${A}" STREQUAL "some string")
потому что может быть непреднамеренное двойное расширение первого аргумента, если переменная A
определяется как строка, которая также является именем переменной CMake, например:
set (A "d")
set (d "some string")
if("${A}" STREQUAL "some string")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
Возможные обходы:
Вы можете добавить символ суффикса в строку после расширения ${}
, который не позволяет оператору if выполнять автоматическую оценку:
set (A "d")
set (d "some string")
if("${A} " STREQUAL "some string ")
message("oops...")
else()
# this branch will be taken
message("fine")
endif()
Не используйте расширение ${}
:
set (A "d")
set (d "some string")
if(A STREQUAL "some string")
message("oops...")
else()
# this branch will be taken
message("fine")
endif()
Чтобы предотвратить непреднамеренную оценку с правой стороны STREQUAL
, используйте MATCHES
вместо регулярное выражение CMake:
if(A MATCHES "^value$")
...
endif()
Дополнение: CMake 3.1 больше не выполняет двойных расширений для цитируемых аргументов. См. новая политика.