Indirect expansion of environment and cache variables

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 variables.

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}'")

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:

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).

1 Like

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.