CMake Visual Studio 将构建的 dll 和来自 Conan 的依赖 dll 组合在一起

CMake Visual Studio Group together builded dll and dependend dlls from Conan

我有一个项目,我用 CMake 管理并用 MSVC 构建它。 对于依赖管理,我使用 Conancmake_find_package 生成器。

Build it 自行运行没有任何问题。但我不能 运行 例如测试可执行文件,无需将创建的 dlldll 从依赖项复制到 Test Executable.

的位置

这是我的 conanfile.txt:

[requires]
gtest/1.10.0

[generators]
cmake_find_package

[options]
gtest:shared=True
gtest:build_gmock=True

这是我的 CMakeLists.txt 文件 DLL:

cmake_minimum_required(VERSION 3.14)

if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
    message(FATAL_ERROR "Do not build in-source. Please remove CMakeCache.txt and the CMakeFiles/ directory. Then build out-of-source")
endif()

project("CommandDispatcher" VERSION 1.0.0 LANGUAGES CXX)

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

option(BUILD_SHARED_LIBS "Build shared (dynamic) libraries." ON)
option(ENABLE_TESTING "Build with Tests enabled." ON)

include(generate_product_version)
generate_product_version(
        VersionFilesOutputVariable
        ICON ${CMAKE_CURRENT_SOURCE_DIR}/resources/Product.ico
        NAME ${PROJECT_NAME}
        VERSION_MAJOR 1
        VERSION_MINOR 0
        VERSION_PATCH 0
        VERSION_REVISION 0
)

add_library(${PROJECT_NAME})
add_library("Product::CommandDispatcher" ALIAS ${PROJECT_NAME})

target_sources(${PROJECT_NAME}
                        PUBLIC
                        include/${PROJECT_NAME}/export.hpp
                        include/${PROJECT_NAME}/command_dispatcher.hpp
                        PRIVATE
                        src/command_dispatcher.cpp
                        src/test.hpp
                        src/test.cpp
                        ${VersionFilesOutputVariable}
)

target_include_directories(${PROJECT_NAME} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
                            "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>"
                            PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>")

set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION 1 VERSION 1.0.0)

if (MSVC)
    set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX "d")
endif()

include(GenerateExportHeader)
string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
generate_export_header(${PROJECT_NAME}
    EXPORT_FILE_NAME ${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/export.hpp
    EXPORT_MACRO_NAME ${PROJECT_NAME_UPPER}_EXPORT
    STATIC_DEFINE ${PROJECT_NAME_UPPER}_STATIC
)

if(ENABLE_TESTING)
    message(STATUS "Build Library as Static Version for testing purpose")

    set(PROJECT_NAME_STATIC ${PROJECT_NAME}_static)
    add_library(${PROJECT_NAME_STATIC} STATIC)
    target_sources(${PROJECT_NAME_STATIC}
                        PUBLIC
                        include/${PROJECT_NAME}/export.hpp
                        include/${PROJECT_NAME}/command_dispatcher.hpp
                        PRIVATE
                        src/command_dispatcher.cpp
                        src/test.hpp
                        src/test.cpp
    )  
    
    target_include_directories(${PROJECT_NAME_STATIC}  PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
                                "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>"
                                PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>")

    string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
    set_target_properties(${PROJECT_NAME_STATIC} PROPERTIES COMPILE_FLAGS -D${PROJECT_NAME_UPPER}_STATIC)   

    if (MSVC)
       # set_target_properties(${PROJECT_NAME_STATIC} PROPERTIES DEBUG_POSTFIX "d")
    endif()

    message(STATUS "Running Tests for Library ${PROJECT_NAME}")

    include(CTest)
    enable_testing()
    add_subdirectory(tests)
endif()

我首先将库构建为 DLLstatic 库用于测试目的(也测试库的私有部分。

这是tests目录里面的CMakeLists.txt

set(TEST_TARGET_NAME ${PROJECT_NAME}_TEST)

add_executable(${TEST_TARGET_NAME})

target_sources(${TEST_TARGET_NAME}
                    PRIVATE
                    ExampleTest.cpp
                    TestRunner.cpp
)                   

find_package(GTest)

if(TARGET GTest::GTest)
    message(STATUS "Target Found")
    target_link_libraries(${TEST_TARGET_NAME} PRIVATE GTest::GTest)
endif()

target_link_libraries(${TEST_TARGET_NAME} PRIVATE ${PROJECT_NAME_STATIC})

add_test(NAME ${TEST_TARGET_NAME}
         COMMAND ${TEST_TARGET_NAME}
         WORKING_DIRECTORY $<TARGET_FILE_DIR:${TEST_TARGET_NAME}>)

target_include_directories(${TEST_TARGET_NAME} PRIVATE $<TARGET_PROPERTY:${PROJECT_NAME_STATIC},INCLUDE_DIRECTORIES>)                                                      

这里我 Link 与 GTest 库相对应 Conan.

如果我 运行 构建结果位于 Build 目录中的以下文件夹结构中:

+---build
    |
    +---Debug
    |       CommandDispatcherd.dll
    +---tests
    |   |               
    |   \---Debug
    |           CommandDispatcher_TEST.exe

GTest DLLs 在我的 Userfolder/.conan 下方某处。

将这些东西组合在一起的好方法是什么?例如。在 build 目录中的 bin/test 文件夹中构建 DLLTest ExeDependencies DLL

我的第一个猜测是将以下内容添加到 Conanfile.txt:

[imports]
bin, gmockd.dll -> ./bin/test
bin, gmock_maind.dll -> ./bin/test
bin, gtestd.dll -> ./bin/test
bin, gtest_maind.dll -> ./bin/test

但是为此我需要知道构建的名称 dlls

并且还将以下内容添加到 Main CMakeFile.txt:

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)

或者我应该根据 targetset_target_properties 进行更改吗?

或者有更好的解决方案吗?柯南部分还要将 DLL 复制到正确的位置吗?

也欢迎对我的 CMakeFile.txt 进行任何改进 =)。

But for this i need to know the name of the builded dlls.

我认为您不需要知道 dll 的名称。您可以像这样设置导入:

bin, *.dll -> ./bin/test @ root_package=gtest

注意 root_package 参数,它将告诉柯南从哪个包中复制 dll。 更多信息在这里:https://docs.conan.io/en/latest/reference/conanfile_txt.html#imports

或者在conanfile.py中可以实现为:

def imports(self):
    self.copy("*.dll", f"bin\tests", "bin", root_package='gtest')