CMake - 如何链接到我与项目一起打包的外部库

CMake - How Can I link to an external library that I have packed with my project?

本文关键字:一起 项目 外部 何链接 链接 CMake      更新时间:2023-10-16

如何链接到我与项目一起打包的外部库?

以下是我的项目的设置方式:

有一个名为App的文件夹,这就是我的主要.cpp所在的位置。

C:RaphsrcApp
main.cpp

我还有一个名为"ExternalLibrary"的文件夹,这是我捆绑Qt库的地方,我需要在我的项目中使用:

C:RaphsrcExternalLibraryPlatformWindowsQt5.6VS2013_64bit

它包含3个文件夹:

**bin**
    moc.exe
    rcc.exe
    uic.exe
    ......
    bunch of Qt dll files
**include**
    bunch of Qt header files
**lib**
    bunch of Qt lib files 

我需要设置 Cmake 来做三件事:

  1. 链接到我动态打包在"外部库"中的Qt库。

  2. 每次我在项目中添加Qt类或资源时.exe自动执行moc.exe,uic.exe,rcc。我也不需要任何生成的moc_myClassname.cpp显示在项目中。

  3. 我希望所有Qt dll最终都位于可执行文件所在的bin文件夹中,例如:

    C:\Raph\

    build\Raph\Windows\x64\Debug\bin

    拉夫.exe + 所有必要的 Qt Dll

(1)您可以通过以下方式找到Qt库:

find_package(Qt5Core [...] 5.6 REQUIRED)
add_executable(someExe file1.cpp)
target_link_libraries(someExe Qt5::Core)

请注意,您应该保留 Qt 的原始目录结构,也包含 Qt cmake 脚本,例如 lib/cmake/Qt5/Qt5Config.cmake

如果您希望在搜索Qt

时包含特定目录,则可以(在搜索Qt之前):

set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "./your/path")

例如,这可以是您提供的目录。

(2)您可以使用cmake的自动功能。只需添加

set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

在 cmake 脚本的开头。CMake 还支持 AUTOUICAUTORCC 。我还没有尝试过它们,但可能工作相似。

(3) 例如,您可以向项目添加一个自定义目标,用于复制 dll。生成该目标时,将复制所有 dll。您可以从 Qt 查找脚本定义的目标(如 Qt5::Core )获取的 dll 路径。

get_target_property(LOC_R Qt5::Core LOCATION_RELEASE)
get_target_property(LOC_D Qt5::Core LOCATION_DEBUG)

但是,还应扫描这些目标的依赖项(它们所依赖的其他 dll)。您可以编写一个宏来扫描相应的dll的整个目标列表并将它们添加到列表中,我们称这些RELEASE_DLLSDEBUG_DLLS

macro(copydlls RELEASE_DLLS DEBUG_DLLS MODULELIST)
    foreach(ELEMENT ${${MODULELIST}})
        get_target_property(LOC_R ${ELEMENT} LOCATION_RELEASE)
        get_target_property(LOC_D ${ELEMENT} LOCATION_DEBUG)
        list(APPEND ${RELEASE_DLLS} ${LOC_R})
        list(APPEND ${DEBUG_DLLS} ${LOC_D})

        get_target_property(DEPENDENCIES_RELEASE ${ELEMENT} IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE)
        foreach(DEPENDENCY ${DEPENDENCIES_RELEASE})
            if(TARGET ${DEPENDENCY})
                get_target_property(LOC_R ${DEPENDENCY} LOCATION_RELEASE)
                if(${LOC_R} MATCHES ".dll$")
                    list(APPEND ${RELEASE_DLLS} ${LOC_R})
                endif()
            endif()
        endforeach()    
        get_target_property(DEPENDENCIES_DEBUG ${ELEMENT} IMPORTED_LINK_DEPENDENT_LIBRARIES_DEBUG)
        foreach(DEPENDENCY ${DEPENDENCIES_DEBUG})
            if(TARGET ${DEPENDENCY})
                get_target_property(LOC_D ${DEPENDENCY} LOCATION_DEBUG)
                if(${LOC_D} MATCHES ".dll$")
                    list(APPEND ${DEBUG_DLLS} ${LOC_D})
                endif()         
            endif()
        endforeach()    
        get_target_property(DEPENDENCIES_RELEASE ${ELEMENT} IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE)
        foreach(DEPENDENCY ${DEPENDENCIES_RELEASE})
            if(TARGET ${DEPENDENCY})
                get_target_property(LOC_R ${DEPENDENCY} LOCATION_RELEASE)
                if(${LOC_R} MATCHES ".dll$")
                    list(APPEND ${RELEASE_DLLS} ${LOC_R})
                endif()
            endif()
        endforeach()    
        get_target_property(DEPENDENCIES_DEBUG ${ELEMENT} IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG)
        foreach(DEPENDENCY ${DEPENDENCIES_DEBUG})
            if(TARGET ${DEPENDENCY})
                get_target_property(LOC_D ${DEPENDENCY} LOCATION_DEBUG)
                if(${LOC_D} MATCHES ".dll$")
                    list(APPEND ${DEBUG_DLLS} ${LOC_D})
                endif()
            endif()
        endforeach()
    endforeach()
endmacro()

然后,您可以通过使用以下方式调用此宏来获取列表中的所有 Qt dll:

IF(MSVC)
    set(QT_MODULES "Qt5::Core" "Qt5::Gui" "Qt5::Widgets")
    set(RELEASE_DLLS)
    set(DEBUG_DLLS)
    copydlls(RELEASE_DLLS DEBUG_DLLS QT_MODULES)    
ENDIF(MSVC)

检索到该信息后,可以通过以下方式创建自定义目标。假设您在列表中的所有 dll 路径都RELEASE_DLLSDEBUG_DLLS 以及您的可执行文件名称作为 TARGETS 中的列表。然后你可以做这样的事情:

if(MSVC)
    set(COPY_COMMAND_RELEASE "-E copy_if_different ")
    set(COPY_COMMAND_DEBUG "-E copy_if_different ")
    list(REMOVE_DUPLICATES RELEASE_DLLS)
    list(REMOVE_DUPLICATES DEBUG_DLLS)
    foreach(DLL ${RELEASE_DLLS})
        string(CONCAT COPY_COMMAND_RELEASE "${COPY_COMMAND_RELEASE} "${DLL}" ")
    endforeach()
    foreach(DLL ${DEBUG_DLLS})
        string(CONCAT COPY_COMMAND_DEBUG "${COPY_COMMAND_DEBUG} "${DLL}" ")
    endforeach()
    string(CONCAT COPY_COMMAND_RELEASE ${COPY_COMMAND_RELEASE} ""${CMAKE_CURRENT_BINARY_DIR}/Release" ")
    string(CONCAT COPY_COMMAND_DEBUG ${COPY_COMMAND_DEBUG} ""${CMAKE_CURRENT_BINARY_DIR}/Debug" ")
    add_custom_target(COPY_DLLS)
    foreach(EXECUTABLE ${TARGETS})
        add_custom_command(TARGET COPY_DLLS PRE_BUILD COMMAND ${CMAKE_COMMAND} ${COPY_COMMAND_RELEASE} COMMENT "Copying dlls to executable directory...")   
        add_custom_command(TARGET COPY_DLLS PRE_BUILD COMMAND ${CMAKE_COMMAND} ${COPY_COMMAND_DEBUG} COMMENT "Copying dlls to executable directory...")
    endforeach()
endif()

如果您希望每次构建其他目标时都执行此目标,则可以执行以下操作:

foreach(EXECUTABLE ${TARGETS})
    add_dependencies(${EXECUTABLE} COPY_DLLS)
endforeach()

不要担心您还必须将platforms目录从plugins复制到可执行文件文件夹,例如将其添加到复制 dll 目标:

add_custom_command(TARGET COPY_DLLS PRE_BUILD 
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PATH_QT_ROOT}/plugins/platforms ${CMAKE_CURRENT_BINARY_DIR}/Debug/platforms
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PATH_QT_ROOT}/plugins/platforms ${CMAKE_CURRENT_BINARY_DIR}/Release/platforms
    COMMENT "Copying Qt platforms to executable directory...")