Làm thế nào để sao chép các tệp DLL vào cùng một thư mục với tệp thực thi bằng CMake?


98

Chúng tôi sử dụng CMake để tạo tệp Visual Studio của các nguồn trong SVN của chúng tôi. Bây giờ công cụ của tôi yêu cầu một số tệp DLL nằm trong cùng thư mục với tệp thực thi. Các tệp DLL nằm trong một thư mục cùng với nguồn.

Làm cách nào để thay đổi của tôi CMakeLists.txtđể dự án Visual Studio được tạo sẽ có các tệp DLL cụ thể trong thư mục phát hành / gỡ lỗi hoặc sẽ sao chép chúng khi biên dịch?

Câu trả lời:


122

Tôi sẽ sử dụng add_custom_commandđể đạt được điều này cùng với cmake -E copy_if_different.... Để có thông tin đầy đủ, hãy chạy

cmake --help-command add_custom_command
cmake -E


Vì vậy, trong trường hợp của bạn, nếu bạn có cấu trúc thư mục sau:

/CMakeLists.txt
/src
/libs/test.dll

và mục tiêu CMake của bạn mà lệnh áp dụng MyTest, sau đó bạn có thể thêm phần sau vào CMakeLists.txt của mình:

add_custom_command(TARGET MyTest POST_BUILD        # Adds a post-build event to MyTest
    COMMAND ${CMAKE_COMMAND} -E copy_if_different  # which executes "cmake - E copy_if_different..."
        "${PROJECT_SOURCE_DIR}/libs/test.dll"      # <--this is in-file
        $<TARGET_FILE_DIR:MyTest>)                 # <--this is out-file path


Nếu bạn chỉ muốn toàn bộ nội dung của /libs/thư mục được sao chép, hãy sử dụng cmake -E copy_directory:

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs"
        $<TARGET_FILE_DIR:MyTest>)


Nếu bạn cần sao chép các hình nền khác nhau tùy thuộc vào cấu hình (Ví dụ: Phát hành, Gỡ lỗi) thì bạn có thể có chúng trong các thư mục con được đặt tên với cấu hình tương ứng: /libs/Release/libs/Debug. Sau đó, bạn cần đưa loại cấu hình vào đường dẫn đến dll trong add_custom_commandcuộc gọi, như sau:

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
        $<TARGET_FILE_DIR:MyTest>)

3
Lưu ý nhanh cho những gì đã hoạt động trong trường hợp của tôi trong trường hợp nó giúp ích cho người khác trong tương lai: Tôi có một dự án thư viện tĩnh mà tệp thực thi chính liên kết tùy chọn và thư viện đó yêu cầu một DLL được sao chép nếu được thêm vào. Vì vậy, trong tệp CMakeLists.txt của thư viện đó tôi đã sử dụng ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>cho đích đích. Nếu không, nó sẽ sao chép nó vào đường dẫn xây dựng thư viện, điều này vô ích.
AberrantWolf

nó không phải là mục tiêu của các install()chỉ thị cmake để lắp ráp các tệp nhị phân? Hoặc có thể làm LIBRARYmọi thứ? Tôi không thực sự biết chuỗi công cụ.
Sandburg

1
$<TARGET_FILE_DIR:MyTest>- nó là gì? Làm thế nào để in thông tin, chính xác có nghĩa là gì
ilw

Trừ khi tôi bỏ lỡ điều gì đó khi tích hợp lệnh, phương pháp này không hoạt động đối với các thư viện được thêm vào IMPORTED_LIBRARIES. Nó phàn nàn về việc không thể chạy lệnh sau xây dựng khi chưa có gì được xây dựng.
Tzalumen

2
Khi thử nghiệm và thúc đẩy cmake của tôi: Nếu bạn đang sử dụng IMPORTEDthư viện và cần di chuyển lại các tệp DLL, bạn cần sử dụng lệnh biến thể. Nếu bạn đã thêm bạn IMPORTEDthư viện như MyImportedLibbạn sẽ sử dụng COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>Lưu ý rằng để chạy nhiều bài build lệnh bạn cần chúng tất cả ràng buộc vào lệnh một tùy chỉnh ví dụadd_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
Tzalumen

24

Tôi đặt những dòng này trong tệp CMakeLists.txt cấp cao nhất của mình. Tất cả các thư viện và tệp thực thi được biên dịch bởi CMake sẽ được đặt ở cấp cao nhất của thư mục xây dựng để các tệp thực thi có thể tìm thấy các thư viện và dễ dàng chạy mọi thứ.

set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

Lưu ý rằng điều này không giải quyết được vấn đề OP sao chép các tệp nhị phân được biên dịch trước từ thư mục nguồn của dự án.


7

Hôm nay tôi đã gặp sự cố này khi cố tạo bản dựng Windows cho chương trình của mình. Và tôi đã tự mình thực hiện một số nghiên cứu vì tất cả những câu trả lời này không làm tôi hài lòng. Có ba vấn đề chính:

  • Tôi muốn các bản dựng gỡ lỗi được liên kết với các phiên bản gỡ lỗi của thư viện và các bản dựng phát hành được liên kết với các bản dựng thư viện phát hành.

  • Ngoài ra, tôi muốn các phiên bản đúng của tệp DLL (Gỡ lỗi / Phát hành) được sao chép vào thư mục đầu ra.

  • Và tôi muốn đạt được tất cả những điều này mà không cần viết những kịch bản phức tạp và mỏng manh.

Sau khi duyệt một số hướng dẫn sử dụng CMake và một số dự án đa nền tảng tại github, tôi đã tìm thấy giải pháp này:

Khai báo thư viện của bạn dưới dạng mục tiêu với thuộc tính "IMPORTED", tham khảo gỡ lỗi và phát hành các tệp .lib và .dll của nó.

add_library(sdl2 SHARED IMPORTED GLOBAL)
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_RELEASE "${SDL_ROOT_PATH}/lib/SDL2.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_RELEASE "${SDL_ROOT_PATH}/bin/SDL2.dll")
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_DEBUG "${SDL_ROOT_PATH}/lib/SDL2d.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_DEBUG "${SDL_ROOT_PATH}/bin/SDL2d.dll")

Liên kết mục tiêu này với dự án của bạn như bình thường

target_link_libraries(YourProg sdl2 ...)

Thực hiện bước xây dựng tùy chỉnh để sao chép tệp dll đến đích của nó nếu nó đã bị thay đổi bằng cách nào đó kể từ lần tạo trước

add_custom_command ( TARGET YourProg POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)

5

Một phụ lục cho câu trả lời được chấp nhận, được thêm vào dưới dạng một câu trả lời riêng để tôi nhận được định dạng mã:

Nếu bạn đang xây dựng các hình nền của mình trong cùng một dự án, chúng thường sẽ nằm trong các thư mục Phát hành, Gỡ lỗi, v.v. Bạn sẽ phải sử dụng các biến môi trường Visual Studio để sao chép chúng một cách chính xác. ví dụ:

"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"

cho nguồn và

"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"

cho điểm đến. Lưu ý thoát!

Bạn không thể sử dụng biến CMake CMAKE_BUILD_TYPE cho cấu hình vì nó được giải quyết tại thời điểm tạo dự án VS và sẽ luôn ở bất kỳ giá trị mặc định nào.


8
Phần cuối cùng của câu trả lời được chấp nhận địa chỉ này trong sạch CMake cách sử dụng$<CONFIGURATION>
Chuck Claunch

4

Bạn cũng có thể sử dụng lệnh find_library:

find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")

Ví dụ: với EXECUTABLE_PATH đã xác định:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

bạn có thể di chuyển các tệp .dll mà tệp thực thi của bạn cần, với

file(COPY ${<some_var>}
    DESTINATION ${EXECUTABLE_OUTPUT_PATH})

2

Điều này hữu ích cho một trong số họ

SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
    ${PROJECT_SOURCE_DIR}/lib CACHE
    PATH "Directory where all the .lib files are dumped." FORCE)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY
    ${PROJECT_SOURCE_DIR}/bin CACHE
    PATH "Directory where .exe and .dll files are dumped." FORCE)

1

Bạn có thể cần thêm mục tiêu tùy chỉnh và làm cho nó phụ thuộc vào một trong các mục tiêu thực thi của bạn.

Để sao chép tệp bằng chức năng trên, hãy sử dụng:

COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`

0

Tôi là người mới bắt đầu CMake, nhưng tôi vẫn muốn chia sẻ kinh nghiệm của mình. Trong trường hợp của tôi, tôi cần một bản sao sau khi cài đặt để tất cả các tệp nhị phân của tôi đều ở trong. Trong trường hợp tệp nhị phân của bên thứ ba có thể được nhập trong CMake, những điều sau phù hợp với tôi:

find_package( dependency REQUIRED )
if( MSVC ) 
    # If done properly and if the dependency has a correct config file, IMPORTED_LOCATION_RELEASE should be defined
    get_target_property( DEP_SHARED_LIB_PATH dependency IMPORTED_LOCATION_RELEASE )
    # Create a bin directory in the install folder
    add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory  ${CMAKE_INSTALL_PREFIX}/bin/)
    # Copy the shared lib file
    add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DEP_SHARED_LIB_PATH} ${CMAKE_INSTALL_PREFIX}/bin/)
endif()

Rõ ràng IMPORTED_LOCATION_RELEASE có thể có các biến thể tùy thuộc vào cách xây dựng / cài đặt thư viện được chia sẻ. Có thể là IMPORTED_LOCATION_DEBUG.

Có lẽ có một cách tốt hơn để lấy tên tài sản đó, tôi không biết.


0

Di chuyển tệp trong quá trình xây dựng bằng cách sử dụng install

Tôi gặp sự cố này khi cố gắng làm theo hướng dẫn chính thức của CMake ở Bước 9 . Đây là vị trí của tệp tôi muốn di chuyển:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

Đây là vị trí tôi muốn tệp ở đó:

src
 |_build
    |_install
         |_bin
             - `MathFunctions.dll`

Vì DLL này được tạo dưới dạng thư viện được chia sẻ, tất cả những gì tôi làm là đưa dòng này CMakeLists.txtvào thư mục con chứa mã nguồn cho thư việnsrc/Mathfunctions/CMakeLists.txt

install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)

Nhờ câu trả lời của bạn, tôi có thể nghĩ về câu trả lời này. Chỉ là một dòng, vì vậy tôi nghĩ là ok. Có $<CONFIG>thể có hai giá trị Gỡ lỗi hoặc Phát hành Tùy thuộc vào cách dự án được xây dựng, như câu hỏi ban đầu yêu cầu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.