it-swarm.dev

¿Cómo puedo construir un proyecto de C++ con múltiples subdirectorios interdependientes?

Tengo un proyecto de C++ en el que he usado los directorios como un elemento más de la organización, de la misma forma en que uno podría usar paquetes en Java o directorios en PHP. Los directorios no pretenden ser elementos autosuficientes, sino más bien una forma de organizar todo el proyecto y evitar que las fuentes me abrumen. ¿Cómo puedo construir mis archivos CMakeLists.txt para lidiar con esto? Hacer las bibliotecas de directorios no parece encajar aquí, ya que todas son interdependientes y no están diseñadas para ser utilizadas de esa manera.

Como un problema relacionado, la mayoría de los ejemplos que he visto de varios subdirectorios en CMake (y no hay muchos de ellos) se han ignorado o pasado por alto el tema de la configuración de include_directories, que es algo con lo que he estado teniendo problemas . Aparte de combinar mis archivos de origen para determinar qué archivo depende de cuál y de qué directorio, ¿existe de todos modos simplemente establecer todos los directorios en /src/ como directorios de inclusión potenciales y dejar que CMake determine cuáles son realmente dependientes?

Aquí hay una estructura de ejemplo:

--src
  --top1
    --mid1
      --bot1
        --src1.cpp
        --hdr1.h
      --bot2
        --src2.cpp
        --hdr2.h
    --mid2
      --bot3
        --src3.cpp
        --src4.cpp
        --hdr3.h
  --top2
    --mid3
      --src5.cpp
      --hdr4.h

Y así sucesivamente. ¿Cómo puedo estructurar mis archivos CMakeLists.txt para manejar este tipo de estructura?

63
Daniel Bingham

Dado que la estructura de directorios en su proyecto solo está ahí para mantener sus archivos organizados, un enfoque es tener un CMakeLists.txt que encuentre automáticamente todos los archivos de fuentes en el directorio src y también agregue todos los directorios como directorios que incluyen un archivo de encabezado. El siguiente archivo CMake puede servir como punto de partida:

cmake_minimum_required(VERSION 3.0)

project (Foo)

file(GLOB_RECURSE Foo_SOURCES "src/*.cpp")
file(GLOB_RECURSE Foo_HEADERS "src/*.h")

set (Foo_INCLUDE_DIRS "")
foreach (_headerFile ${Foo_HEADERS})
    get_filename_component(_dir ${_headerFile} PATH)
    list (APPEND Foo_INCLUDE_DIRS ${_dir})
endforeach()
list(REMOVE_DUPLICATES Foo_INCLUDE_DIRS)

add_executable (FooExe ${Foo_SOURCES})
target_include_directories(FooExe PRIVATE ${Foo_INCLUDE_DIRS})

Los dos comandos file(GLOB_RECURSE ... determinan el conjunto de archivos de origen y encabezado. El bucle foreach calcula el conjunto de directorios de inclusión de la lista de todos los archivos de encabezado.

Un inconveniente de calcular el conjunto de archivos de origen es que CMake no detectará automáticamente cuando se agreguen nuevos archivos a su árbol de origen. Tienes que volver a crear manualmente tus archivos de compilación.

57
sakra

No soy un experto en CMake, pero como no hay otras respuestas, echaré un vistazo a la documentación y le daré una oportunidad. Organizar la fuente e incluir archivos en diferentes directorios es casi la norma.

Parece que CMake le permite dar una lista de directorios de inclusión: http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories

Así que algo como:

include_directories("src/top1/mid1/bot1" "src/top1/mid1/bot2/" ... )

Estos se pasan al compilador para que pueda encontrar los archivos de encabezado y se pasarán para cada uno de los archivos de origen. Por lo tanto, cualquiera de sus archivos de origen debería poder incluir cualquiera de los archivos de encabezado (que creo que es lo que está pidiendo).

Similar a eso, deberías poder listar todos tus archivos de origen en el comando add_executable :

add_executable(name "src/top1/mid1/bot1/src1.cpp" "src/top1/id1/bot2/src2.cpp" ...)

Así que esta sería una manera ingenua de hacer que todo se construya. Cada archivo de origen se compilará y buscará encabezados en todos esos directorios y luego los archivos de objetos se vincularán. Considere si hay alguna forma de simplificar esto de tal manera que no necesite tantas carpetas de inclusión, tal vez solo haya unos pocos archivos de encabezado comunes a los que todos los archivos de origen deban hacer referencia. Si las cosas se vuelven más complejas, puede crear sub-jerarquías en bibliotecas, etc. También considere separar los archivos y encabezados de origen (por ejemplo, en src e incluir).

2
Guy Sirton