فهرست منبع

feat: 添加基础程序

SongZihuan 3 سال پیش
کامیت
e442eb5a49

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+build*
+cmake-*
+.idea

+ 39 - 0
CMakeLists.txt

@@ -0,0 +1,39 @@
+#[[
+CMakeFindExternalProject的测试程序
+目标时通过github访问一个动态库
+并且编译该库
+]]
+cmake_minimum_required(VERSION 3.20)
+project(CMakeFindExternalProjectTest C)
+
+message(STATUS "CMAKE_GENERATOR = ${CMAKE_GENERATOR}")
+
+include(cmake/CMakeFindExternalProject/CMakeFindExternalProject.cmake)
+CFEP_find_git(msgTargets GIT "https://gitee.com/SuperHuan0630/cmake-learn.git" GIT_TAG "main"
+                       EXTERNAL TIMEOUT 60 INSTALL_DIR base)
+CFEP_copy_install(msgTargets)
+
+if (msgTargets_FOUND)
+    # IMPORTED_IMPLIB和IMPORTED_IMPLIB_<CONFIG>属性设定了该导入库的动态库导入文件的路径(例如, windows上的.lib, .dll.a)
+    # <CONFIG>一般是DEBUG, RELEASE等, IMPORTED_IMPLIB一般为IMPORTED_IMPLIB_RELEASE
+    get_target_property(imp message::msg IMPORTED_IMPLIB)
+    get_target_property(imp_debug message::msg IMPORTED_IMPLIB_DEBUG)
+    get_target_property(imp_release message::msg IMPORTED_IMPLIB_RELEASE)
+
+    # IMPORTED_LOCATION和IMPORTED_LOCATION_<CONFIG>属性设定了该导入库的动态库运行时文件的路径(例如, windows上的.dll)
+    get_target_property(loc message::msg IMPORTED_LOCATION)
+    get_target_property(loc_debug message::msg IMPORTED_LOCATION_DEBUG)
+    get_target_property(loc_release message::msg IMPORTED_LOCATION_RELEASE)
+
+    message(STATUS "Import lib: ${imp}")
+    message(STATUS "Location lib: ${loc}")
+
+    message(STATUS "Import debug lib: ${imp_debug}")
+    message(STATUS "Location debug lib: ${loc_debug}")
+
+    message(STATUS "Import release lib: ${imp_release}")
+    message(STATUS "Location release lib: ${loc_release}")
+else()
+    message(STATUS "msgTargets NOT FOUND.")
+    message(STATUS "maybe you should set the cache msgTargets_DIR.")  # <报名>_DIR用于find_package在config模式时在何处寻找.cmake文件
+endif()

+ 24 - 0
README

@@ -0,0 +1,24 @@
+CMakeFindExternalProject CMake配置时安装依赖程序
+============================================
+允许在CMake配置时检查库的存在, 若不存在则构建该库
+目前尚处开发阶段...
+
+导出宏:
+CFEP_find_git 寻找指定Package, 若无则从git下载项目并构建
+CFEP_find_url 寻找指定Package, 若无则从url下载项目并构建
+他们的执行效果相当于find_package
+
+导出函数:
+CFEP_install 依赖库安装的内容会被添加到安装目录
+CFEP_copy_install 拷贝依赖库安装的内容到指定目录
+WI_install_import 为导入库添加安装程序
+WI_copy_import 将导入库的运行时和imp-lib复制到指定目录
+WI_install_dll_bin 检查bin目录中的dll, 并添加install
+
+注意: 其余函数和宏均为内部函数, 不建议直接调用
+
+
+使用当时:
+将cmake文件夹复制到你的项目中
+通过包含代码: include(cmake/CMakeFindExternalProject/init.cmake)
+即可使用

+ 467 - 0
cmake/CMakeFindExternalProject/CMakeFindExternalProject.cmake

@@ -0,0 +1,467 @@
+#[[
+文件名: CMakeFindExternalProject.cmake
+用于定位一个外部项目
+若外部项目不存在则构建该项目
+]]
+
+# 保存 CMAKE_CURRENT_LIST_DIR
+# 因为 CMake 函数是动态作用域的
+set(CMakeFindExternalProject_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "CMAKE_CURRENT_LIST_DIR" FORCE)
+
+macro(_cfep_build_found_inline _found)
+    set(${name}_CFEP_FOUND ${_found} CACHE INTERNAL "${name} found by CMakeFindExternalProject" FORCE)
+    if (${name}_CFEP_FOUND)
+        set(${name}_CFEP_BUILD_DIR ${_build_dir} CACHE INTERNAL "${name} install dirs" FORCE)
+        set(${name}_CFEP_INSTALL ${_install_dir} CACHE INTERNAL "${name} install dirs" FORCE)
+        set(${name}_CFEP_INSTALL_TYPE ${cfp_INSTALL_DIR} CACHE INTERNAL "${name} install dirs type" FORCE)
+    else()
+        set(${name}_CFEP_BUILD_DIR "" CACHE INTERNAL "${name} install dirs" FORCE)
+        set(${name}_CFEP_INSTALL "" CACHE INTERNAL "${name} install dirs" FORCE)
+        set(${name}_CFEP_INSTALL_TYPE "" CACHE INTERNAL "${name} install dirs type" FORCE)
+    endif()
+endmacro()
+
+function(_cfep_build_inline name)
+    set(options NOT_INFO FORCE)
+    set(oneValueArgs
+        BUILD_DIR
+        INSTALL_DIR  # 有三个选择: base, deps, binary
+        TIMEOUT)
+    set(multiValueArgs
+        DOWNLOAD_COMMAND
+        CMAKE_ARGS
+        BUILD_CMAKE_ARGS
+        BUILD_CMAKE_CACHE_ARGS
+        BUILD_CMAKE_CACHE_DEFAULT_ARGS)
+
+    cmake_parse_arguments(cfp
+                          "${options}"
+                          "${oneValueArgs}"
+                          "${multiValueArgs}"
+                          ${ARGN})
+    if (NOT cfp_BUILD_DIR)
+        set(_build_dir "${CMAKE_BINARY_DIR}/deps/${name}")
+    else()
+        set(_build_dir "${CMAKE_BINARY_DIR}/deps/${cfp_BUILD_DIR}")
+    endif()
+
+    set(_force ${cfp_FORCE})
+    if (cfp_NOT_INFO)
+        set(_info false)
+    else()
+        set(_info true)
+    endif()
+
+    set(_cmake_dir ${_build_dir}/cmake.dir)
+    set(_source_dir ${_build_dir}/source)
+    set(_binary_dir ${_build_dir}/binary)
+    set(_timeout ${cfp_TIMEOUT})
+
+    if (cfp_INSTALL_DIR STREQUAL "base")
+        set(_install_dir ${CMAKE_BINARY_DIR}/${name})
+    elseif(cfp_INSTALL_DIR STREQUAL "binary")
+        set(_install_dir ${CMAKE_BINARY_DIR}/${name})
+    else()
+        set(_install_dir ${_build_dir}/install)
+    endif()
+
+    if(NOT _force)
+        if ((${_name}_CFEP_FOUND) AND (EXISTS ${_cmake_dir}))  # 若 _cmake_dir 被删除则重新构建项目
+            return()
+        endif()
+    endif()
+
+    foreach(dir cmake install source binary install)  # 构建目录
+        execute_process(
+                COMMAND "${CMAKE_COMMAND}" -E make_directory "${_${dir}_dir}"
+                RESULT_VARIABLE re)
+        if (re)
+            if (_info)
+                message(WARNING "cmake make directory ${_${dir}_dir} fail(${re})")
+            endif()
+            _cfep_build_found_inline(FALSE)
+            return()
+        endif()
+
+        unset(re)
+        unset(_stderr)
+        unset(_stdout)
+    endforeach()
+
+    set(_download ${cfp_DOWNLOAD_COMMAND})
+
+    set(_cmake_args ${cfp_CMAKE_ARGS})
+    set(_build_cmake_args
+        ${cfp_BUILD_CMAKE_ARGS}
+        "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
+
+    set(_build_cmake_cache
+        ${cfp_BUILD_CMAKE_CACHE_ARGS}
+        \"-DCMAKE_INSTALL_PREFIX:PATH=${_install_dir}\")  # ${_install_dir}不需要分号
+    set(_build_cmake_default_cache ${BUILD_CMAKE_CACHE_DEFAULT_ARGS})
+
+    set(CEFP_CMAKE_VERSION ${CMAKE_VERSION})
+    set(CFEP_NAME ${name})
+    set(SHOW_INFO ${_info})
+
+    set(CEFP_BUILD_PREFIX ${_build_dir})
+    set(CEFP_SOURCE_DIR ${_source_dir})
+    set(CEFP_BINARY_DIR ${_binary_dir})
+    set(CEFP_INSTALL_DIR ${_install_dir})
+
+    set(_CEFP_COMMAND
+        TIMEOUT ${_timeout}
+
+        ${_download}
+
+        CMAKE_COMMAND \"${CMAKE_COMMAND}\"  # "需要转义, 作为字符串的一部分内容
+        CMAKE_GENERATOR \"${CMAKE_GENERATOR}\"
+        CMAKE_GENERATOR_PLATFORM \"${CMAKE_GENERATOR_PLATFORM}\"
+        CMAKE_GENERATOR_TOOLSET \"${CMAKE_GENERATOR_TOOLSET}\"
+        CMAKE_GENERATOR_INSTANCE \"${CMAKE_GENERATOR_INSTANCE}\"
+
+        CMAKE_ARGS ${_build_cmake_args}
+        CMAKE_CACHE_ARGS ${_build_cmake_cache}
+        CMAKE_CACHE_DEFAULT_ARGS ${_build_cmake_default_cache}
+        )
+
+    string(REPLACE ";" " \n" CEFP_COMMAND "${_CEFP_COMMAND}")  # 把;替换为空格
+    unset(_CEFP_COMMAND)
+
+    set(config_file TRUE)  # 生成文件
+    if ((NOT _force) AND (EXISTS ${_cmake_dir}/CMakeLists.txt))  # 非强制模式, 文件已存在
+        if (CFEP_${_cmake_dir}_CMAKE_FILE)  # CFEP_${_cmake_dir}_CMAKE_FILE记录文件的md5值
+            file(MD5 ${_cmake_dir}/CMakeLists.txt _md5)  # 计算md5
+            if (_md5 STREQUAL CFEP_${_cmake_dir}_CMAKE_FILE)
+                set(config_file FALSE)  # 不需要构建文件
+            endif()
+            unset(_md5)
+        endif()
+    endif()
+
+    if (config_file)
+        configure_file(${CMakeFindExternalProject_DIR}/CMakeLists.txt.in
+                       ${_cmake_dir}/CMakeLists.txt
+                       @ONLY)
+        file(MD5 ${_cmake_dir}/CMakeLists.txt _md5)  # 计算md5
+        set(CFEP_${_cmake_dir}_CMAKE_FILE ${_md5} CACHE INTERNAL "md5" FORCE)
+        unset(_md5)
+    endif()
+
+    unset(CEFP_CMAKE_VERSION)
+    unset(CFEP_NAME)
+    unset(SHOW_INFO)
+
+    unset(CEFP_BUILD_PREFIX)
+    unset(CEFP_SOURCE_DIR)
+    unset(CEFP_BINARY_DIR)
+    unset(CEFP_INSTALL_DIR)
+
+    unset(CEFP_COMMAND)
+
+    # 定义项目
+    if (_info)
+        message(STATUS "CMake Config ${name}...(Please Wait)")
+    endif()
+    execute_process(
+                    COMMAND "${CMAKE_COMMAND}" . -B ./build -G ${CMAKE_GENERATOR} ${_cmake_args}
+                    WORKING_DIRECTORY "${_cmake_dir}"
+                    RESULT_VARIABLE re
+                    OUTPUT_VARIABLE _stdout  # stdout的输出内容
+                    ERROR_VARIABLE _stderr  # stderr的输出内容
+                    OUTPUT_STRIP_TRAILING_WHITESPACE
+                    ERROR_STRIP_TRAILING_WHITESPACE
+    )
+
+    if(re)
+        _cfep_build_found_inline(FALSE)
+        if (_info)
+            message(WARNING "CMake config ${name} fail(${re}): \n${_stderr}")
+        endif()
+        return()
+    endif()
+
+    unset(re)
+    unset(_stderr)
+    unset(_stdout)
+
+    # 构建项目
+    if (_info)
+        message(STATUS "CMake Build ${name}...(Please Wait)")
+    endif()
+    execute_process(
+                    COMMAND "${CMAKE_COMMAND}" --build .
+                    WORKING_DIRECTORY "${_cmake_dir}/build"
+                    RESULT_VARIABLE re
+                    OUTPUT_VARIABLE _stdout  # stdout的输出内容
+                    ERROR_VARIABLE _stderr  # stderr的输出内容
+                    OUTPUT_STRIP_TRAILING_WHITESPACE
+                    ERROR_STRIP_TRAILING_WHITESPACE
+    )
+
+    if(re)
+        _cfep_build_found_inline(FALSE)
+        if (_info)
+            message(WARNING "CMake build ${name} fail(${re}): \n${_stderr}")
+        endif()
+        return()
+    endif()
+
+    unset(re)
+    unset(_stderr)
+    unset(_stdout)
+    _cfep_build_found_inline(TRUE)
+endfunction()
+
+# 从url下载程序
+function(_cfep_build_url_inline name url)
+    _cfep_build_inline(${name} DOWNLOAD_COMMAND URL ${url} ${ARGN})
+    if (${name}_CFEP_FOUND)
+        set(${name}_BUILD TRUE PARENT_SCOPE)
+    else()
+        set(${name}_BUILD FALSE PARENT_SCOPE)
+    endif()
+endfunction()
+
+# 从git下载程序
+function(_cfep_build_git_inline name git git_tag)
+    _cfep_build_inline(${name}
+                 DOWNLOAD_COMMAND
+                 GIT_REPOSITORY ${git}
+                 GIT_TAG ${git_tag}
+                 GIT_PROGRESS 0
+                 GIT_REMOTE_UPDATE_STRATEGY REBASE_CHECKOUT
+                 ${ARGN})
+    if (${name}_CFEP_FOUND)
+        set(${name}_BUILD TRUE PARENT_SCOPE)
+    else()
+        set(${name}_BUILD FALSE PARENT_SCOPE)
+    endif()
+endfunction()
+
+macro(_cfep_found_inline _found)
+    set(__found ${_found})
+    if (NOT ${__found})
+        set(${_name}_FOUND ${_name}-NOTFOUND)
+        if (_required)
+            message(FATAL_ERROR "Package not found: ${_name}")
+        endif()
+        if (NOT _quiet)
+            message(WARNING "Package not found: ${_name}")
+        endif()
+    endif()
+    unset(__found)
+endmacro()
+
+# 从url下载文件
+macro(CFEP_find_url name)
+    while (1)  # 宏无法处理return, 所以使用while+break来模拟return
+        set(options REQUIRED QUIET)
+        set(oneValueArgs URL CMAKE_DIR)
+        set(multiValueArgs
+            PACKAGE
+            EXTERNAL)
+
+        cmake_parse_arguments(cfpu
+                              "${options}"
+                              "${oneValueArgs}"
+                              "${multiValueArgs}"
+                              ${ARGN})
+
+        set(_name ${name})
+        set(_url ${cfpu_URL})
+        set(_cmake ${cfpu_CMAKE_DIR})
+        set(_find_args ${cfpu_PACKAGE})
+        set(_external_args ${cfpu_EXTERNAL})
+        set(_required ${cfpu_REQUIRED})
+        set(_quiet ${cfpu_QUIET})
+
+        if (NOT _url)
+            _cfep_found_inline(FALSE)
+            break()
+        endif()
+
+        if (NOT ${name}_MUST_BUILD)  # 必须构建, 则先不尝试搜索库
+            find_package(${name} QUIET ${_find_args})  # 尝试搜索
+            if (${name}_FOUND)
+                _cfep_found_inline(TRUE)
+                break()
+            endif()
+        else()
+            set(${name}_MUST_BUILD FALSE CACHE BOOL "" FORCE)
+        endif()
+
+        _cfep_build_url_inline(${name} ${_url} ${_external_args})  # 尝试构建
+        if (NOT ${name}_BUILD)  # 未构建
+            _cfep_found_inline(FALSE)
+            break()
+        endif()
+
+        if (_cmake)
+            set(${name}_DIR "${${name}_CFEP_INSTALL}/${_cmake}" CACHE PATH "" FORCE)
+        elseif(WIN32 AND NOT CYGWIN)
+            set(${name}_DIR "${${name}_CFEP_INSTALL}/cmake" CACHE PATH "" FORCE)
+        else()
+            set(${name}_DIR "${${name}_CFEP_INSTALL}/share/cmake/${name}" CACHE PATH "" FORCE)
+        endif()
+
+        find_package(${name} QUIET ${_find_args})  # 最后搜索
+        if (${name}_FOUND)
+            _cfep_found_inline(TRUE)
+            break()
+        endif()
+        _cfep_found_inline(FALSE)
+        break()
+    endwhile()
+
+    unset(_name)
+
+    unset(_url)
+    unset(_cmake)
+    unset(_find_args)
+    unset(_external_args)
+    unset(_required)
+    unset(_quiet)
+
+    unset(cfpu_URL)
+    unset(cfpu_CMAKE_DIR)
+    unset(cfpu_PACKAGE)
+    unset(cfpu_EXTERNAL)
+    unset(cfpu_REQUIRED)
+    unset(cfpu_QUIET)
+endmacro()
+
+# 从git下载文件
+macro(CFEP_find_git name)
+    while (1)  # 宏无法处理return, 所以使用while+break来模拟return
+        set(options REQUIRED QUIET)
+        set(oneValueArgs GIT GIT_TAG CMAKE_DIR)
+        set(multiValueArgs
+            PACKAGE
+            EXTERNAL)
+
+        cmake_parse_arguments(cfpu
+                              "${options}"
+                              "${oneValueArgs}"
+                              "${multiValueArgs}"
+                              ${ARGN})
+
+        set(_name ${name})
+        set(_git ${cfpu_GIT})
+        set(_git_tag ${cfpu_GIT_TAG})
+        set(_cmake ${cfpu_CMAKE_DIR})
+        set(_find_args ${cfpu_PACKAGE})
+        set(_external_args ${cfpu_EXTERNAL})
+        set(_required ${cfpu_REQUIRED})
+        set(_quiet ${cfpu_QUIET})
+
+        if ((NOT _git) OR (NOT _git_tag))
+            _cfep_found_inline(FALSE)
+            break()
+        endif()
+
+        if (NOT ${name}_MUST_BUILD)  # 必须构建, 则先不尝试搜索库
+            find_package(${name} QUIET ${_find_args})  # 尝试搜索
+            if (${name}_FOUND)
+                _cfep_found_inline(TRUE)
+                break()
+            endif()
+        else()
+            set(${name}_MUST_BUILD FALSE CACHE BOOL "" FORCE)
+        endif()
+
+        _cfep_build_git_inline(${name} ${_git} ${_git_tag} ${_external_args})  # 尝试构建
+        if (NOT ${name}_BUILD)  # 未构建
+            _cfep_found_inline(FALSE)
+            break()
+        endif()
+
+        if (_cmake)
+            set(${name}_DIR "${${name}_CFEP_INSTALL}/${_cmake}" CACHE PATH "" FORCE)
+        elseif(WIN32 AND NOT CYGWIN)
+            set(${name}_DIR "${${name}_CFEP_INSTALL}/cmake" CACHE PATH "" FORCE)
+        else()
+            set(${name}_DIR "${${name}_CFEP_INSTALL}/share/cmake/${name}" CACHE PATH "" FORCE)
+        endif()
+
+        find_package(${name} QUIET ${_find_args})  # 最后搜索
+        if (${name}_FOUND)
+            _cfep_found_inline(TRUE)
+            break()
+        endif()
+        _cfep_found_inline(FALSE)
+        break()
+    endwhile()
+
+    unset(_name)
+
+    unset(_git)
+    unset(_git_tag)
+    unset(_cmake)
+    unset(_find_args)
+    unset(_external_args)
+    unset(_required)
+    unset(_quiet)
+
+    unset(cfpu_GIT)
+    unset(cfpu_GIT_TAG)
+    unset(cfpu_CMAKE_DIR)
+    unset(cfpu_PACKAGE)
+    unset(cfpu_EXTERNAL)
+    unset(cfpu_REQUIRED)
+    unset(cfpu_QUIET)
+endmacro()
+
+function(CFEP_install name)
+    cmake_parse_arguments(ci "NOT_QUIET" "PREFIX" "" ${ARGN})
+
+    if (NOT ci_PREFIX)
+        set(prefix ${CMAKE_INSTALL_PREFIX})
+    else()
+        set(prefix ${ci_PREFIX})
+    endif()
+
+    if (NOT ${name}_CFEP_FOUND)
+        if (ci_NOT_QUIET)
+            message(WARNING "Cannot install ${name}.")
+        endif()
+        set(${name}_CFEP_INSTALL_SUCCESS FALSE PARENT_SCOPE)
+        return()
+    endif()
+
+    if (NOT prefix)
+        set(prefix ${CMAKE_INSTALL_PREFIX})
+    endif()
+
+    install(DIRECTORY ${${name}_CFEP_INSTALL}
+            DESTINATION ${prefix}
+            USE_SOURCE_PERMISSIONS)
+    set(${name}_CFEP_INSTALL_SUCCESS TRUE PARENT_SCOPE)
+endfunction()
+
+function(CFEP_copy_install name)
+    cmake_parse_arguments(cci "NOT_QUIET" "DEST" "" ${ARGN})
+
+    if (NOT cci_DEST)
+        set(dest ${CMAKE_BINARY_DIR})
+    else()
+        set(dest ${cci_DEST})
+    endif()
+
+    if (NOT ${name}_CFEP_FOUND)
+        if (cci_NOT_QUIET)
+            message(WARNING "Cannot copy install ${name}.")
+        endif()
+        set(${name}_CFEP_COPY_SUCCESS FALSE PARENT_SCOPE)
+        return()
+    endif()
+
+    execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_directory ${${name}_CFEP_INSTALL} ${dest}
+                    RESULT_VARIABLE re)
+    if(re)
+        if (cci_NOT_QUIET)
+            message(WARNING "Cannot copy install ${name}.")
+        endif()
+        set(${name}_CFEP_COPY_SUCCESS TRUE PARENT_SCOPE)
+    endif()
+endfunction()

+ 32 - 0
cmake/CMakeFindExternalProject/CMakeLists.txt.in

@@ -0,0 +1,32 @@
+#[[
+文件名: CMakeLists.txt
+由CMakeFindExternalProject自动生成的CMakeLists.txt文件
+]]
+
+cmake_minimum_required(VERSION @CEFP_CMAKE_VERSION@)
+project(CFEP_@CFEP_NAME@)
+
+if(@SHOW_INFO@)
+    message(STATUS "CMakeFindExternalProject: Build @CFEP_NAME@ in cmake.")
+endif()
+
+include(ExternalProject)
+ExternalProject_Add(
+@CFEP_NAME@_cefp
+PREFIX "@CEFP_BUILD_PREFIX@"
+DOWNLOAD_DIR "@CEFP_BUILD_PREFIX@/download"
+SOURCE_DIR "@CEFP_SOURCE_DIR@"
+BINARY_DIR "@CEFP_BINARY_DIR@"
+INSTALL_DIR "@CEFP_INSTALL_DIR@"
+STAMP_DIR "@CEFP_BUILD_PREFIX@/stamp"
+LOG_DIR "@CEFP_BUILD_PREFIX@/log"
+TMP_DIR "@CEFP_BUILD_PREFIX@/tmp"
+
+@CEFP_COMMAND@
+
+DOWNLOAD_NO_PROGRESS 0
+BUILD_ALWAYS 1
+LOG_DOWNLOAD 1
+LOG_CONFIGURE 1
+LOG_BUILD 1
+LOG_INSTALL 1)

+ 144 - 0
cmake/CMakeFindExternalProject/WindowsInstall.cmake

@@ -0,0 +1,144 @@
+#[[
+文件名: WindowsInstall.cmake
+windows下安装程序
+因为windows需要复制动态库到指定位置, 因此需要特殊的安装程序
+]]
+
+# 找到导入库的.dll和.lib并添加install
+function(_wi_install_import_inline target run lib)
+    if(WIN32)  # 只有windows需要执行该操作
+        if (CMAKE_BUILD_TYPE)
+            string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type)
+        else()
+            set(_build_type DEBUG)
+        endif()
+
+        get_target_property(imp ${target} IMPORTED_IMPLIB)
+        get_target_property(imp_t ${target} IMPORTED_IMPLIB_${_build_type})
+
+        get_target_property(loc target IMPORTED_LOCATION)
+        get_target_property(loc_t target IMPORTED_LOCATION_${_build_type})
+
+        if(lib)
+            if (imp OR imp_t)
+                install(FILE ${imp} ${imp_t} DESTINATION ${lib})
+            endif()
+        endif()
+
+        if(run)
+            if (loc OR loc_t)
+                install(FILE ${loc} ${loc_t} DESTINATION ${run})
+            endif()
+        endif()
+    endif()
+endfunction()
+
+function(WI_install_import)
+    cmake_parse_arguments(ii "" "RUNTIME;LIBRARY" "TARGETS" ${ARGN})
+    if (NOT ii_RUNTIME)
+        if (INSTALL_BINDIR)
+            set(runtime ${INSTALL_BINDIR})
+        else()
+            set(runtime ${CMAKE_INSTALL_BINDIR})
+        endif()
+    else()
+        set(runtime ${ii_RUNTIME})
+    endif()
+
+    if (NOT ii_LIBRARY)
+        if (INSTALL_LIBRARY)
+            set(library ${INSTALL_LIBRARY})
+        else()
+            set(library ${CMAKE_INSTALL_LIBDIR})
+        endif()
+    else()
+        set(library ${ii_LIBRARY})
+    endif()
+
+    set(targets ${ii_TARGETS})
+    foreach(tgt IN LISTS targets)
+        _wi_install_import_inline(tgt runtime library)
+    endforeach()
+endfunction()
+
+# 找到导入库的.dll和.lib并复制到指定的目录
+function(_wi_copy_import_inline target run lib)
+    if(WIN32)  # 只有windows需要执行该操作
+        if (CMAKE_BUILD_TYPE)
+            string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type)
+        else()
+            set(_build_type DEBUG)
+        endif()
+
+        get_target_property(imp ${target} IMPORTED_IMPLIB)
+        get_target_property(imp_t ${target} IMPORTED_IMPLIB_${_build_type})
+
+        get_target_property(loc target IMPORTED_LOCATION)
+        get_target_property(loc_t target IMPORTED_LOCATION_${_build_type})
+
+        if(lib)
+            if (imp OR imp_t)
+                file(COPY ${imp} ${imp_t} DESTINATION ${lib} USE_SOURCE_PERMISSIONS)
+            endif()
+        endif()
+
+        if(run)
+            if (loc OR loc_t)
+                file(COPY ${loc} ${loc_t} DESTINATION ${run} USE_SOURCE_PERMISSIONS)
+            endif()
+        endif()
+    endif()
+endfunction()
+
+function(WI_copy_import)
+    cmake_parse_arguments(ii "" "RUNTIME;LIBRARY" "TARGETS" ${ARGN})
+    if (NOT ii_RUNTIME)
+        if (INSTALL_BINDIR)
+            set(runtime ${INSTALL_BINDIR})
+        else()
+            set(runtime ${CMAKE_INSTALL_BINDIR})
+        endif()
+    else()
+        set(runtime ${ii_RUNTIME})
+    endif()
+
+    if (NOT ii_LIBRARY)
+        if (INSTALL_LIBRARY)
+            set(library ${INSTALL_LIBRARY})
+        else()
+            set(library ${CMAKE_INSTALL_LIBDIR})
+        endif()
+    else()
+        set(library ${ii_LIBRARY})
+    endif()
+
+    set(targets ${ii_TARGETS})
+    foreach(tgt IN LISTS targets)
+        _wi_copy_import_inline(tgt runtime library)
+    endforeach()
+endfunction()
+
+# 安装install的bin目录(检查.dll并复制到指定位置)
+function(WI_install_dll_bin)
+    if(WIN32)
+        cmake_parse_arguments(ii "" "RUNTIME" "DIRS" ${ARGN})
+        if (NOT ii_RUNTIME)
+            if (INSTALL_BINDIR)
+                set(runtime ${INSTALL_BINDIR})
+            else()
+                set(runtime ${CMAKE_INSTALL_BINDIR})
+            endif()
+        else()
+            set(runtime ${ii_RUNTIME})
+        endif()
+
+        set(dirs ${ii_DIRS})
+        foreach(dir IN LISTS dirs)
+            file(GLOB_RECURSE _dll  # 遍历所有的.dll
+                 LIST_DIRECTORIES FALSE  #
+                 CONFIGURE_DEPENDS
+                 "${dirs}/*.dll")
+            install(FILES ${_dll} DESTINATION ${RUNTIME})
+        endforeach()
+    endif()
+endfunction()

+ 2 - 0
cmake/CMakeFindExternalProject/init.cmake

@@ -0,0 +1,2 @@
+include(CMakeFindExternalProject.cmake)
+include(WindowsInstall.cmake)