¿Es mejor especificar los archivos de origen con GLOB o cada archivo individualmente en CMake?


CMake ofrece varias formas de especificar los archivos de origen para un destino. Una es usar globbing ( documentación ), por ejemplo:

FILE (GLOB dir/*)

Otra es especificar cada archivo individualmente.

¿Qué camino es preferir? Globbing parece fácil, pero he oído que tiene algunas desventajas.

 125

4 answers

Divulgación completa: Originalmente preferí el enfoque globbing por su simplicidad, pero a lo largo de los años he llegado a reconocer que enumerar explícitamente los archivos es menos propenso a errores para grandes proyectos de múltiples desarrolladores.

Respuesta original:


Las ventajas de globbing son:

  • Es fácil agregar nuevos archivos a medida que solo se enumeran en un lugar: on disco. No globbing crea duplicación.

  • Sus listas de fabricantes.txt file will ser más corto. Esta es una gran ventaja si tengo muchos archivos. No globbing hace que pierda la lógica de CMake entre enormes listas de archivos.

Las ventajas de usar listas de archivos codificadas son:

  • CMake rastreará las dependencias de un nuevo archivo en el disco correctamente - si usamos glob a continuación, los archivos no globbed primera vez cuando se ejecuta CMake no obtendrá recogido

  • Asegúrese de que solo se agreguen los archivos que desee. Globbing puede recoger extraviado file que no quieres.

Para solucionar el primer problema, simplemente puede "tocar" las listas de CMakeLists.txt que hace el glob, ya sea mediante el comando touch o escribiendo el archivo sin cambios. Esto obligará a cmake a volver a ejecutar y recoger el nuevo archivo.

Para solucionar el segundo problema, puede organizar su código cuidadosamente en directorios, que es lo que probablemente haga de todos modos. En el peor de los casos, puede utilizar la lista(REMOVE_ITEM) comando para limpiar el global lista de archivos:

file(GLOB to_remove file_to_remove.cpp)
list(REMOVE_ITEM list ${to_remove})

La única situación real en la que esto puede morderte es si estás usando algo como git-bisect para probar versiones anteriores de tu código en el mismo directorio de compilación. En ese caso, es posible que tenga que limpiar y compilar más de lo necesario para asegurarse de obtener los archivos correctos en la lista. Este es un caso tan esquinero, y uno en el que ya estás de puntillas, que realmente no es un problema.

 158
Author: richq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-01 22:14:32

La mejor manera de especificar archivos de fuente en CMake es mediante listándolos explícitamente.

Los creadores de CMake aconsejan no usar globbing.

Véase: http://www.cmake.org/cmake/help/v3.3/command/file.html?highlight=glob#file

(No recomendamos usar GLOB para recopilar una lista de archivos fuente de su árbol de fuentes. Si no CMakeLists.el archivo txt cambia cuando se agrega o elimina una fuente, entonces el sistema de compilación generado no puede saber cuándo pedirle a CMake que se regenere.)

Por supuesto, es posible que desee saber cuáles son las desventajas - siga leyendo!


Cuando Falla el Globbing:

La gran desventaja de globbing es que la creación/eliminación de archivos no actualizará automáticamente el sistema de compilación.

Si usted es la persona que agrega los archivos, esto puede parecer una compensación aceptable, sin embargo, esto causa problemas para otras personas que construyen su código, actualizan el proyecto desde el control de versiones, ejecutar build, a continuación, en contacto con usted, quejándose de que
"the build's broken"(en inglés).

Para empeorar las cosas, la falla generalmente da algún error de enlace que no da ninguna pista a la causa del problema y se pierde tiempo para solucionarlo.

En un proyecto en el que trabajé comenzamos globbing, pero recibimos tantas quejas cuando se agregaron nuevos archivos, que fue razón suficiente para listar explícitamente los archivos en lugar de globbing.

Esto también rompe el git común flujos de trabajo
(git bisect y cambiar entre ramas de características).

Así que no podría recomendar esto, los problemas que causa superan con creces la conveniencia, cuando alguien no puede construir su software debido a esto, pueden perder mucho tiempo para rastrear el problema o simplemente darse por vencido.

Y otra nota, recordar tocar CMakeLists.txt no siempre es suficiente, con compilaciones automatizadas que usan globbing, tuve que ejecutar cmake antes de cada compilación ya que los archivos podrían haber sido añadido / eliminado desde el último edificio *.

Excepciones a la regla:

Hay momentos en los que el globbing es preferible:

  • Para configurar archivos CMakeLists.txt para proyectos existentes que no usan CMake.
    Es una forma rápida de obtener toda la fuente referenciada (una vez que se ejecuta el sistema de compilación, reemplace la globbing con listas de archivos explícitas).
  • Cuando CMake no se usa como el sistema de compilación primario, si, por ejemplo, está utilizando un proyecto que no está usando CMake, y le gustaría mantener su propio sistema de construcción para ello.
  • Para cualquier situación en la que la lista de archivos cambia tan a menudo que resulta poco práctico mantenerla. En este caso podría ser útil, pero entonces tienes que aceptar ejecutar cmake para generar archivos de compilación cada vez para obtener una compilación confiable/correcta (lo que va en contra de la intención de CMake-la capacidad de dividir la configuración de la construcción).

* Sí, podría haber escrito un código para comparar el árbol de archivos en el disco antes y después de una actualización, pero esto no es una buena solución y algo mejor dejado hasta el sistema de compilación.

 92
Author: ideasman42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-28 11:52:38

Puede glob de forma segura (y probablemente debería) al costo de un archivo adicional para mantener las dependencias.

Agregue funciones como estas en algún lugar:

# Compare the new contents with the existing file, if it exists and is the 
# same we don't want to trigger a make by changing its timestamp.
function(update_file path content)
    set(old_content "")
    if(EXISTS "${path}")
        file(READ "${path}" old_content)
    endif()
    if(NOT old_content STREQUAL content)
        file(WRITE "${path}" "${content}")
    endif()
endfunction(update_file)

# Creates a file called CMakeDeps.cmake next to your CMakeLists.txt with
# the list of dependencies in it - this file should be treated as part of 
# CMakeLists.txt (source controlled, etc.).
function(update_deps_file deps)
    set(deps_file "CMakeDeps.cmake")
    # Normalize the list so it's the same on every machine
    list(REMOVE_DUPLICATES deps)
    foreach(dep IN LISTS deps)
        file(RELATIVE_PATH rel_dep ${CMAKE_CURRENT_SOURCE_DIR} ${dep})
        list(APPEND rel_deps ${rel_dep})
    endforeach(dep)
    list(SORT rel_deps)
    # Update the deps file
    set(content "# generated by make process\nset(sources ${rel_deps})\n")
    update_file(${deps_file} "${content}")
    # Include the file so it's tracked as a generation dependency we don't
    # need the content.
    include(${deps_file})
endfunction(update_deps_file)

Y luego ir globbing:

file(GLOB_RECURSE sources LIST_DIRECTORIES false *.h *.cpp)
update_deps_file("${sources}")
add_executable(test ${sources})

Todavía estás rastreando las dependencias explícitas (¡y activando todas las compilaciones automatizadas!) como antes, solo que está en dos archivos en lugar de uno.

El único cambio en el procedimiento es después de haber creado un nuevo archivo. Si no globaliza el flujo de trabajo es modificar las listas de CMakeLists.txt desde dentro de Visual Studio y rebuild, si hace glob, ejecute cmake explícitamente , o simplemente toque las listas de CMakeLists.txt.

 8
Author: Glen Knowles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-11 07:28:11

Especifique cada archivo individualmente!

Utilizo una lista de CMakeLists convencional.txt y un script python para actualizarlo. Corro el script de python manualmente después de agregar archivos.

Ver mi respuesta aquí: https://stackoverflow.com/a/48318388/3929196

 -1
Author: palfi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-18 10:19:17