Change policy for set(<varName>) to set to empty/uninitiated instead of unset()
Would it be possible to add a new CMake policy to make it so that calling set(<varName>)
will create and/or reset a local variable <varName>
to an empty or uninitialized state instead of removing the variable (and therefore exposing a cache var of the same name). And existing usages of set(<varName>)
should create a warning and inform the user to instead call unset(<varName>)
.
The current behavior of set(<varName>)
is very confusing and counterintuitive that a command called set()
would ever remove a variable.
For example, the following CMake code will surprise even very experienced CMake developers and users:
set(someList "d;e" CACHE STRING "")
message("Initail value of cache var someList: '${someList}'")
set(someList "false value")
message("Initial value of local var someList: '${someList}'")
set(someList)
message("Value of \${someList} after calling set(someList): '${someList}'")
list(APPEND someList a)
list(APPEND someList b)
list(APPEND someList c)
message("Value of someList after calling list(APPEND someList ...) several times: '${someList}'")
set(someList)
message("Value of \${someList} after calling set(someList): '${someList}'")
When I run that with CMake 3.20.0, I get:
$ cmake -P create_a_list.cmake
Initail value of cache var someList: 'd;e'
Initial value of local var someList: 'false value'
Value of ${someList} after calling set(someList): 'd;e'
Value of someList after calling list(APPEND someList ...) several times: 'd;e;a;b;c'
Value of ${someList} after calling set(someList): 'd;e'
The problem is that the call set(someList)
simply removes the local variable someList
that has the value false value
which then exposes the cache variable someList
with the value d;e
. It seems what list(APPEND someList a)
then picks up the cache variable value d;e
and uses it to create a local variable with that value and then appends a
to it.
So if you change set(someList)
to set(someList "")
in the code above, you get the desired behavior:
$ cmake -P create_a_list.cmake
Initail value of cache var someList: 'd;e'
Initial value of local var someList: 'false value'
Value of ${someList} after calling set(someList ""): ''
Value of someList after calling list(APPEND someList ...) several times: 'a;b;c'
Value of ${someList} after calling set(someList ""): ''
So you can never safely call set(<varName>)
and expect that to start you out with a uninitialized variable. You always have to call set(<varName> "")
to make sure you are creating an uninitialized/empty local variable that is safe to amend.
For the motivation for this, see this conversation.