# Proper way to craft a CMakeLists.txt whose (only) output is a Bash script?

**URL:** <https://discourse.cmake.org/t/proper-way-to-craft-a-cmakelists-txt-whose-only-output-is-a-bash-script/13439>\
**Category:** Code\
**Created:** [January 20, 2025, 5:53pm UTC](https://discourse.cmake.org/t/proper-way-to-craft-a-cmakelists-txt-whose-only-output-is-a-bash-script/13439 "2025-01-20T17:53:12Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dennis\_Ferron](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dennis_ferron/32/2953_2.png) [@Dennis\_Ferron](https://discourse.cmake.org/u/Dennis_Ferron)\
**Post date:** [January 20, 2025, 5:53pm UTC](https://discourse.cmake.org/t/proper-way-to-craft-a-cmakelists-txt-whose-only-output-is-a-bash-script/13439/1 "2025-01-20T17:53:12Z")

</div>

I have a project using ANTLR4 with an executable in a top level CMakeLists.txt, and one of the subfolders is “testrig” which I want to just produce a Bash script that issues Java commandlines to run the ANTLR4 testrig on my grammar. (The reason it can’t be a static script file is there are substitutions for the name of the grammar and path of the CMake build output for compiled artifacts produced from the grammar file.)

Previously I had written CMake code to run those Java commands during configuration step, but that required re-running configuration for that target. I changed things so that testrig builds a tool with add\_executable, but that program just used a process-start C++ library to run commands based on settings written to an .ini file generated during CMake configuration. I thought, well, this is kinda pointless pulling in a library and building an executable to do what could be just a Bash script (run by MSys2 in my case).

It seems like my “testrig/CMakeLists.txt” file could be very simple, but I’m finding it surprisingly difficult to search the web for an example of this specific use-case and only this. Everything I’ve found is either relevant to generating a file but not having a file as a target, or else does other things like add\_executable.

The problem I have with the example in this link is it uses add\_executable and thus isn’t different from the intermediate way I’ve already done it with a process-starting executable:  
[https://cmake.org/cmake/help/latest/guide/tutorial/Adding%20a%20Custom%20Command%20and%20Generated%20File.html](https://cmake.org/cmake/help/latest/guide/tutorial/Adding%20a%20Custom%20Command%20and%20Generated%20File.html)

The problem I have with this next example (add\_custom\_target) is it says the custom target will be considered always out of date. Does that mean it will rebuild the script every time even if it’s not needed to be rebuilt?  
[https://cmake.org/cmake/help/v3.0/command/add\_custom\_target.html](https://cmake.org/cmake/help/v3.0/command/add_custom_target.html)

I am sure that somehow add\_custom\_command and add\_custom\_target will be involved in the solution; I’m just not quite seeing things clearly. I’m using CMake “file(WRITE …” to create the Bash script, so I’m not understanding what there is for add\_custom\_command to do here. Do I have to change from “file(WRITE …” to “echo” commands so I can write the .sh file at build time, or can I have add\_custom\_target with DEPENDS on the output of “file(WRITE …” with no add\_custom\_command?

Actually that’s not entirely true; I would still have “add\_custom\_command” to generate the Java .class files needed by the testrig script target. Previously I had problems I never fully figured out with those custom commands getting run more times than I expected. I assume either it was because if I had multiple outputs from the command it was re-running the command for each output (instead of understanding that one command produced two files), and/or the always-out-of-date thing I am worried about for add\_custom\_target.

So to recap, first attempt looked like this:  
add\_custom\_command → .class file  
add\_custom\_command → runs ANTLR4 testrig  
add\_custom\_target ← depends on both custom commands

Second attempt:  
add\_custom\_command → .class file  
file(WRITE …) → .ini file  
add\_executable(testrig\_runner) ← depends on outputs above

Third attempt:  
add\_custom\_command → .class file  
file(WRITE …) → .sh file  
\<\<\< what goes here? \>\>\>

---

<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:** [January 22, 2025, 3:17pm UTC](https://discourse.cmake.org/t/proper-way-to-craft-a-cmakelists-txt-whose-only-output-is-a-bash-script/13439/2 "2025-01-22T15:17:06Z")

</div>

Hi. Can you please clarify when & how you want the script to be _executed?_ There’s nothing wrong with creating a script using `file(WRITE)`, which you can apparently do now. It’s not clear to me what is missing. Please elaborate on the state you want to achieve: what should get created at CMake time, what should get created at build time, what build targets (=`make what_ever` commands) should be available etc.

* * *

If the answers are “the script can be created whenever, the `.class` files should be created at build time, and there should be a `make run_script` target that runs the script if and only if invoked explicitly,” then you could achieve that like this:

```auto
add_custom_command(
  OUTPUT wherever/whatever.class 
  COMMAND somehow do it
  COMMENT "Compiling whatever.class"
  DEPENDS all/sources.java which/should/cause/rebuild.java
  VERBATIM
  # ... other args as necessary
)
file(WRITE somewhere/script.sh "script contents")
add_custom_target(run_script
  COMMAND sh somewhere/script.sh
  COMMENT "Running test script"
  DEPENDS wherever/whatever.class
  VERBATIM
  # ... other args as necessary
)

```

This will generate build rules to create the `.class` file and create a build target called `run_script` that:

- is not part of `make all` (there was no `ALL` argument in the `add_custom_target()`)
- depends on the `.class` file, i.e. causes the file to be built if it is absent or out of date
- always execute the script when invoked (via e.g. `make run_script`)

If what you want differs from the above, please specify how and we can look for a solution.

---

<div class="post-metadata">

**Author:** ![Dennis\_Ferron](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dennis_ferron/32/2953_2.png) [@Dennis\_Ferron](https://discourse.cmake.org/u/Dennis_Ferron)\
**Post date:** [January 27, 2025, 4:37am UTC](https://discourse.cmake.org/t/proper-way-to-craft-a-cmakelists-txt-whose-only-output-is-a-bash-script/13439/3 "2025-01-27T04:37:32Z")

</div>

> [@Angew](#):
>
> Can you please clarify when & how you want the script to be _executed?_

What I want is to be able to execute the script from the Run/Debug menu in CLion (as if it were an EXE generated by add\_executable). As a custom target, it does show up in CLion’s drop down of targets, but CLion won’t run non-executable targets, such as scripts:

[https://youtrack.jetbrains.com/issue/CPP-5831](https://youtrack.jetbrains.com/issue/CPP-5831)

However (and as I commented on that issue), I did find a work-around. Since I have Msys2 installed, I can specify msys2.exe as the Executable for CLion to run, and the script as an argument.

One thing this has made me realize is that although the script has a runtime dependency on build outputs, it doesn’t actually have a build dependency on it. In fact, the .sh file can be (and is) written during the configuration step. To my understanding, CMake doesn’t really have a way to express purely runtime dependencies:

> [@Expressing runtime dependencies in CMake](https://discourse.cmake.org/t/expressing-runtime-dependencies-in-cmake/2235):
>
> Hi all, I am working on a project making excessive use of run-time library loading, i.e. dlopen()/LoadLibrary(). This means that if target B uses library A, it needs: at compile time: the include directories of A at link time: nothing at load time: nothing at run time: the shared library A to be present Currently I do the following: add\_library(A.SharedLib SHARED …) add\_library(A INTERFACE) target\_include\_directories(A INTERFACE path/to/A/includes) add\_dependencies(A A.SharedLib) # mak…

…but that’s moot in this case as the script doesn’t take any build-time time. (What does get built at build time is custom commands used to compile the Java code for the grammar, which the .sh script then has a runtime dependency on.)

---

<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:** [January 27, 2025, 10:02am UTC](https://discourse.cmake.org/t/proper-way-to-craft-a-cmakelists-txt-whose-only-output-is-a-bash-script/13439/4 "2025-01-27T10:02:53Z")

</div>

I believe the example I gave covers all of your points:

- It uses the shell as the command executable (I used `sh` in the example, you’d apparently be using `msys2.exe`).
- It introduces dependencies such that the custom commands will be checked for staleness and built if necessary before the script is run.
