We are catching errors during testing for CMP0054 policy violations. An example can be found online at Build 367.
cmake : CMake Warning (dev) at CMakeLists.txt:364 (if):
At line:8 char:5
+ cmake -G "Visual Studio 15 2017" -DCMAKE_BUILD_TYPE=$env:configur ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (CMake Warning (...s.txt:364 (if)::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
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 "MSVC" 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.
It is due to making an if statement like so:
if ("${CRYPTOPP_AMD64}" STREQUAL "1" OR "${CRYPTOPP_I386}" STREQUAL "1")
...
endif()
The statements above are consistent with What's the CMake syntax to set and use variables?, and it was the only thing that seemed to "just work" everywhere, regardless of whether the variable was set, was empty, had a 0 value, had a 1 value or had some other value.
We removed the quotes from the variable to satisfy the god damned policy and all hell broke loose. Now we are lucky to get through a CMake configuration without an error. We tried:
if (${CRYPTOPP_AMD64} STREQUAL "1" OR ${CRYPTOPP_I386} STREQUAL "1")
...
endif()
And:
if (${CRYPTOPP_AMD64} STREQUAL 1 OR ${CRYPTOPP_I386} STREQUAL 1)
...
endif()
And:
if (${CRYPTOPP_AMD64} EQUAL 1 OR ${CRYPTOPP_I386} EQUAL 1)
...
endif()
They mostly lead to a "CMake Error at CMakeLists.txt... if given arguments...". For example, here's testing on Solaris 11:
CMake Error at CMakeLists.txt:507 (if):
if given arguments:
"EQUAL" "1" "AND" "NOT" "DISABLE_SSSE3"
Unknown arguments specified
We don't control user machines, so changing a policy and running commands like cmake_policy is out of the question for us. We don't expect users to do anything special. Users are only expected to make a directory, cd into the directory, and then run cmake. That's it.
What is the syntax we should use for variables that works everywhere given the latest changes in CMake?
When we say everywhere, we mean from Cmake 2.8 to Current, and a variable that might be in any state, including set, empty, 0 value, 1 value or an unexpected value.
EDIT: We are now catching bug reports for the unquoted variables on Windows machines. Yet another damn CMake bug at Windows CMake failure when compiler path has a space.
CMake has been in the library for two years. It makes up 18% of the bugs in our bug reporter. It causes a disproportionate number of problems for users.
There are two solutions:
Just set policy CMP0054
to NEW
cmake_policy(SET CMP0054 NEW)
That would stop CMake version >= 3.1 to try to interpret variables in quotes as variable names again (see also the discussion here, nobody really wanted the OLD
behavior).
The hint that "the OLD
behavior of a policy is deprecated by definition and may be removed in a future version of CMake" just means that the CMake developers will sometime in the future remove the legacy code necessary to still support the OLD
behavior.
Change - as @Tsyvarev commented - all if
statements to just the variable name without the dollar sign and braces
if (CRYPTOPP_AMD64 STREQUAL "1" OR CRYPTOPP_I386 STREQUAL "1")
...
endif()
That would also work for older versions of CMake.
It's not an option to use the ${ }
variable de-referencing syntax without quotes, because it could end in an empty string (leading to those if()
syntax errors).
Note: As a workaround CMake modules itself are using an "x" prefix for their variable checks. But I think that looks a little weird:
if ("x${CRYPTOPP_AMD64}" STREQUAL "x1" OR "x${CRYPTOPP_I386}" STREQUAL "x1")
...
endif()
Note: You only get the CMP0054
warning if the context of your variable was actually evaluated again (so it's a hint your CMake code will not work in those places).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With