CMake add_custom_command not being run
Asked Answered
E

3

78

I'm trying to use add_custom_command to generate a file during the build. The command never seemed to be run, so I made this test file.

cmake_minimum_required( VERSION 2.6 )

add_custom_command(
  OUTPUT hello.txt
  COMMAND touch hello.txt
  DEPENDS hello.txt
)

I tried running:

cmake .  
make

And hello.txt was not generated. What have I done wrong?

Emmer answered 30/5, 2010 at 0:50 Comment(2)
add_custom_target could be an alternative to add_custom_commandSalver
Note that your example is definitely broken. You cannot output hello.txt and depend on hello.txt at the same time!Residency
M
46

Add the following:

add_custom_target(run ALL
    DEPENDS hello.txt)

If you're familiar with makefiles, this means:

all: run
run: hello.txt
Mabelmabelle answered 30/5, 2010 at 20:21 Comment(3)
This is not working, for me, CMake 3.6.1, OSX. I've did the following in my CMakeLists.txt add_custom_command( OUTPUT hello.txt COMMAND touch ARGS hello.txt DEPENDS hello.txt ) and added add_custom_target(run ALL DEPENDS hello.txt )Dutton
add_custom_target is run every time, use add_custom_command as advocated by Rian insteadDode
@Dutton Remove the DEPENDS from your add_custom_command() call, it creates a circular dependency. Only the add_custom_target() should have the DEPENDS argument here. It works for me on OS X when you fix that (tested with CMake 3.8.0).Gilolo
Z
79

The add_custom_target(run ALL ... solution will work for simple cases when you only have one target you're building, but breaks down when you have multiple top level targets, e.g. app and tests.

I ran into this same problem when I was trying to package up some test data files into an object file so my unit tests wouldn't depend on anything external. I solved it using add_custom_command and some additional dependency magic with set_property.

add_custom_command(
  OUTPUT testData.cpp
  COMMAND reswrap 
  ARGS    testData.src > testData.cpp
  DEPENDS testData.src 
)
set_property(SOURCE unit-tests.cpp APPEND PROPERTY OBJECT_DEPENDS testData.cpp)

add_executable(app main.cpp)
add_executable(tests unit-tests.cpp)

So now testData.cpp will generated before unit-tests.cpp is compiled, and any time testData.src changes. If the command you're calling is really slow you get the added bonus that when you build just the app target you won't have to wait around for that command (which only the tests executable needs) to finish.

It's not shown above, but careful application of ${PROJECT_BINARY_DIR}, ${PROJECT_SOURCE_DIR} and include_directories() will keep your source tree clean of generated files.

Zonda answered 22/7, 2011 at 4:7 Comment(5)
This awkward moment when the best answer is not the one with a green check icon :) Thanks Rian!Gelding
Shouldn't add_dependencies be able to do the job of the set_property(... line?Soho
There are so many other good things about cmake. One of the main things that I really like is the Generators (Makefiles, ninja files, Visual Studio, Eclipse, etc). The language of CMake is not as evolved as that of any regular high level programming language, but it's very easy once you get a hang of it in a couple of hours. Autotools was good, popular in the past. Think about this: Why are there so many people using cmake instead of autotools? It's easier to learn and provides a lot more benefits.Malloch
@dom0, You can do it with add_dependencies, but it gets a bit tricky. You can't directly add a dependency between add_custom_command and something else, you first have to create an add_custom_target (which is empty, it just serves to provide a target you can name later). The reason is that add_dependencies can only take a target as an argument, not a file. See this blog for more: samthursfield.wordpress.com/2015/11/21/…Zarf
The even MORE awkward moment when TWO answers down from the accepted answer is the best one, AND the first comment on the should-be-answer is a professional sounding one instead of a snarky one.Fossette
Z
49

The problem with two existing answers is that they either make the dependency global (add_custom_target(name ALL ...)), or they assign it to a specific, single file (set_property(...)) which gets obnoxious if you have many files that need it as a dependency. Instead what we want is a target that we can make a dependency of another target.

The way to do this is to use add_custom_command to define the rule, and then add_custom_target to define a new target based on that rule. Then you can add that target as a dependency of another target via add_dependencies.

# this defines the build rule for some_file
add_custom_command(
  OUTPUT some_file
  COMMAND ...
)
# create a target that includes some_file, this gives us a name that we can use later
add_custom_target(
  some_target
  DEPENDS some_file
)
# then let's suppose we're creating a library
add_library(some_library some_other_file.c)
# we can add the target as a dependency, and it will affect only this library
add_dependencies(some_library some_target)

The advantages of this approach:

  • some_target is not a dependency for ALL, which means you only build it when it's required by a specific target. (Whereas add_custom_target(name ALL ...) would build it unconditionally for all targets.)
  • Because some_target is a dependency for the library as a whole, it will get built before all of the files in that library. That means that if there are many files in the library, we don't have to do set_property on every single one of them.
  • If we add DEPENDS to add_custom_command then it will only get rebuilt when its inputs change. (Compare this to the approach that uses add_custom_target(name ALL ...) where the command gets run on every build regardless of whether it needs to or not.)

For more information on why things work this way, see this blog post: https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/

Zarf answered 16/8, 2018 at 16:1 Comment(0)
M
46

Add the following:

add_custom_target(run ALL
    DEPENDS hello.txt)

If you're familiar with makefiles, this means:

all: run
run: hello.txt
Mabelmabelle answered 30/5, 2010 at 20:21 Comment(3)
This is not working, for me, CMake 3.6.1, OSX. I've did the following in my CMakeLists.txt add_custom_command( OUTPUT hello.txt COMMAND touch ARGS hello.txt DEPENDS hello.txt ) and added add_custom_target(run ALL DEPENDS hello.txt )Dutton
add_custom_target is run every time, use add_custom_command as advocated by Rian insteadDode
@Dutton Remove the DEPENDS from your add_custom_command() call, it creates a circular dependency. Only the add_custom_target() should have the DEPENDS argument here. It works for me on OS X when you fix that (tested with CMake 3.8.0).Gilolo

© 2022 - 2024 — McMap. All rights reserved.