# Why macro argument gets evaluated?

**URL:** <https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811>\
**Category:** Code\
**Created:** [January 10, 2022, 3:05pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811 "2022-01-10T15:05:57Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![ixsci](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ixsci/32/2041_2.png) [@ixsci](https://discourse.cmake.org/u/ixsci)\
**Post date:** [January 10, 2022, 3:05pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/1 "2022-01-10T15:05:57Z")

</div>

Given the following simple code:

```cmake
set(var [[\$\{something\}]])
function(print_fun VAR)
    message("Fun: {${VAR}}")
endfunction()
macro(print_mac VAR)
    message("Mac: {${VAR}}")
endmacro()
print_fun("${var}")
print_mac("${var}")

```

It will produce this output:

```auto
Fun: {\$\{something\}}
Mac: {${something}}

```

So it is clear that in the macro our argument changed (got evaluated) and in the function it stayed intact. Could you please point me to the part in the docs which describes this behavior?

---

<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:** [January 10, 2022, 4:46pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/2 "2022-01-10T16:46:06Z")

</div>

[https://cmake.org/cmake/help/latest/command/macro.html#arguments](https://cmake.org/cmake/help/latest/command/macro.html#arguments)

---

<div class="post-metadata">

**Author:** ![ixsci](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ixsci/32/2041_2.png) [@ixsci](https://discourse.cmake.org/u/ixsci)\
**Post date:** [January 10, 2022, 5:12pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/3 "2022-01-10T17:12:59Z")

</div>

And what exactly explains this behavior in the section you linked in?

---

<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:** [January 10, 2022, 5:28pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/4 "2022-01-10T17:28:58Z")

</div>

> When a macro is invoked, the commands recorded in the macro are first modified by replacing formal parameters (`${arg1}`, …) with the arguments passed, and then invoked as normal commands.

---

<div class="post-metadata">

**Author:** ![ixsci](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ixsci/32/2041_2.png) [@ixsci](https://discourse.cmake.org/u/ixsci)\
**Post date:** [January 10, 2022, 5:35pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/5 "2022-01-10T17:35:03Z")

</div>

And how does it answer what I asked? Try replacing formal parameters with actual argument just like it says in the docs and see what happens:  
`message("Mac: {${VAR}}")` ==\> `message("Mac: {\\$\\{something\\}}")`  
And that should print exactly the same as with function.

---

<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:** [January 10, 2022, 10:59pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/6 "2022-01-10T22:59:07Z")

</div>

Nope, it means that the content of the macro first has a replacement of its formal (named) parameters expanded. _Then_ the code is executed. This is why this code doesn’t work:

```cmake
macro (foo arg)
  if (arg) # Macro arguments are not variables, so this doesn't care about what it looks like it cares about
    message("arg: ${arg}") # prints `arg: 0` because this is replaced by the macro argument value
  endif ()
endmacro ()

set(arg 1) # What that `if` sees
foo(0)

```

If `foo` was instead a `function`, the argument exists as a variable and the `if` would end up in the `else()` branch.

---

<div class="post-metadata">

**Author:** ![ixsci](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ixsci/32/2041_2.png) [@ixsci](https://discourse.cmake.org/u/ixsci)\
**Post date:** [January 11, 2022, 4:48am UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/7 "2022-01-11T04:48:19Z")

</div>

Sorry, but I still fail to see how any of it explains the evaluation of the argument. Let’s get the outer variable out of the way and simplify the calling code to this:

```cmake
print_fun([[\$\{something\}]])
print_mac([[\$\{something\}]])

```

So we have a literal replacement in case of macro, so our argument should go directly to where it is mentioned (`message("Mac: {${VAR}}")`) but somewhere our argument gets evaluated and all ‘\’ get dropped. I don’t see how docs explain it, in my opinion docs are silent about this quirk hence this question: is it a doc deficiency or macro’s behavior is incorrect?

---

<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:** [January 11, 2022, 1:39pm UTC](https://discourse.cmake.org/t/why-macro-argument-gets-evaluated/4811/8 "2022-01-11T13:39:48Z")

</div>

The macro replaces the value in the code, so the code now looks like `fun("\$\{expanded_value\}")` which is just a string with escapes (which avoid the expansion, but don’t get printed). Given the quoting rules, losing the escapes doesn’t surprise me, but I don’t know which path actually does that. I also don’t know how to write documentation for this beyond what is already stated: macro arguments are expanded and then the code is executed after expansion. I suppose that an explicit note about that this may mean an extra layer of escaping is necessary depending on the usage of the argument in the macro body is useful, but I can see that as just leading to more confusion too.

Really, just avoid macros unless you _need_ the “affects the calling scope” behavior and use functions for everything else.
