# Ninja generator, add\_custom\_command and conditional statements

**URL:** <https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200>\
**Category:** Code\
**Tags:** gen:ninja\
**Created:** [November 13, 2019, 11:09pm UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200 "2019-11-13T23:09:31Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![UmberGryphon](https://discourse.cmake.org/user_avatar/discourse.cmake.org/umbergryphon/32/157_2.png) [@UmberGryphon](https://discourse.cmake.org/u/UmberGryphon)\
**Post date:** [November 13, 2019, 11:09pm UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200/1 "2019-11-13T23:09:31Z")

</div>

I am trying to create a command that will copy a data directory from my source directory to my build directory so that it will be grabbed when I package up a build into a zip file. For Windows, my custom command looks like

```
add_custom_command(TARGET "${target_name}" PRE_BUILD
  COMMAND IF NOT EXIST "$<SHELL_PATH:$<TARGET_FILE_DIR:${target_name}>/${dest_relpath}>" mkdir "$<SHELL_PATH:$<TARGET_FILE_DIR:${target_name}>/${dest_relpath}>"
  COMMAND cp -auv "${source_dir}/*" "$<TARGET_FILE_DIR:${target_name}>/${dest_relpath}")

```

And this works well in the MSVC generator, but in the Ninja generator, I get the following in my build.ninja file (edited for length):

PRE\_LINK = cmd.exe /C “IF NOT EXIST c:\build-dir\Debug\data mkdir c:\build-dir\Debug\data && cp -auv C:/source-dir/data/\* C:/build-dir/Debug/data”

But “&&” means “execute the second command if the first command succeeded”, which is not how I thought add\_custom\_command handled multiple commands. And both IF NOT EXIST and mkdir return errors if the directory does exist, which causes the copy to not happen.

Is this a bug in the Ninja generator for Windows? If not, how should I call add\_custom\_command in order to get the behavior I want?

---

<div class="post-metadata">

**Author:** ![kyle.edwards](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/k/65b543/32.png) [@kyle.edwards](https://discourse.cmake.org/u/kyle.edwards)\
**Post date:** [November 13, 2019, 11:23pm UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200/2 "2019-11-13T23:23:09Z")

</div>

Yeah, I would definitely not recommend trying to shoehorn chained commands into an `IF` statement inside the Ninja file like that. My recommended approach would be to put your logic inside a `cmake -P` script. For example:

```cmake
add_custom_command(TARGET "${target_name}" PRE_BUILD
  COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_LIST_DIR}/copy_dir.cmake")

```

---

<div class="post-metadata">

**Author:** ![UmberGryphon](https://discourse.cmake.org/user_avatar/discourse.cmake.org/umbergryphon/32/157_2.png) [@UmberGryphon](https://discourse.cmake.org/u/UmberGryphon)\
**Post date:** [November 14, 2019, 1:01am UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200/3 "2019-11-14T01:01:38Z")

</div>

I wrote something that the CMake documentation strongly implies will work one way, and that does in fact work that way in both the “Unix Makefiles” and “Visual Studio 15 2017 Win64” generators.

If the Ninja generator generates something that works another way that you would “definitely not recommend”, isn’t that a problem?

---

<div class="post-metadata">

**Author:** ![kyle.edwards](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/k/65b543/32.png) [@kyle.edwards](https://discourse.cmake.org/u/kyle.edwards)\
**Post date:** [November 14, 2019, 2:48pm UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200/4 "2019-11-14T14:48:24Z")

</div>

> [@UmberGryphon](#):
>
> I wrote something that the CMake documentation strongly implies will work one way

Interesting. Can you please point out where in the documentation this is implied? FWIW, the [`add_custom_command()`](https://cmake.org/cmake/help/latest/command/add_custom_command.html) documentation says:

> If more than one `COMMAND` is specified they will be executed in order, but _not_ necessarily composed into a stateful shell or batch script.

So, if the documentation implied somewhere else that your case would work, that sounds like a documentation error, and I would like to fix it.

---

<div class="post-metadata">

**Author:** ![UmberGryphon](https://discourse.cmake.org/user_avatar/discourse.cmake.org/umbergryphon/32/157_2.png) [@UmberGryphon](https://discourse.cmake.org/u/UmberGryphon)\
**Post date:** [November 14, 2019, 9:57pm UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200/6 "2019-11-14T21:57:56Z")

</div>

OK, I know what the actual problem is now. On Windows, && binds more tightly than IF does. So the PRE\_LINK command in the first post is interpreted as

IF NOT EXIST c:\build-dir\Debug\data  
( mkdir c:\build-dir\Debug\data && cp -auv C:/source-dir/data/\* C:/build-dir/Debug/data )

which I would have said as one COMMAND if that is what I intended. By using two separate COMMANDs, I was stating my intention to be

( IF NOT EXIST c:\build-dir\Debug\data mkdir c:\build-dir\Debug\data )  
&& ( cp -auv C:/source-dir/data/\* C:/build-dir/Debug/data )

Would it be possible to get the Ninja generator for Windows to add parentheses to group things so such ambiguity doesn’t happen? Now that I know that the lack of parentheses is the problem, I can work around this myself, but I would like to help other people avoid pitfalls.

---

<div class="post-metadata">

**Author:** ![kyle.edwards](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/k/65b543/32.png) [@kyle.edwards](https://discourse.cmake.org/u/kyle.edwards)\
**Post date:** [November 14, 2019, 10:10pm UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200/7 "2019-11-14T22:10:30Z")

</div>

> [@UmberGryphon](#):
>
> Would it be possible to get the Ninja generator for Windows to add parentheses to group things so such ambiguity doesn’t happen?

I will defer to @brad.king on this one.

---

<div class="post-metadata">

**Author:** ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)\
**Post date:** [November 15, 2019, 1:32pm UTC](https://discourse.cmake.org/t/ninja-generator-add-custom-command-and-conditional-statements/200/8 "2019-11-15T13:32:22Z")

</div>

I vaguely recall someone trying to modify the generator to add `(` and `)` but encountering problems. Unfortunately I could not find anything in a quick search just now. If anyone can get that working in a compatible way I’d be open to integrating it into the generator.

`add_custom_command`'s abstraction isn’t really meant to allow arbitrary shell-specific code since it’s supposed to be cross-platform. You could use `${CMAKE_COMMAND} -E make_directory ...` to make the directory instead. It doesn’t complain about already-existing directories.
