# Indirect expansion of environment and cache variables

**URL:** https://discourse.cmake.org/t/indirect-expansion-of-environment-and-cache-variables/15363
**Category:** Usage
**Created:** [December 5, 2025, 9:07am UTC](https://discourse.cmake.org/t/indirect-expansion-of-environment-and-cache-variables/15363 "2025-12-05T09:07:48Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![Andrej730](https://discourse.cmake.org/user_avatar/discourse.cmake.org/andrej730/32/5752_2.png) [@Andrej730](https://discourse.cmake.org/u/Andrej730)
#### Post date: [December 5, 2025, 9:07am UTC](https://discourse.cmake.org/t/indirect-expansion-of-environment-and-cache-variables/15363/1 "2025-12-05T09:07:48Z")

</div>

See example below.

For usual vars it’s possible to store their names in variables and then retrieve them using `${${VAR}}`.

But is it possibile for env variables? Tried to store it as `ENV{TEST_ON}` and retrieve it with `${${ENV_VAR}}` but that didn’t worked.

Not very practical question - as a workaround `ENV_VAR_VALUE` var can be defined next to `ENV_VAR`, just got curious stumbling upon this.

Also probably the same issues goes for [`CACHE`](https://cmake.org/cmake/help/latest/variable/CACHE.html) variables.

```cmake
set(TEST_ON "123")
set(VAR "TEST_ON")
# VAR's variable is 'TEST_ON' has value '123'
message(STATUS "VAR's variable is '${VAR}' has value '${${VAR}}'")

set(ENV_VAR "ENV{TEST_ON}")
set(ENV{TEST_ON} "52")
# ENV_VAR's variable is 'ENV{TEST_ON}' has value ''. Accessing it without var: '52
message(STATUS "ENV_VAR's variable is '${ENV_VAR}' has value '${${ENV_VAR}}'. Accessing it without var: '$ENV{TEST_ON}'")

set(ENV_VAR_VALUE "$ENV{TEST_ON}")
# ENV_VAR_VALUE is '52'
message(STATUS "ENV_VAR_VALUE is '${ENV_VAR_VALUE}'")

```

---

<div class="post-metadata">

### Author: ![Angew](https://discourse.cmake.org/user_avatar/discourse.cmake.org/angew/32/229_2.png) [@Angew](https://discourse.cmake.org/u/Angew)
#### Post date: [December 5, 2025, 9:19am UTC](https://discourse.cmake.org/t/indirect-expansion-of-environment-and-cache-variables/15363/2 "2025-12-05T09:19:17Z")

</div>

You can have an indirect reference to an environment variable, but you cannot have runtime choice between environment and CMake variable. In other words, you cannot do what your initial post is trying to do, but you can do this:

```auto
set(ENV_VAR "TEST_ON")
set(ENV{TEST_ON} "52")
# ENV_VAR's variable is 'TEST_ON' has value '52'
message(STATUS "ENV_VAR's variable is '${ENV_VAR}' has value '$ENV{${ENV_VAR}}'")

```

The placement of `ENV` in the `$ENV{foo}` syntax can be a hint here for how it works. It’s outside the `{}` which delimit the variable name, so whatever expands from the variable name cannot really play the role of this `ENV`.

Perhaps the cleanest way to think about this is that CMake has two distinct operators, `$` and `$ENV`. They each take a variable name as argument in `{}`, but you cannot use CMake variable to choose between them, just like you cannot use a variable to resolve to a CMake command name (i.e. you cannot do `${var}(arg arg)`.

---

<div class="post-metadata">

### Author: ![Andrej730](https://discourse.cmake.org/user_avatar/discourse.cmake.org/andrej730/32/5752_2.png) [@Andrej730](https://discourse.cmake.org/u/Andrej730)
#### Post date: [December 5, 2025, 11:04am UTC](https://discourse.cmake.org/t/indirect-expansion-of-environment-and-cache-variables/15363/3 "2025-12-05T11:04:03Z")

</div>

Thanks, makes sense.

Operators intuition sounds good for this case, but it’s a bit contradicting with some other uses of env variables. E.g. with `if(DEFINED VAR)` for environment variables translated to `if(DEFINED ENV{VAR})` - that’s probably why I started to think of `ENV{VAR}` being sort-of treated as a cmake variable name.
