# CMake NOT operator broken?

**URL:** https://discourse.cmake.org/t/cmake-not-operator-broken/11419
**Category:** Development
**Created:** [August 11, 2024, 10:32am UTC](https://discourse.cmake.org/t/cmake-not-operator-broken/11419 "2024-08-11T10:32:51Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![Louis\_Strous](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/l/8e8cbc/32.png) [@Louis\_Strous](https://discourse.cmake.org/u/Louis_Strous)
#### Post date: [August 11, 2024, 10:32am UTC](https://discourse.cmake.org/t/cmake-not-operator-broken/11419/1 "2024-08-11T10:32:51Z")

</div>

I found a case where the CMake NOT operator doesn’t behave as I expected. I expect that if I negate the condition by prefixing NOT to it then the other branch of the if-statement is taken, but that doesn’t always happen. My CMake code is as follows:

```cmake
include(CheckSymbolExists)

# cmath contains sin but not nosin
check_symbol_exists(sin "cmath" HAVE_SIN)
check_symbol_exists(nosin "cmath" HAVE_NOSIN)

message("HAVE_SIN: ${HAVE_SIN}")
message("HAVE_NOSIN: ${HAVE_NOSIN}")

if (${HAVE_SIN})
  message("sin true")
else()
  message("sin false")
endif()
if (NOT ${HAVE_SIN})
  message("not sin true")
else()
  message("not sin false")
endif()

if (${HAVE_NOSIN})
  message("nosin true")
else()
  message("nosin false")
endif()
if (NOT ${HAVE_NOSIN})
  message("not nosin true")
else()
  message("not nosin false")
endif()

```

My expectation was that I’d get “sin true”, “not sin false”, “nosin false”, and “not nosin true”. I got (with CMake 3.30.2 on Microsoft Windows 11)

```auto
-- Looking for sin
-- Looking for sin - found
-- Looking for nosin
-- Looking for nosin - not found
HAVE_SIN: 1
HAVE_NOSIN:
sin true
not sin false
nosin false
not nosin false

```

So for “nosin” the same branch of the if statement is taken regardless of the use of NOT. Is this as designed? Or is it a bug?

I need some action taken if the sought symbol is not yet available. I thought I could do that using “if (NOT ${HAVE\_NOSIN}) do\_action endif()” but that doesn’t work. The workaround is to use “if (${HAVE\_NOSIN}) else() do\_action endif()”.

Best regards,  
Louis Strous

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [August 11, 2024, 10:10pm UTC](https://discourse.cmake.org/t/cmake-not-operator-broken/11419/2 "2024-08-11T22:10:12Z")

</div>

The crux of it comes down to this:

```auto
if(NOT ${some_undefined_variable})
  ...
endif()

```

The `if()` command is a bit special in how it handles its arguments. There’s different behavior depending on whether arguments are quoted or not, and there are policy settings that influence the way arguments are interpreted. For unquoted arguments, if the argument evaluates to an empty string after variable expansion has occurred, it will be as though the argument wasn’t even there. In other words, for the case above, the result will be as though you had written `if(NOT)`. Like you, I was expecting this to result in the expression being treated as true, since `if()` is treated as false, but indeed `if(NOT)` also evaluates to false. @brad.king this would be very long-standing behavior, but it does seem inconsistent. Is this something we should consider changing (with a policy, of course)?

For the specific case you gave, you can avoid this problem by using the variable names without the `${}`. This takes advantage of how the `if()` command treats arguments as both variable names or strings in some contexts. I’ll leave you to read up on this in the [if() command docs](https://cmake.org/cmake/help/latest/command/if.html), but your example could be expressed like so:

```cmake
if (HAVE_SIN)
  message("sin true")
else()
  message("sin false")
endif()
if (NOT HAVE_SIN)
  message("not sin true")
else()
  message("not sin false")
endif()

if (HAVE_NOSIN)
  message("nosin true")
else()
  message("nosin false")
endif()
if (NOT HAVE_NOSIN)
  message("not nosin true")
else()
  message("not nosin false")
endif()

```
