Para empezar, existen algunos nombres convencionales para directorios que no puede ignorar, estos se basan en la larga tradición del sistema de archivos Unix. Estos son:
trunk
├── bin : for all executables (applications)
├── lib : for all other binaries (static and shared libraries (.so or .dll))
├── include : for all header files
├── src : for source files
└── doc : for documentation
Probablemente sea una buena idea ceñirse a este diseño básico, al menos en el nivel superior.
Acerca de dividir los archivos de encabezado y los archivos de origen (cpp), ambos esquemas son bastante comunes. Sin embargo, tiendo a preferir mantenerlos juntos, simplemente es más práctico en las tareas del día a día tener los archivos juntos. Además, cuando todo el código está en una carpeta de nivel superior, es decir, la trunk/src/
carpeta, puede observar que todas las demás carpetas (bin, lib, include, doc y tal vez alguna carpeta de prueba) en el nivel superior, además de el directorio de "compilación" para una compilación fuera de la fuente, son todas las carpetas que contienen nada más que archivos que se generan en el proceso de compilación. Y, por lo tanto, solo se debe hacer una copia de seguridad de la carpeta src, o mucho mejor, mantenerla en un sistema / servidor de control de versiones (como Git o SVN).
Y cuando se trata de instalar sus archivos de encabezado en el sistema de destino (si desea distribuir eventualmente su biblioteca), bueno, CMake tiene un comando para instalar archivos (crea implícitamente un destino de "instalación", para hacer "hacer instalar") que puede usar para poner todos los encabezados en el /usr/include/
directorio. Solo uso la siguiente macro cmake para este propósito:
# custom macro to register some headers as target for installation:
# setup_headers("/path/to/header/something.h" "/relative/install/path")
macro(setup_headers HEADER_FILES HEADER_PATH)
foreach(CURRENT_HEADER_FILE ${HEADER_FILES})
install(FILES "${SRCROOT}${CURRENT_HEADER_FILE}" DESTINATION "${INCLUDEROOT}${HEADER_PATH}")
endforeach(CURRENT_HEADER_FILE)
endmacro(setup_headers)
¿Dónde SRCROOT
está una variable cmake que configuré en la carpeta src, y INCLUDEROOT
es la variable cmake que configuro donde deben ir los encabezados? Por supuesto, hay muchas otras formas de hacer esto, y estoy seguro de que la mía no es la mejor. El punto es que no hay razón para dividir los encabezados y las fuentes solo porque solo los encabezados deben instalarse en el sistema de destino, porque es muy fácil, especialmente con CMake (o CPack), seleccionar y configurar los encabezados para instalarse sin tener que tenerlos en un directorio aparte. Y esto es lo que he visto en la mayoría de las bibliotecas.
Cita: En segundo lugar, me gustaría utilizar Google C ++ Testing Framework para realizar pruebas unitarias de mi código, ya que parece bastante fácil de usar. ¿Sugieres incluir esto con mi código, por ejemplo, en una carpeta "inc / gtest" o "contrib / gtest"? Si está incluido, ¿sugiere usar el script fuse_gtest_files.py para reducir el número de archivos, o dejarlo como está? Si no está incluido, ¿cómo se maneja esta dependencia?
No agrupe dependencias con su biblioteca. Esta es generalmente una idea bastante horrible, y siempre odio cuando estoy atascado tratando de construir una biblioteca que lo haga. Debe ser su último recurso y tenga cuidado con las trampas. A menudo, las personas agrupan dependencias con su biblioteca ya sea porque se dirigen a un entorno de desarrollo terrible (por ejemplo, Windows) o porque solo admiten una versión antigua (obsoleta) de la biblioteca (dependencia) en cuestión. El problema principal es que su dependencia empaquetada podría chocar con versiones ya instaladas de la misma biblioteca / aplicación (por ejemplo, usted empaquetó gtest, pero la persona que intenta construir su biblioteca ya tiene una versión más nueva (o anterior) de gtest ya instalada, entonces los dos podrían chocar y darle a esa persona un dolor de cabeza muy desagradable). Entonces, como dije, hazlo bajo tu propio riesgo, y yo diría que solo como último recurso. Pedirle a la gente que instale algunas dependencias antes de poder compilar su biblioteca es un mal mucho menor que tratar de resolver los conflictos entre las dependencias agrupadas y las instalaciones existentes.
Cita: Cuando se trata de pruebas de redacción, ¿cómo se organizan en general? Estaba pensando en tener un archivo cpp para cada clase (test_vector3.cpp por ejemplo) pero todos compilados en un binario para que todos puedan ejecutarse juntos fácilmente.
Un archivo cpp por clase (o un pequeño grupo cohesivo de clases y funciones) es más habitual y práctico en mi opinión. Sin embargo, definitivamente, no los compile todos en un binario sólo para que "se puedan ejecutar todos juntos". Esa es una muy mala idea. Generalmente, cuando se trata de codificación, desea dividir las cosas tanto como sea razonable para hacerlo. En el caso de las pruebas unitarias, no desea que un binario ejecute todas las pruebas, porque eso significa que cualquier pequeño cambio que realice en cualquier cosa en su biblioteca probablemente provocará una recompilación casi total de ese programa de prueba unitaria. , y eso es solo minutos / horas perdidas esperando la recompilación. Siga un esquema simple: 1 unidad = 1 programa de prueba de unidad. Luego,
Cita: Dado que la biblioteca gtest generalmente se construye usando cmake y make, estaba pensando que tendría sentido que mi proyecto también se construyera así. Si decidiera usar el siguiente diseño de proyecto:
Preferiría sugerir este diseño:
trunk
├── bin
├── lib
│ └── project
│ └── libvector3.so
│ └── libvector3.a products of installation / building
├── docs
│ └── Doxyfile
├── include
│ └── project
│ └── vector3.hpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── src
│ └── CMakeLists.txt
│ └── Doxyfile.in
│ └── project part of version-control / source-distribution
│ └── CMakeLists.txt
│ └── vector3.hpp
│ └── vector3.cpp
│ └── test
│ └── test_vector3.cpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── build
└── test working directories for building / testing
└── test_vector3
Algunas cosas para notar aquí. Primero, los subdirectorios de su directorio src deben reflejar los subdirectorios de su directorio de inclusión, esto es solo para mantener las cosas intuitivas (también, intente mantener la estructura de su subdirectorio razonablemente plana (superficial), porque la anidación profunda de carpetas es a menudo más complicado que cualquier otra cosa). En segundo lugar, el directorio "incluir" es solo un directorio de instalación, su contenido son solo los encabezados que se seleccionan del directorio src.
En tercer lugar, el sistema CMake está diseñado para distribuirse en los subdirectorios de origen, no como un archivo CMakeLists.txt en el nivel superior. Esto mantiene las cosas locales, y eso es bueno (con el espíritu de dividir las cosas en partes independientes). Si agrega una nueva fuente, un nuevo encabezado o un nuevo programa de prueba, todo lo que necesita es editar un archivo CMakeLists.txt pequeño y simple en el subdirectorio en cuestión, sin afectar nada más. Esto también le permite reestructurar los directorios con facilidad (las CMakeLists son locales y están contenidas en los subdirectorios que se están moviendo). Las CMakeLists de nivel superior deben contener la mayoría de las configuraciones de nivel superior, como la configuración de directorios de destino, comandos personalizados (o macros) y búsqueda de paquetes instalados en el sistema. Las CMakeLists de nivel inferior deben contener solo listas simples de encabezados, fuentes,
Cita: ¿Cómo debería verse CMakeLists.txt para que pueda construir solo la biblioteca o la biblioteca y las pruebas?
La respuesta básica es que CMake le permite excluir específicamente ciertos objetivos de "todos" (que es lo que se crea cuando escribe "hacer"), y también puede crear paquetes específicos de objetivos. No puedo hacer un tutorial de CMake aquí, pero es bastante sencillo descubrirlo usted mismo. En este caso específico, sin embargo, la solución recomendada es, por supuesto, usar CTest, que es solo un conjunto adicional de comandos que puede usar en los archivos CMakeLists para registrar una cantidad de objetivos (programas) que están marcados como unidad- pruebas. Entonces, CMake pondrá todas las pruebas en una categoría especial de compilaciones, y eso es exactamente lo que solicitó, entonces, problema resuelto.
Cita: También he visto bastantes proyectos que tienen un anuncio de compilación en un directorio bin. ¿La compilación ocurre en el directorio de compilación y luego los binarios se trasladan al directorio bin? ¿Los binarios de las pruebas y la biblioteca vivirían en el mismo lugar? ¿O tendría más sentido estructurarlo de la siguiente manera:
Tener un directorio de compilación fuera de la fuente (compilación "fuera de la fuente") es realmente la única cosa sensata que se puede hacer, es el estándar de facto en estos días. Entonces, definitivamente, tenga un directorio de "compilación" separado, fuera del directorio de origen, tal como lo recomienda la gente de CMake, y como lo hacen todos los programadores que he conocido. En cuanto al directorio bin, bueno, eso es una convención, y probablemente sea una buena idea ceñirse a él, como dije al principio de esta publicación.
Cita: También me gustaría usar doxygen para documentar mi código. ¿Es posible hacer que esto se ejecute automáticamente con cmake y make?
Si. Es más que posible, es asombroso. Dependiendo de lo elegante que quieras ponerte, hay varias posibilidades. CMake tiene un módulo para Doxygen (es decir, find_package(Doxygen)
) que le permite registrar objetivos que ejecutarán Doxygen en algunos archivos. Si desea hacer cosas más sofisticadas, como actualizar el número de versión en el Doxyfile, o ingresar automáticamente un sello de fecha / autor para los archivos de origen, etc., todo es posible con un poco de CMake kung-fu. Generalmente, hacer esto implicará que mantengas un Doxyfile de origen (por ejemplo, el "Doxyfile.in" que puse en el diseño de la carpeta anterior) que tiene tokens para ser encontrados y reemplazados por los comandos de análisis de CMake. En mi archivo CMakeLists de nivel superior , encontrará una pieza de CMake kung-fu que hace algunas cosas elegantes con cmake-doxygen juntos.