Open2

CMakeのif()は変数を展開したりしなかったりする

okuokuokuoku

https://github.com/okuoku/em2native-proto/commit/d25a970e612c05d3d0fc813fa5dbd1de5b6dc0cc

このコミットでビルドが壊れた。

CMakeは if 文の仕様を途中で変えて、変数をダブルクオートすることで展開しないようになった 。よって、 cmake_minimum_required を足すと挙動が変わってしまう。

macOSでは変数 APPLE1 に初期化されるため、

set(host APPLE)

message(STATUS "Host: ${host} Apple: ${APPLE}")

if(host STREQUAL "APPLE")
    message(STATUS "true")
else()
    message(STATUS "false")
endif()

# 途中で前提バージョンを変更することでポリシを切り替える
cmake_minimum_required(VERSION 3.1)

if(host STREQUAL "APPLE")
    message(STATUS "true")
else()
    message(STATUS "false")
endif()

のようにすることで、挙動が変化することを確かめられる。

-- Host: APPLE Apple: 1
-- false
-- true

いやまぁ実際には、

-- Host: APPLE Apple: 1
CMake Warning (dev) at check.cmake:5 (if):
  Policy CMP0054 is not set: Only interpret if() arguments as variables or
  keywords when unquoted.  Run "cmake --help-policy CMP0054" for policy
  details.  Use the cmake_policy command to set the policy and suppress this
  warning.

  Quoted variables like "APPLE" will no longer be dereferenced when the
  policy is set to NEW.  Since the policy is not set the OLD behavior will be
  used.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- false
-- true

のようにバッチリ警告されるけど。

okuokuokuoku

直した

https://github.com/okuoku/em2native-proto/commit/ed7a5410c971a384ebe4e7da4789311ee5d682bf

CMakeでは変数参照も展開される

cmake_minimum_required(VERSION 3.1)

set(host APPLE)

# NG: ${host} => APPLE => 1 のように展開され、 (1 STREQUAL "APPLE") は偽
if(${host} STREQUAL "APPLE")
    message(STATUS "OK")
else()
    message(STATUS "NG")
endif()

# OK: APPLE == 1 なので、1と比較した場合は真となる
if(${host} STREQUAL "1")
    message(STATUS "OK")
else()
    message(STATUS "NG")
endif()


# OK: 変数参照をクオートすれば展開は止まる
if("${host}" STREQUAL "APPLE")
    message(STATUS "OK")
else()
    message(STATUS "NG")
endif()

は、

-- NG
-- OK
-- OK

のようになる。要するに慣れてないなら if のパラメタは全部quoteしろという事で。。10年CMakeやってるけど年に1回は間違えてる気がする。