guia - ¿Es mejor especificar los archivos fuente con GLOB o cada archivo individualmente en CMake?
qgis español (4)
CMake ofrece varias formas de especificar los archivos fuente para un objetivo. Una es usar globbing ( documentation ), por ejemplo:
FILE (GLOB dir/*)
Otra es especificar cada archivo individualmente.
¿De qué manera es preferir? Globos parece fácil, pero escuché que tiene algunos inconvenientes.
¡Especifique cada archivo individualmente!
Uso un CMakeLists.txt convencional y un script python para actualizarlo. Ejecuto el script python manualmente después de agregar archivos.
Vea mi respuesta aquí: https://.com/a/48318388/3929196
Divulgación completa: originalmente prefería el enfoque globbing por su simplicidad, pero a lo largo de los años he llegado a reconocer que la enumeración explícita de los archivos es menos propensa a errores para proyectos grandes y de múltiples desarrolladores.
Respuesta original:
Las ventajas de globbing son:
Es fácil agregar nuevos archivos, ya que solo se enumeran en un solo lugar: en el disco. No globbing crea duplicación.
Su archivo CMakeLists.txt será más corto. Esta es una gran ventaja si tienes muchos archivos. No englobar hace que pierdas la lógica CMake entre enormes listas de archivos.
Las ventajas de utilizar listas de archivos codificados son:
CMake hará un seguimiento de las dependencias de un nuevo archivo en el disco correctamente: si usamos glob, los archivos no englobados la primera vez que ejecutas CMake no serán recogidos
Usted se asegura de que solo se agreguen los archivos que desea. Globbing puede recoger archivos perdidos que no desea.
Para evitar el primer problema, simplemente puede "tocar" el CMakeLists.txt que hace el glob, ya sea utilizando el comando táctil 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 usar el comando list (REMOVE_ITEM) para limpiar la lista globbed 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 utilizando 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 deba limpiar y compilar más de lo necesario para asegurarse de obtener los archivos correctos en la lista. Este es un caso de esquina, y uno donde ya estás de puntillas, que no es realmente un problema.
La mejor forma de especificar archivos de origen en CMake es listándolos explícitamente .
Los creadores de CMake recomiendan no usar globbing.
Ver: http://www.cmake.org/cmake/help/v3.3/command/file.html?highlight=glob#file
(No recomendamos utilizar GLOB para recopilar una lista de archivos de origen de su árbol de fuentes. Si no se cambia ningún archivo CMakeLists.txt cuando se agrega o elimina una fuente, el sistema de compilación generado no puede saber cuándo solicitar la regeneración de CMake).
Por supuesto, es posible que desee saber cuáles son los inconvenientes: ¡siga leyendo!
Cuando Globbing falla:
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 que otras personas construyan su código, actualicen el proyecto desde el control de versiones, ejecute la construcción y luego se comuniquen con usted, quejándose de que
"la construcción está rota".
Para empeorar las cosas, la falla generalmente da algún error de vinculación que no da pistas sobre la causa del problema y se pierde tiempo para resolverlo.
En un proyecto en el que trabajé comenzamos a englobar pero recibimos tantas quejas cuando se agregaron nuevos archivos, que era motivo suficiente para enumerar explícitamente los archivos en lugar de englobar.
Esto también rompe los flujos de trabajo de git comunes
( git bisect
y cambio entre ramas de características).
Así que no podría recomendar esto, los problemas que causa superan con creces la comodidad, 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, solo 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 haberse agregado / eliminado desde el último edificio *.
Excepciones a la regla:
Hay momentos en que es preferible aplicar globbing:
- Para configurar un archivo
CMakeLists.txt
para proyectos existentes que no usan CMake.
Es una manera rápida de hacer referencia a toda la fuente (una vez que se ejecuta el sistema de compilación, reemplaza los englobamientos con listas de archivos explícitas). - Cuando CMake no se utiliza como el sistema de compilación primario , por ejemplo, si está utilizando un proyecto que no está utilizando CMake, y le gustaría mantener su propio sistema de compilación para él.
- Para cualquier situación en la que la lista de archivos cambie tan a menudo que no sea práctico mantenerla. En este caso podría ser útil, pero luego debe 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 compilació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 esta no es una buena solución y algo mejor queda en el sistema de compilación.
Puede englobar de forma segura (y probablemente debería) a costa de un archivo adicional para contener las dependencias.
Agregue funciones como estas en alguna parte:
# 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 a globbing:
file(GLOB_RECURSE sources LIST_DIRECTORIES false *.h *.cpp)
update_deps_file("${sources}")
add_executable(test ${sources})
Todavía está recorriendo las dependencias explícitas (¡y desencadenando todas las construcciones automáticas!) 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 engloba el flujo de trabajo, debe modificar CMakeLists.txt desde dentro de Visual Studio y volver a compilar, si lo hace, ejecute cmake explícitamente o simplemente toque CMakeLists.txt.