# Passing flags to custom commands with generator expressions

**URL:** https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416
**Category:** Usage
**Created:** [December 21, 2025, 10:41pm UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416 "2025-12-21T22:41:09Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![roelandschoukens](https://discourse.cmake.org/user_avatar/discourse.cmake.org/roelandschoukens/32/5960_2.png) [@roelandschoukens](https://discourse.cmake.org/u/roelandschoukens)
#### Post date: [December 21, 2025, 10:41pm UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416/1 "2025-12-21T22:41:09Z")

</div>

Given a command `our_tool` that we want to run as a custom target, and we want a flag `--debug` in debug builds only:

Some sources say you add a generator expression with quotes like this:

```cmake
    ADD_CUSTOM_TARGET(our_tool_command 
                    COMMAND our_tool "$<$<config:Debug>:--debug>" 
                    VERBATIM)

```

This is wrong and results in an empty string `""` argument to our command.

Some sources say you add a generator expression without quotes like this:

```cmake
    ADD_CUSTOM_TARGET(our_tool_command 
                    COMMAND our_tool $<$<config:Debug>:--debug>
                    VERBATIM)

```

This is also wrong and still adds an empty string `""` argument to our command.

The documentation suggests COMMAND\_EXPAND\_LISTS like so

```cmake
    ADD_CUSTOM_TARGET(our_tool_command 
                    COMMAND our_tool $<$<config:Debug>:--debug>
                    VERBATIM COMMAND_EXPAND_LISTS)

```

This works, but it raises another question, what are you supposed to do if later an argument must contain a semicolon? [“Passing lists or strings with semi-colon to add\_custom\_command”](https://discourse.cmake.org/t/passing-lists-or-strings-with-semi-colon-to-add-custom-command/15231) exists but that looks a lot like a hack that works in one specific generator only. Is there a proper supported way of doing this?

---

<div class="post-metadata">

### Author: ![marc.chevrier](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/ecb155/32.png) [@marc.chevrier](https://discourse.cmake.org/u/marc.chevrier)
#### Post date: [December 22, 2025, 11:13am UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416/2 "2025-12-22T11:13:08Z")

</div>

Some remarks:

- The generator expression `$<config:...>` does not exist. The correct one is [`$<CONFIG:...>`](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:CONFIG).
- It is preferable to always specify the generator expressions inside [quotes](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#whitespace-and-quoting).

Now, your behavior is unexpected. The first example should work as expected (by specifying `$<CONFIG:...>`, of course).

What are your cmake version and generator used?

---

<div class="post-metadata">

### Author: ![roelandschoukens](https://discourse.cmake.org/user_avatar/discourse.cmake.org/roelandschoukens/32/5960_2.png) [@roelandschoukens](https://discourse.cmake.org/u/roelandschoukens)
#### Post date: [December 22, 2025, 11:51pm UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416/3 "2025-12-22T23:51:31Z")

</div>

`"$<$<CONFIG:Debug>:--debug>"` will definitely always generates an argument. That seems consistent across versions and generators. (observed in at least 3.26.5 with Makefiles and in 4.1.2 with Ninja). The documentation mentions this under [generator expressions](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#whitespace-and-quoting). I don’t see a mention of what happens without the quotes but it seems to always generate an argument as well.

Just testing with a toy example:  
args.sh:

```bash
for arg in "$@"; do
  printf '"%s"\n' "$arg"
done

```

CMakeLists.txt:

```cmake
cmake_minimum_required(VERSION 3.24)
project(test)
add_custom_target(our_tool_command 
                COMMAND sh "${CMAKE_CURRENT_LIST_DIR}/args.sh" foo "$<$<CONFIG:Debug>:--debug>" bar $<$<CONFIG:Debug>:--debug>
                VERBATIM)

```

Building the `our_tool_command` target in Release config results in

```auto
"foo"
""
"bar"
""

```

for cmake 4.1.2 using either Ninja, Unix Makefiles or Xcode.

---

<div class="post-metadata">

### Author: ![roelandschoukens](https://discourse.cmake.org/user_avatar/discourse.cmake.org/roelandschoukens/32/5960_2.png) [@roelandschoukens](https://discourse.cmake.org/u/roelandschoukens)
#### Post date: [December 23, 2025, 12:13am UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416/4 "2025-12-23T00:13:56Z")

</div>

And when adding `COMMAND_EXPAND_LISTS`:

- `"foo\\;bar"` becomes “foo;bar”
- `"foo$<SEMICOLON>bar"` will be split in two arguments “foo” “bar”
- `"foo\\$<SEMICOLON>bar"` becomes “foo;bar”

---

<div class="post-metadata">

### Author: ![marc.chevrier](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/ecb155/32.png) [@marc.chevrier](https://discourse.cmake.org/u/marc.chevrier)
#### Post date: [December 23, 2025, 9:19am UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416/5 "2025-12-23T09:19:04Z")

</div>

In fact, it seems I didn’t understand your problem: Are you complaining that an empty string is produced when the build **is not** a debug one?

If yes, the empty string is produced because you have specified the `VERBATIM` option.

---

<div class="post-metadata">

### Author: ![roelandschoukens](https://discourse.cmake.org/user_avatar/discourse.cmake.org/roelandschoukens/32/5960_2.png) [@roelandschoukens](https://discourse.cmake.org/u/roelandschoukens)
#### Post date: [December 25, 2025, 5:43am UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416/6 "2025-12-25T05:43:46Z")

</div>

Yes I thought passing `VERBATIM` is mandatory if you don’t want to be tied to one platform and generator.

So to summarize

- Pass `--debug` for debug builds, and no argument for release build. This is solved by adding `COMMAND_EXPAND_LISTS` and `"$<$<config:Debug>:--debug>"`
- But then we have no documented way of passing arguments containing semicolons.

So the solution to producing a literal `;`:

- `\\;` works and is consistent with [cmake-language § Lists](https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#cmake-language-lists) but that page cautions against relying on this when passing lists to other commands, so is this reliable behaviour across generators?

---

<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: [February 9, 2026, 5:28am UTC](https://discourse.cmake.org/t/passing-flags-to-custom-commands-with-generator-expressions/15416/7 "2026-02-09T05:28:51Z")

</div>

> [@roelandschoukens](#):
>
> Yes I thought passing `VERBATIM` is mandatory if you don’t want to be tied to one platform and generator.

FWIW, I try to avoid `VERBATIM` and haven’t had issues. But I’m very steeped in shell syntax weirdness and have a very defensive CMake coding style…
