0

I would like to set up a custom command in cmake to generate some files (.h) before building our test binary, which uses those files during compilation.

My first attempt was to add the custom command to PRE_BUILD the target:

add_executable(mytest ${SRCS})

add_custom_command(
   TARGET mytest PRE_BUILD
   COMMAND <generate my_file.h>
   BYPRODUCTS my_file.h
)

target_sources(mytest PRIVATE my_file.h)

But when I attempt to build mytest the impl file (my_file.cpp) complains that my_file.h isn't found:

[ 97%] Building CXX object CMakeFiles/my_test.cpp.o
/usr/redacted/project/my_test.cpp:4:10: fatal error: 'my_test.h' file not found
#include "my_test.h"
         ^~~~~~~~~~~
1 error generated.

So I attempted to move the impl file from ${SRCS} and explicitly add it after the generated file was added:

#same as above

target_sources(mytest PRIVATE my_file.h)
target_sources(mytest PRIVATE my_file.cpp)

But that didn't seem to work either.

I have cmake_minimum_required(VERSION 3.8) with 3.25.1 installed.

starball
  • 20,030
  • 7
  • 43
  • 238
Moop
  • 3,414
  • 2
  • 23
  • 37
  • "But when I attempt to build `mytest` the impl file (`my_file.cpp`) complains that `my_file.h` isn't found." - How exactly it complains? Please, add **exact error message** to the question post. – Tsyvarev May 05 '23 at 17:06
  • Added. My custom_command command is never firing either. I tried to change it to be a separate library: `add_library(mylib my_file.cpp`) and change the `add_custom_command(TARGET mylib PRE_BUILD ...)` to target it, and just `make mylib` and it still fails. – Moop May 05 '23 at 17:09
  • Ah, more searching came up with this: https://stackoverflow.com/a/26217660/868247 – Moop May 05 '23 at 17:32
  • I was trying to refactor the code so the thing that needs the generated files (the test) was responsible for building them. Currently, I have the generated files as a `POST_BUILD` step on the generation target. I saw the `PRE_BUILD` option and was like, perfect. Obviously not. – Moop May 05 '23 at 17:51
  • 1
    If you use `add_custom_command(OUTPUT)` and list one of the outputs as a source of a binary target, cmake will ensure the files are up to date judging by the parameters provided to `add_custom_command`. If you want a generation target, use `add_custom_target()` and list the files generated by `add_custom_command()` among the files the target `DEPENDS` on. Then use `add_dependencies` to add the custom target as dependency of the target using the generated stuff and the files are updated as necessary, plus you're able to manually run the generation step by building the custom target... – fabian May 05 '23 at 21:41

1 Answers1

2

Can I use add_custom_command(... PRE_BUILD ...) on a target to generate sources for that target?

No you cannot. See the docs for PRE_BUILD, which state:

On Visual Studio Generators, run before any other rules are executed within the target. On other generators, run just before PRE_LINK commands.

I.e. The command does not run before the compilation of sources, which you need it to, since you're generating a header, which presumably you want to #include in those sources. The same applies for non-headers, which need to be compiled.

What you can do is generate the header / source file using the other signature of add_custom_command: the "generating files" signature (instead of the "build events" signature). Ex.

add_executable(mytest ${SRCS})
add_custom_command(
   OUTPUT my_file.h
   COMMAND <generate my_file.h>
   # any other arguments as necessary, Ex. DEPENDS
   VERBATIM
)
target_sources(mytest PRIVATE my_file.h)

When you do that, CMake will notice that the output file is used as a source file for another target, and generate a buildsystem that ensures the output file is generated before building that target, and that rebuilds both in order if the output file changes (Ex. it will generate a buildsystem to update the output file if any files in the DEPENDS argument change).

Other approaches may include (if appropriate), using file(GENERATE ...), or configure_file(...).

See also Craig Scott (one of the CMake maintainers)'s post on this topic here.

starball
  • 20,030
  • 7
  • 43
  • 238
  • Thanks, the doc is worded poorly, as it starts with "Visual Studio Generators" so I just ignored the whole paragraph. But the second sentence is obviously important. – Moop May 08 '23 at 19:52