2013-03-02 2 views
67

У меня есть проект А, который экспортирует статическую библиотеку в качестве мишени:CMake: Как построить внешние проекты и включают в свои цели

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

Теперь я хочу использовать Project A в качестве внешнего проекта от проекта B и включают в свои встроенные цели:

ExternalProject_Add(project_a 
    URL ...project_a.tar.gz 
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a 
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> 
) 

include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake) 

проблема заключается в том, что включаемый файл еще не существует, когда CMakeLists Проектного B запускается.

Есть ли способ сделать включение зависимым от внешнего проекта, который строится?

ответ

45

Думаю, вы смешиваете здесь две разные парадигмы.

Как вы отметили, очень гибкий модуль ExternalProject выполняет свои команды во время сборки, поэтому вы не можете напрямую использовать файл импорта Project A, поскольку он создается только после того, как был установлен проект A.

Если вы хотите импортировать файл include Проект А, вы будете иметь установить Project вручную перед вызовом CMakeLists.txt Project Б - так же, как и любой другой зависимости третьей стороной добавил этот путь или через find_file/find_library/find_package.

Если вы хотите использовать ExternalProject_Add, вам нужно добавить что-то вроде следующего к вашему CMakeLists.txt:

ExternalProject_Add(project_a 
    URL ...project_a.tar.gz 
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a 
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> 
) 


             
  
    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)
+1

Спасибо за ваш ответ. То, что вы предлагаете, похоже на то, что у меня было раньше. Я надеялся найти способ использовать экспортированные цели, поскольку это казалось более приятным интерфейсом, чем указание путей lib вручную ... – mirkokiefer

+0

@mirkok В некотором смысле я согласен, что это более удобный интерфейс. Там * есть несколько других вариантов. Например, вы можете включить источник Project A в подкаталог Project B и вывести его через 'add_subdirectory'. Или вы можете использовать 'ExternalProject_Add' и делать некоторые обманки, которые заставляют CMake запускаться дважды; при первом создании внешнего проекта, во второй раз успешно собрал свой файл импорта «project_a-target.cmake». – Fraser

+2

Я не хотел включать источник внешних проектов в свое исходное дерево. Было бы замечательно, если бы 'ExternalProject_Add' просто вел себя как' add_subdirectory' и обнаруживал все цели. Решение, описанное выше, вероятно, по-прежнему является самым чистым. – mirkokiefer

4

Вы также можете заставить строить зависимой цели в средней марки процесс

См. my answer по соответствующей теме.

8

This post имеет разумный ответ:

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 

Однако это кажется вполне Hacky. Я хотел бы предложить альтернативное решение - использовать подмодули 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" 

Тогда в MyProject/dependencies/gtest/CMakeList.txt вы можете сделать что-то вроде:

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

Я не пробовал этого еще экстенсивно, но мне кажется чище.

Редактировать: Существует недостаток этого подхода: в подкаталоге могут выполняться команды install(), которые вы не хотите. This post has an approach to disable them, но это было плохо и не работало для меня.

Редактировать 2: Если вы используете add_subdirectory("googletest" EXCLUDE_FROM_ALL), похоже, что команды install() в подменю не используются по умолчанию.

Смежные вопросы