*Config.cmake或Find*.cmake的编写

发布时间 2023-10-13 15:29:01作者: 非法关键字

当使用vcpkg安装detours时,如果find_package未能找到它,这通常意味着这个库可能没有提供CMake的配置文件(*Config.cmakeFind*.cmake)。vcpkg通常会提供这些文件,但不是所有库都会这么做。

在这种情况下,您有以下几种选择:

  1. 手动指定库和头文件的路径

    在您的CMakeLists.txt中,您可以直接指定头文件和库文件的路径。

    include_directories("${VCPKG_ROOT}/installed/x64-windows-static/include")
    link_directories("${VCPKG_ROOT}/installed/x64-windows-static/lib")
    
    add_executable(MyTarget your_source_files_here)
    target_link_libraries(MyTarget detours)
    

    在这里,VCPKG_ROOT是您的vcpkg安装路径。

  2. 编写自己的FindDetours.cmake

    如果你喜欢find_package的标准化方式,你可以编写一个自定义的FindDetours.cmake文件,并把它放在你的项目中,然后用list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/your/path/to")来添加到CMAKE_MODULE_PATH

编写自己的FindDetours.cmake

# 设置库的名称
set(DETOURS_LIBRARY_NAME detours)

# 尝试查找库文件
find_library(DETOURS_LIBRARY
    NAMES ${DETOURS_LIBRARY_NAME}
    PATHS ${VCPKG_ROOT}/installed/x64-windows-static/lib
    NO_DEFAULT_PATH
)

# 尝试查找头文件
find_path(DETOURS_INCLUDE_DIR
    NAMES detours.h
    PATHS ${VCPKG_ROOT}/installed/x64-windows-static/include
    NO_DEFAULT_PATH
)

# 确定是否找到了库和头文件
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Detours
    DEFAULT_MSG
    DETOURS_LIBRARY DETOURS_INCLUDE_DIR
)

# 设置导入的目标
if(DETOURS_FOUND AND NOT TARGET Detours::Detours)
    add_library(Detours::Detours STATIC IMPORTED)
    set_target_properties(Detours::Detours PROPERTIES
        IMPORTED_LOCATION ${DETOURS_LIBRARY}
        INTERFACE_INCLUDE_DIRECTORIES ${DETOURS_INCLUDE_DIR}
    )
endif()

1. 目录的结构树如下

├── CMakeLists.txt
├── CMakeModules
│ └── FindDetours.cmake
├── DetoureTerminateProcess.cpp
└── DetoureTerminateProcess.h

2. CMakeLists.txt的内容如下

# CMakeList.txt: DetoureTerminateProcess 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#

# 将源代码添加到此项目的可执行文件。
# add_executable (DetoureTerminateProcess "DetoureTerminateProcess.cpp" "DetoureTerminateProcess.h")
add_library (DetoureTerminateProcess SHARED "DetoureTerminateProcess.cpp" "DetoureTerminateProcess.h")

if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET DetoureTerminateProcess PROPERTY CXX_STANDARD 20)
endif()

set(VCPKG_ROOT "D:/vcpkg")

# TODO: 如有需要,请添加测试并安装目标。
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
find_package(Detours REQUIRED)

target_link_libraries(DetoureTerminateProcess
 PRIVATE
 Detours::Detours
)

3. 对于FindDetours.cmake的解释

确定库文件:

根据CMAKE_BUILD_TYPE来动态选择debug或release版本的库。

if (CMAKE_BUILD_TYPE MATCHES Debug)
 	find_library(DETOURS_LIBRARY
 		NAMES ${DETOURS_LIBRARY_NAME}
 		PATHS ${VCPKG_ROOT}/installed/x64-windows-static/debug/lib
 		NO_DEFAULT_PATH
 	)
else()
    find_library(DETOURS_LIBRARY
        NAMES ${DETOURS_LIBRARY_NAME}
        PATHS ${VCPKG_ROOT}/installed/x64-windows-static/lib
        NO_DEFAULT_PATH
    )
endif()
确定头文件:

对于头文件通常不需要区分DebugRelease,因为它们通常都是相同的。

find_path(DETOURS_INCLUDE_DIR
     NAMES detours.h detver.h
     PATHS ${VCPKG_ROOT}/installed/x64-windows-static/include/detours
     NO_DEFAULT_PATH
)

对于find_library、find_path中NO_DEFAULT_PATH的理解:

NO_DEFAULT_PATHfind_libraryfind_path 以及其他一些 find_* CMake命令中的一个选项。当你使用这个选项,CMake会修改其默认的查找行为。

通常,当你使用例如 find_libraryfind_path 这类的命令时,CMake会在一系列预定义的路径中查找所需的文件或库。这些预定义的路径包括例如 /usr/lib/usr/local/lib 这样的系统目录,也包括一些CMake特定的路径。

但是,有时你可能只想在你明确指定的路径中查找某些东西,而不希望CMake在其他任何地方查找。这就是NO_DEFAULT_PATH选项的用处。当你使用这个选项时,CMake只会在你明确指定的PATHSHINTS参数中提供的路径中查找,而不会去任何其他默认的查找路径。

所以,理解 NO_DEFAULT_PATH 的关键是:它让你能够更精确地控制CMake的查找行为,确保只在你明确提供的路径中查找,而不是在其他任何默认路径中。这在某些情况下是很有用的,特别是当你不希望找到系统中的其他版本,或者当你知道所需的东西在一个非常特定的位置时。

确定是否找到库和头文件:
include(FindPackageHandleStandardArgs)
 	find_package_handle_standard_args(Detours
     DEFAULT_MSG
     DETOURS_LIBRARY DETOURS_INCLUDE_DIR
 )

include(FindPackageHandleStandardArgs) 是 CMake 中的一个指令,用于包含 FindPackageHandleStandardArgs.cmake 模块。这个模块提供了一个宏/函数,用于统一处理 find_package 的标准参数和结果。

让我们详细解释一下:

  1. include(FileName):

    这是一个 CMake 命令,用于包含并执行指定的 CMake 脚本文件。此命令会查找 FileName 并执行其中的命令。

  2. FindPackageHandleStandardArgs.cmake:

    • 这是 CMake 自带的模块,提供了一个名为 find_package_handle_standard_args() 的宏/函数。
    • 此函数主要用于处理 find_package 命令的结果,并生成适当的成功/失败消息。
    • 它可以检查是否找到了所有必需的组件,并自动生成适当的 Found 变量(如 DETOURS_FOUND)。
    • 它还提供了一种标准的方式来生成有关哪些组件找到或未找到的消息。

    使用此模块的好处是为了确保所有的 find_package 命令在查找库和头文件时都有一致的行为和输出。

    在你给出的代码中,你可以看到 find_package_handle_standard_args 的实际使用:

    find_package_handle_standard_args(Detours
        DEFAULT_MSG
        DETOURS_LIBRARY DETOURS_INCLUDE_DIR
     )
    

    这里,函数检查 DETOURS_LIBRARYDETOURS_INCLUDE_DIR 是否已被设置(意味着它们已被找到)。如果都被设置了,它会自动设置 DETOURS_FOUNDTRUE。如果任何一个没有被设置,它会打印一个标准的错误消息,告诉你哪个组件没有被找到。

    设置导入目标:
if (DETOURS_FOUND AND NOT TARGET Detours::Detours)
   add_library(Detours::Detours STATIC IMPORTED)
   set_target_properties(Detours::Detours PROPERTIES
   	IMPORTED_LOCATION ${DETOURS_LIBRARY}
   	INTERFACE_INCLUDE_DIRECTORIES ${DETOURS_INCLUDE_DIR}
   )
endif()

这段代码是使用set_target_properties命令为Detours::Detours目标设置一些属性。在CMake中,目标可以是可执行文件、库或其他一些构建产物。这些属性告诉CMake如何处理这个目标。让我们逐行解释这段代码:

  1. set_target_properties(Detours::Detours PROPERTIES:这是设置Detours::Detours目标属性的开始。PROPERTIES关键字后面列出的是您要设置的属性名及其对应的值。
  2. IMPORTED_LOCATION ${DETOURS_LIBRARY}:这是设置导入库的物理位置。当这是一个导入的目标时(例如,它不是由当前项目构建的,而是已经存在的库),这个属性告诉CMake库文件在文件系统上的位置。${DETOURS_LIBRARY}是之前通过find_library查找到的库文件的完整路径。
  3. INTERFACE_INCLUDE_DIRECTORIES ${DETOURS_INCLUDE_DIR}:这指定了当其他目标链接到Detours::Detours时,它们需要的头文件的位置。这意味着,当您链接到这个库时,这些目录将被添加到编译器的包含路径中,以便可以找到库的头文件。${DETOURS_INCLUDE_DIR}是之前通过find_path查找到的头文件目录。

这段代码的目的是为Detours::Detours目标设置其库文件的位置和头文件的位置。这样,当其他目标在项目中链接到Detours::Detours时,CMake将知道如何找到库和头文件,并将它们包含在构建过程中。