2013-03-02 36 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()命令未默认使用。