2013-03-02 34 views
67

我有一個項目是導出一個靜態庫作爲目標:CMake的:如何建立外部項目,包括他們的目標

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

現在我想用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) 

問題是當項目B的CMakeLists運行時,包含文件尚不存在。

有沒有辦法讓包含依賴於正在構建的外部項目?

回答

45

我想你在這裏混合了兩種不同的範例。

正如您所指出的那樣,高度靈活的ExternalProject模塊在構建時運行它的命令,所以您不能直接使用Project A的導入文件,因爲它只在安裝項目A後才創建。

如果你想include項目A的導入文件,你會調用項目B的的CMakeLists.txt之前手動安裝Project A - 就像任何其他第三方的依賴以這種方式添加或通過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 2013-03-02 23:14:00

+0

@mirkok在某些方面,我認爲它是一個更好的界面。 *有*其他選項。例如,您可以將項目A的源代碼包含在項目B的子目錄中,並通過「add_subdirectory」將其引入。或者你可以使用'ExternalProject_Add'並做一些讓CMake運行兩次的技巧;第一次構建外部項目時,第二次成功地獲取其導入文件「project_a-targets.cmake」。 – Fraser 2013-03-03 00:41:12

+2

我想避免在源代碼樹中包含外部項目的源代碼。如果'ExternalProject_Add'的行爲像'add_subdirectory'並且暴露了所有目標,那將是非常好的。 上面描述的解決方案可能仍然是最乾淨的。 – mirkokiefer 2013-03-03 01:47:46

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 

但是它似乎相當哈克。我想提出一個替代解決方案 - 使用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()命令未默認使用。