CMake: Como construir projetos externos e include seus alvos

Eu tenho um projeto que exporta uma biblioteca estática como um destino:

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

Agora quero usar o Projeto A como um projeto externo do Projeto B e include seus objectives construídos:

 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) 

O problema é que o arquivo de inclusão ainda não existe quando o CMakeLists do Projeto B é executado.

Existe uma maneira de tornar a inclusão dependente do projeto externo que está sendo construído?

Eu acho que você está misturando dois paradigmas diferentes aqui.

Como você observou, o módulo ExternalProject altamente flexível executa seus comandos no tempo de compilation, portanto, não é possível usar diretamente o arquivo de importação do Projeto A, pois ele é criado apenas quando o Projeto A é instalado.

Se você quiser include o arquivo de importação do Projeto A, terá que instalar o Projeto A manualmente antes de chamar o CMakeLists.txt do Projeto B – assim como qualquer outra dependência de terceiros adicionada dessa forma ou através de find_file / find_library / find_package .

Se você quiser usar o ExternalProject_Add , precisará adicionar algo como o seguinte ao seu 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) 

Este post tem uma resposta razoável:

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 

No entanto, parece bastante hacky. Eu gostaria de propor uma solução alternativa – use submodules 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" 

Então em MyProject/dependencies/gtest/CMakeList.txt você pode fazer 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") 

Eu não tentei isso extensivamente ainda, mas parece mais limpo.

Edit: Há uma desvantagem para esta abordagem: O subdiretório pode executar comandos install() que você não deseja. Este post tem uma abordagem para desativá-los, mas foi buggy e não funcionou para mim.

Edit 2: Se você usar add_subdirectory("googletest" EXCLUDE_FROM_ALL) , significa que os comandos install() no subdiretório não são usados ​​por padrão.

Você também pode forçar a construção do destino dependente em um processo de criação secundário

Veja minha resposta em um tópico relacionado.