2013-03-02 10 views
67

Tôi có một dự án A mà xuất khẩu một thư viện tĩnh như một mục tiêu:CMake: Làm thế nào để xây dựng các dự án bên ngoài và bao gồm các mục tiêu của họ

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

Bây giờ tôi muốn sử dụng Dự án A như một dự án bên ngoài từ Dự án B và bao gồm các mục tiêu được xây dựng của nó:

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) 

Vấn đề là tệp bao gồm chưa tồn tại khi CMakeLists của dự án B được chạy.

Có cách nào để đưa phụ thuộc vào dự án bên ngoài đang được xây dựng không?

Trả lời

45

Tôi nghĩ bạn đang trộn lẫn hai mô hình khác nhau ở đây.

Như bạn đã lưu ý, mô-đun ExternalProject rất linh hoạt chạy các lệnh của nó tại thời gian xây dựng, do đó bạn không thể sử dụng trực tiếp tệp nhập của Project A vì nó chỉ được tạo khi dự án A được cài đặt.

Nếu bạn muốn include Dự án tập tin nhập khẩu A, bạn sẽ để cài đặt Dự án Một thủ công trước khi gọi CMakeLists.txt Dự án B - giống như bất kỳ phụ thuộc bên thứ ba khác thêm vào bằng cách này hoặc thông qua find_file/find_library/find_package.

Nếu bạn muốn tận dụng ExternalProject_Add, bạn sẽ cần phải thêm một cái gì đó như sau để CMakeLists.txt của bạn:

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

Cảm ơn câu trả lời của bạn. Những gì bạn đề nghị là tương tự như những gì tôi đã có trước đây. Tôi hy vọng sẽ tìm cách sử dụng các mục tiêu được xuất ra vì nó có vẻ như giao diện đẹp hơn việc chỉ định đường dẫn lib theo cách thủ công ... – mirkokiefer

+0

@mirkok Theo một số cách, tôi đồng ý rằng đó là giao diện đẹp hơn. Có * là * một vài tùy chọn khác. Ví dụ, bạn có thể chỉ bao gồm nguồn của Project A trong thư mục con của Project B và kéo nó qua 'add_subdirectory'. Hoặc bạn có thể sử dụng 'ExternalProject_Add' và thực hiện một số thủ thuật khiến CMake chạy hai lần; lần đầu tiên xây dựng dự án bên ngoài, lần thứ hai chọn thành công tệp nhập "project_a-targets.cmake". – Fraser

+2

Tôi muốn tránh phải bao gồm nguồn của các dự án bên ngoài trong cây nguồn của tôi. Nó sẽ là tuyệt vời nếu 'ExternalProject_Add' chỉ cư xử như' add_subdirectory' và phơi bày tất cả các mục tiêu. Giải pháp mà bạn mô tả ở trên có lẽ vẫn là giải pháp sạch nhất. – mirkokiefer

4

Bạn cũng có thể buộc xây dựng kế hoạch phụ thuộc trong một make thứ quy trình

Xem my answer về một chủ đề liên quan.

8

This post có một câu trả lời hợp lý:

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 

Tuy nhiên nó không có vẻ khá hacky. Tôi muốn đề xuất một giải pháp thay thế - sử dụng các mô-đun con 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" 

Sau đó, trong MyProject/dependencies/gtest/CMakeList.txt bạn có thể làm một cái gì đó như:

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

Tôi đã không cố gắng này rộng rãi chưa nhưng có vẻ như rõ ràng hơn.

Chỉnh sửa: Có một nhược điểm đối với phương pháp này: Thư mục con có thể chạy các lệnh install() mà bạn không muốn. This post has an approach to disable them nhưng nó đã được lỗi và không làm việc cho tôi.

Chỉnh sửa 2: Nếu bạn sử dụng add_subdirectory("googletest" EXCLUDE_FROM_ALL), có vẻ như các lệnh install() trong thư mục phụ không được sử dụng theo mặc định.