Подтвердить что ты не робот

Сравнение CMake с пустой строкой с ошибкой STREQUAL

Я всегда думаю, что если вы хотите сравнить две строки (но не переменные), все, что вам нужно сделать, это процитировать ее так:

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!
4b9b3361

Ответ 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 больше не выполняет двойных расширений для цитируемых аргументов. См. новая политика.