versiones guia español actualizar cmake

guia - ¿Por qué CMake hace una distinción entre un "objetivo" y un "comando"?



qgis español (2)

En la semántica de CMake hay algún tipo de distinción entre "objetivos" y comandos "que me desconcierta. En Makefiles, no existe tal distinción:

targetname:dependency command

es decir, los objetivos corresponden a un archivo generado del mismo nombre.

En CMake tienes comandos como "add_custom_command" y "add_custom_target" que tienen funcionalidad solapada, e incluso en la documentación oficial la semántica está confundida, es decir, en "Mastering CMake, 5ª edición", página 110 en "Agregar un destino personalizado":

El argumento DEPENDS establece una dependencia entre el objetivo personalizado y los comandos personalizados.

Mi entendimiento es que los objetivos (archivos generados) tienen dependencias (otros archivos, generados o no) y un comando para hacer realmente la generación. No tiene sentido decir que un objetivo depende de un comando. Para empeorar las cosas, hay dos formas de "add_custom_command" que añaden un comando adicional a un objetivo existente o escupir el comando en el éter.

¿Puede alguien explicar por qué esta distinción existe?


Objetivos

En general, los objetivos comprenden ejecutables o bibliotecas que se definen llamando a add_executable o add_library y que pueden tener muchas properties establecidas.

Pueden tener dependencias entre sí, lo que para objetivos como estos solo significa que los dependientes se construirán después de sus dependencias.

Sin embargo, también puede definir "objetivos personalizados" a través de add_custom_target . De los documentos:

Agrega un objetivo con el nombre de pila que ejecuta los comandos dados. El objetivo no tiene ningún archivo de salida y SIEMPRE SE CONSIDERA FUERA DE LA FECHA, incluso si los comandos intentan crear un archivo con el nombre del objetivo. Use ADD_CUSTOM_COMMAND para generar un archivo con dependencias. Por defecto, nada depende del objetivo personalizado. Use ADD_DEPENDENCIES para agregar dependencias hacia o desde otros objetivos.

Por lo tanto, estos son diferentes de los objetivos "normales" en el sentido de que no representan cosas que producirán un exe o lib, pero aún así se benefician de todas las propiedades que los destinos pueden tener, incluyendo tener o ser dependencias. Aparecen como un objetivo que se puede construir (por ejemplo, make MyCustomTarget o msbuild MyCustomTarget.vcxproj ). Cuando los construyes, simplemente estás invocando los comandos que se han establecido para ellos. Si tienen dependencias con otros objetivos (normales o personalizados), estos se construirán primero.


Comandos personalizados

Un comando personalizado definido mediante add_custom_command es bastante diferente en el sentido de que no es un objeto "editable" y no tiene propiedades configurables en la forma en que lo hace un objetivo; no es un objeto nombrado al que se puede hacer referencia explícitamente una vez que se haya agregado. el CMakeLists.txt.

Básicamente es un comando (o conjunto de comandos) que se invocará antes de construir un objetivo dependiente. Eso es todo lo que "depende" realmente significa aquí (al menos así es como lo veo); solo dice que si A depende de B, entonces B se construirá / ejecutará antes de que se construya A.

Los valores de un comando personalizado se pueden establecer de forma explícita utilizando el add_custom_command(TARGET target ... o implícitamente creando destinos que incluyen los archivos generados a través del add_custom_command(OUTPUT output1 ...

En el primer caso, cada vez que se target , el comando personalizado se ejecuta primero.

En el segundo caso, es un poco más complejo. Si el comando personalizado tiene objetivos que dependen de su archivo de salida (y el archivo de salida no existe todavía), se invoca antes de que se generen estos objetos dependientes. Las dependencias se crean implícitamente cuando lo hace, por ejemplo, add_library(MyLib output1.h ... ) donde output1.h es un archivo generado a través de add_custom_command(OUTPUT output1.h ... ) .


add_custom_command agrega una función invocable que puede tener salidas definidas (utilizando los argumentos OUTPUT y BYPRODUCTS). También puede tener dependencias que se ejecutarán antes de llamar a la función.

Tenga en cuenta que NO hace cosas que pueda pensar que se deben a documentación extraña (los ejemplos de los archivos MAKE son muy engañosos). En particular, no tiene ninguna garantía sobre el número de veces que se ejecuta. Por ejemplo, imagina esto:

add_custom_command(OUTPUT /tmp/touched COMMAND echo touch COMMAND touch /tmp/touched) add_custom_target(touched-one ALL DEPENDS /tmp/touched) add_custom_target(touched-two ALL DEPENDS /tmp/touched)

¿Cuántas veces se imprimirá el "toque"? No lo sabes, ya que no está especificado en ningún lado; make -j2 lo imprimirá dos veces, probablemente, pero depende del tiempo:

Scanning dependencies of target touched-two Scanning dependencies of target touched-one [ 50%] Generating touched touch [100%] Generating touched touch [100%] Built target touched-two [100%] Built target touched-one

Pero Ninja solo lo imprimirá una vez, probablemente:

# rm -rf * && cmake -GNinja ../c ; cmake --build . -- -j 5 [1/1] Generating touched touch

Por lo general, harás un add_custom_command para hacer algo de trabajo y eso definirá una SALIDA, y luego tendrás un add_custom_target que depende de la salida del comando personalizado. Cualquiera que quiera la salida depende del objetivo, y eso le da las garantías que desea.

Advertencia: vea este error como un gran ejemplo de por qué la construcción de herramientas de metabuild multiplataforma es REALMENTE DIFÍCIL .