CMake add_custom_command no se ejecuta

Estoy tratando de usar add_custom_command para generar un archivo durante la comstackción. El comando nunca pareció ejecutarse, así que hice este archivo de prueba.

cmake_minimum_required( VERSION 2.6 ) add_custom_command( OUTPUT hello.txt COMMAND touch hello.txt DEPENDS hello.txt ) 

Intenté correr:

 cmake . make 

Y hello.txt no fue generado. ¿Qué he hecho mal?

Agregue lo siguiente:

 add_custom_target(run ALL DEPENDS hello.txt) 

Si está familiarizado con los archivos make, esto significa:

 all: run run: hello.txt 

La add_custom_target(run ALL ... funcionará para casos simples cuando solo tiene un objective que está creando, pero se rompe cuando tiene varios objectives de nivel superior, por ejemplo, la aplicación y las pruebas.

Me encontré con este mismo problema cuando estaba tratando de empaquetar algunos archivos de datos de prueba en un archivo de objeto para que mis pruebas de unidad no dependan de nada externo. Lo resolví usando add_custom_command y alguna magia de dependencia adicional con 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) 

Entonces, testData.cpp se generará antes de comstackr unit-tests.cpp y en cualquier momento en que testData.src cambie. Si el comando que estás llamando es realmente lento, obtienes la ventaja adicional de que cuando construyes solo el objective de la aplicación no tendrás que esperar a que termine ese comando (que solo necesita el ejecutable de las pruebas).

No se muestra arriba, pero la aplicación cuidadosa de ${PROJECT_BINARY_DIR}, ${PROJECT_SOURCE_DIR} and include_directories() mantendrá su árbol fuente limpio de los archivos generados.

El problema con las dos respuestas existentes es que o bien hacen que la dependencia sea global ( add_custom_target(name ALL ...) ), o la asignan a un único archivo específico ( set_property(...) ) que se vuelve desagradable si tiene muchas archivos que lo necesitan como una dependencia. En cambio, lo que queremos es un objective que podemos hacer una dependencia de otro objective.

La forma de hacerlo es usar add_custom_command para definir la regla, y luego add_custom_target para definir un nuevo objective basado en esa regla. Luego puede agregar ese objective como una dependencia de otro objective mediante 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) 

Las ventajas de este enfoque:

  • some_target no es una dependencia para ALL , lo que significa que solo la some_target cuando es requerida por un objective específico. (Mientras que add_custom_target(name ALL ...) lo construiría incondicionalmente para todos los objectives).
  • Como some_target es una dependencia de la biblioteca como un todo, se some_target antes que todos los archivos de esa biblioteca. Eso significa que si hay muchos archivos en la biblioteca, no tenemos que hacer set_property en cada uno de ellos.
  • Si agregamos add_custom_command a add_custom_command , solo se reconstruirá cuando cambien sus entradas. (Compare esto con el enfoque que usa add_custom_target(name ALL ...) donde el comando se ejecuta en cada comstackción, independientemente de si necesita o no).

Para obtener más información sobre por qué las cosas funcionan de esta manera, consulte esta publicación en el blog: https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/