cmake

CMake comparte biblioteca con mĂșltiples ejecutables



(2)

Mi proyecto contiene varios ejecutables que comparten un código común. Me gustaría poner el código común en una biblioteca estática a la que puedan vincularse los ejecutables. (El código común es bastante pequeño y prefiero no tratar con bibliotecas compartidas).

El árbol fuente se parece a esto:

  • proyecto
    • CMakeLists.txt
    • común
      • CMakeLists.txt
      • src
      • incluir
    • app1
      • src
      • CMakeLists.txt
    • app2
      • src
      • CMakeLists.txt

app1 y app2 dependen del código en común.

Este código común es muy específico de la aplicación y nunca tendrá que ser utilizado por otro proyecto fuera de este árbol de directorios. Por esa razón, preferiría no instalar la biblioteca en ningún tipo de ubicación global.

El archivo CMakeLists.txt de nivel superior solo agrega los subdirectorios:

project(toplevel) cmake_minimum_required(VERSION 3.1) add_subdirectory(common) add_subdirectory(app1) add_subdirectory(app2)

El archivo CMakeLists.txt de la biblioteca común crea la biblioteca estática y los conjuntos incluyen directorios:

add_library(common STATIC common.cpp) target_include_directories(common PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include")

Y el archivo para los ejecutables se ve así:

project(app1) cmake_minimum_required(VERSION 3.1) add_executable(${PROJECT_NAME} main.cpp) target_link_libraries(${PROJECT_NAME} common)

Ahora para mi pregunta. Si ejecuto CMake desde el directorio de proyectos de nivel superior, puedo compilar app1 y app2 y se compilan con éxito. Sin embargo, si quiero construir uno solo de estos proyectos (ejecutando CMake desde la aplicación1, por ejemplo) en lugar de construir desde el directorio de nivel superior, obtengo un error porque common/include no se agrega a la ruta de búsqueda del encabezado.

Puedo ver por qué sucede esto. No hay nada en el archivo CMakeLists.txt para app1 o app2 que sea "común". Esto solo se hace en el nivel superior.

¿Hay alguna forma de evitar esto, o este comportamiento generalmente se considera aceptable? ¿Hay algo en mi configuración subóptima? Solo estoy pensando que sería bueno poder construir los proyectos individualmente en lugar de desde el nivel superior en caso de que empecemos a desarrollar más y más ejecutables que usen esta biblioteca común, pero quizás esto es algo que no debería estar preocupado por.


Cuando configura su entorno de compilación, debe reflexionar sobre los siguientes tres temas (además de otros, pero para esta discusión / respuesta lo reduje a los tres que considero relevantes aquí):

  1. Dependencias / Acoplamiento
  2. Despliegue
  3. Equipos

"Acoplamiento fuerte"

Llegué a pensar en el add_subdirectory() como compatible con "acoplamiento fuerte" y su configuración actual admite implícitamente:

  • Una biblioteca common cambia con frecuencia
  • Una implementación única (proceso y tiempo) para todas sus aplicaciones
  • Un solo equipo trabajando en la base fuente completa
    • Un IDE lo mostraría todo en una solución
    • Generas un entorno de compilación para todo

"Bajo acoplamiento"

Si desea un "acoplamiento más suelto" , puede utilizar scripts externos en otros idiomas o el uso de la macro ExternalProject_Add() de CMake. Entonces, si configura la biblioteca common (tal vez incluso incluyendo la "entrega binaria") y cada app como un proyecto separado, usted admite:

  • Una biblioteca common cambia con menos frecuencia
    • Probablemente con sus propios ciclos de lanzamiento.
  • Un ciclo de desarrollo / implementación independiente para cada aplicación
  • Un equipo de diferentes desarrolladores trabajando en cada app

Una mezcla de ambos

Entonces, como puede ver, hay muchas cosas que considerar y CMake puede brindarle apoyo para todo tipo de enfoques. Teniendo en cuenta que su proyecto podría estar en las primeras etapas, es probable que adopte un enfoque mixto (no desconecte de inmediato la biblioteca common ):

CMakeLists.txt

project(toplevel) cmake_minimum_required(VERSION 3.1) include(ExternalProject) ExternalProject_Add( app1 SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app1" PREFIX app1 INSTALL_COMMAND "" ) ExternalProject_Add( app2 SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app2" PREFIX app2 INSTALL_COMMAND "" )

app1 / CMakeLists.txt

project(app1) cmake_minimum_required(VERSION 3.1) add_subdirectory(../common common) add_executable(${PROJECT_NAME} src/main.cpp) target_link_libraries(${PROJECT_NAME} common)

En realidad, esto generará tres entornos de compilación. Uno directamente en su directorio de salida binario y uno en cada uno de los app1 y app2 .

Y en estos enfoques, es posible que desee pensar en los archivos comunes de la cadena de herramientas CMake.

Referencias


Debe usar el comando project() en los subdirectorios solo si este subproyecto está diseñado para construirse de manera independiente y como parte del proyecto de nivel superior. Este es el caso de LLVM y Clang, por ejemplo: Clang se puede compilar por separado, pero cuando el sistema de compilación LLVM detecta la fuente de Clang, también incluye sus objetivos.

En su caso no necesita subproyectos. Para compilar solo el problema objetivo de app1 o app2 , make app1 / make app2 en el directorio de compilación de proyectos.