# Inconsistent behavior between generator expressions and if(), else(), etc.

**URL:** https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718
**Category:** Development
**Created:** [July 9, 2021, 3:31pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718 "2021-07-09T15:31:43Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![KBentley57](https://discourse.cmake.org/user_avatar/discourse.cmake.org/kbentley57/32/474_2.png) [@KBentley57](https://discourse.cmake.org/u/KBentley57)
#### Post date: [July 9, 2021, 3:31pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718/1 "2021-07-09T15:31:43Z")

</div>

Hi All,

I recently came across a bug in one of my projects build system, and I feel that its a result of an inconsistent design philosophy between the generator expressions, and the other logical functions.

using the ExternalPackage\_Add function, I’m building a few third party dependencies, based on boolean variables that I set in earlier scripts, BUILD\_ZLIB, and so on. In all of the logic handling functions, I would use this variable as

```auto
if(BUILD_ZLIB)
    ...do stuff
endif(BUILD_ZLIB)

```

if() would automatically dereference BUILD\_ZLIB to see if it were true or false.

In the ExternalProject\_Add function, I have CMAKE\_ARGS lines similar to

`$<$<BOOL:BUILD_ZLIB>:-DZLIB_ROOT=<INSTALL_DIR>>`

A casual user might expect that the same boolean variable is dereferenced here as well, especially since there’s a giant “BOOL” setting right there beside it. However, the generator expression expects a STRING variable here. BUILD\_ZLIB is interpreted as a literal string, which evaluates to TRUE. It was a mistake that was hard to find, and only after carefully reading the docs did I track it down. Fortunately the fix was a good sed command across a bunch of files to add the `${ ... }` characters , but in large projects, I’m sure it would go unnoticed.

Would it be possible to change the behavior here with a new cmake policy? IE, check to see if the RHS of the BOOL:VARIABLE is an existing variable, and dereference it, like the other logical functions? I can’t imagine it would break existing code, as the only time people would be using it this way, would be if they were making a mistake, just as I was. It would also be more consistent with the other functionality.

Thanks,

Kyle

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [July 9, 2021, 4:18pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718/2 "2021-07-09T16:18:01Z")

</div>

> [@KBentley57](#):
>
> Would it be possible to change the behavior here with a new cmake policy?

Not really. When the genex is evaluated, the variable scope is long gone and inaccessible. You need to bake in a _value_. We don’t even parse it until it is meant to be evaluated (`set(foo "$<NOT:A,GENEX")` is perfectly valid code), so there’s no indication that it’s even a variable name at that point (as it could really have been a value).

---

<div class="post-metadata">

### Author: ![kyle.edwards](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/k/65b543/32.png) [@kyle.edwards](https://discourse.cmake.org/u/kyle.edwards)
#### Post date: [July 9, 2021, 5:08pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718/3 "2021-07-09T17:08:08Z")

</div>

With this discrepancy, I’d argue that `if()` is broken rather than the generator expressions. This syntax:

```cmake
if(BUILD_ZLIB)
    # ...
endif(BUILD_ZLIB)

```

is a holdover from the very early days of CMake. If `if()` were being implemented today, it would probably look more like:

```cmake
if(${BUILD_ZLIB})
    # ...
endif()

```

with the variable expansion in `if()`, just like you would put in the generator expression: `$<BOOL:${BUILD_ZLIB}>`.

[`CMP0054`](https://cmake.org/cmake/help/latest/policy/CMP0054.html) fixes this to some extent for quoted arguments:

```cmake
if("${BUILD_ZLIB}")
    # ...
endif()

```

I’ve long considered proposing a policy to extend this to unquoted arguments and do away with the `if(VAR)` syntax entirely, but `if(VAR)` is so heavily ingrained into the CMake ecosystem by now that it would be a very invasive change, even with a policy.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [July 12, 2021, 6:27pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718/4 "2021-07-12T18:27:03Z")

</div>

> [@kyle.edwards](#):
>
> With this discrepancy, I’d argue that `if()` is broken rather than the generator expressions. This syntax:
> 
> ```auto
> if(BUILD_ZLIB)
> # ...
> endif(BUILD_ZLIB)
> 
> ```
> 
> is a holdover from the very early days of CMake. If `if()` were being implemented today, it would probably look more like:

The problem is that with `if (${BUILD_ZLIB})`, a value of `foo;bar;baz-NOTFOUND` is false (well, this is still the case today), a value of `EXISTS;"/some/path"` is not what one expects, etc. Back in the Old Days, quoting was not tracked, so `if` had no idea if the value came in via an expansion or literally.

I actually like the unquoted behavior because it makes it clearer, to me, that a variable is being tested, but I’m also pretty rigorous about my CMake style guidelines for code I write.

---

<div class="post-metadata">

### Author: ![KBentley57](https://discourse.cmake.org/user_avatar/discourse.cmake.org/kbentley57/32/474_2.png) [@KBentley57](https://discourse.cmake.org/u/KBentley57)
#### Post date: [July 12, 2021, 8:27pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718/5 "2021-07-12T20:27:53Z")

</div>

I tend to agree with Ben on the style issue - I like the look of the if(variable) rather than the if(${variable}) scheme.

Any suggestions on how to proceed with future code? I know it’s probably a non-issue, but we’ve always been in the if(variable) endif(variable) camp, especially when they’re heavily nested.

Thanks for the input,

Kyle

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [July 13, 2021, 3:12am UTC](https://discourse.cmake.org/t/inconsistent-behavior-between-generator-expressions-and-if-else-etc/3718/6 "2021-07-13T03:12:49Z")

</div>

I always leave `endif` (and other `end*` commands) with empty arguments. The reason is that `else (cond)` is really dumb and only confusing (and even more so in an `elseif` tree).

The only thing I don’t like is:

```cmake
if (var_${param})

```

breaks my “quote all variable expansions that aren’t intended to be a list of arguments to the command” rule. But it happens rarely enough that I don’t worry about it _too_ much.
