CMake: cómo crear proyectos externos e incluir sus objectives

Tengo un Proyecto A que exporta una biblioteca estática como un objective:

install(TARGETS alib DESTINATION lib EXPORT project_a-targets) install(EXPORT project_a-targets DESTINATION lib/alib) 

Ahora quiero utilizar el Proyecto A como un proyecto externo del Proyecto B e incluir sus objectives integrados:

 ExternalProject_Add(project_a URL ...project_a.tar.gz PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= ) include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake) 

El problema es que el archivo de inclusión aún no existe cuando se ejecuta CMakeLists del Proyecto B.

¿Hay alguna manera de hacer que la inclusión dependa del proyecto externo que se está creando?

Creo que estás mezclando dos paradigmas diferentes aquí.

Como notó, el módulo ExternalProject altamente flexible ejecuta sus comandos en tiempo de comstackción, por lo que no puede usar directamente el archivo de importación del Proyecto A, ya que solo se crea una vez que se ha instalado el Proyecto A.

Si desea include el archivo de importación del Proyecto A, deberá instalar el Proyecto A manualmente antes de invocar el CMakeLists.txt del Proyecto B, al igual que cualquier otra dependencia de terceros agregada de esta manera o mediante find_file / find_library / find_package .

Si desea utilizar ExternalProject_Add , deberá agregar algo como lo siguiente a su CMakeLists.txt:

 ExternalProject_Add(project_a URL ...project_a.tar.gz PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= ) include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake) ExternalProject_Get_Property(project_a install_dir) include_directories(${install_dir}/include) add_dependencies(project_b_exe project_a) target_link_libraries(project_b_exe ${install_dir}/lib/alib.lib) 

Esta publicación tiene una respuesta razonable:

CMakeLists.txt.in :

 cmake_minimum_required(VERSION 2.8.2) project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG master SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) 

CMakeLists.txt :

 # Download and unpack googletest at configure time configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) # Prevent GoogleTest from overriding our compiler/linker options # when building with Visual Studio set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Add googletest directly to our build. This adds # the following targets: gtest, gtest_main, gmock # and gmock_main add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src ${CMAKE_BINARY_DIR}/googletest-build) # The gtest/gmock targets carry header search path # dependencies automatically when using CMake 2.8.11 or # later. Otherwise we have to add them here ourselves. if (CMAKE_VERSION VERSION_LESS 2.8.11) include_directories("${gtest_SOURCE_DIR}/include" "${gmock_SOURCE_DIR}/include") endif() # Now simply link your own targets against gtest, gmock, # etc. as appropriate 

Sin embargo, parece bastante hacky. Me gustaría proponer una solución alternativa: usar submódulos de Git.

 cd MyProject/dependencies/gtest git submodule add https://github.com/google/googletest.git cd googletest git checkout release-1.8.0 cd ../../.. git add * git commit -m "Add googletest" 

Luego, en MyProject/dependencies/gtest/CMakeList.txt puede hacer algo como:

 cmake_minimum_required(VERSION 3.3) if(TARGET gtest) # To avoid diamond dependencies; may not be necessary depending on you project. return() endif() add_subdirectory("googletest") 

No he intentado esto extensivamente todavía pero parece más limpio.

Editar: Hay una desventaja en este enfoque: el subdirectorio podría ejecutar comandos de install() que no desee. Esta publicación tiene un enfoque para deshabilitarlos, pero no funcionaba y no funcionaba para mí.

Editar 2: si usa add_subdirectory("googletest" EXCLUDE_FROM_ALL) , parece que significa que los comandos de install() en el subdirectorio no se utilizan de forma predeterminada.

También puede forzar la creación del objective dependiente en un proceso secundario de fabricación

Ver mi respuesta sobre un tema relacionado.