CMake: come build progetti esterni e includere i loro obiettivi

Ho un progetto A che esporta una libreria statica come destinazione:

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

Ora voglio utilizzare il Progetto A come progetto esterno dal Progetto B e includere i suoi obiettivi predefiniti:

 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) 

Il problema è che il file di inclusione non esiste ancora quando viene eseguito CMakeLists del progetto B.

C’è un modo per rendere l’inclusione dipendente dal progetto esterno in costruzione?

Penso che tu stia mescolando due diversi paradigmi qui.

Come hai notato, il modulo ExternalProject altamente flessibile esegue i suoi comandi in fase di compilazione, quindi non puoi fare un uso diretto del file di importazione del Progetto A poiché è stato creato una volta che il Progetto A è stato installato.

Se si desidera include il file di importazione del progetto A, sarà necessario installare Project A manualmente prima di richiamare il CMakeLists.txt di Project B. – proprio come qualsiasi altra dipendenza di terze parti aggiunta in questo modo o tramite find_file / find_library / find_package .

Se si desidera utilizzare ExternalProject_Add , è necessario aggiungere qualcosa di simile al tuo 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) 

Questo post ha una risposta ragionevole:

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 

Tuttavia sembra abbastanza hacky. Mi piacerebbe proporre una soluzione alternativa – utilizzare i sottomoduli 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" 

Quindi in MyProject/dependencies/gtest/CMakeList.txt puoi fare qualcosa del tipo:

 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") 

Non ho ancora provato questo, ma sembra più pulito.

Modifica: c’è un lato negativo di questo approccio: la sottodirectory potrebbe eseguire comandi di install() che non si desidera. Questo post ha un approccio per disabilitarli ma era bug e non ha funzionato per me.

Modifica 2: Se si utilizza add_subdirectory("googletest" EXCLUDE_FROM_ALL) , sembra che i comandi install() nella sottodirectory non vengano utilizzati per impostazione predefinita.

È anche ansible forzare la generazione del target dipendente in un processo di produzione secondario

Vedi la mia risposta su un argomento correlato.