CMake和FIND_PACKAGE

时间:2019-07-16 12:05:15

标签: c++ cmake

确保cmake仅从特定根目录中查找库和标头的最佳方法是什么。

假设:

  • 我们只想查看特定目录(例如:/ mysdkroot /)
  • 我们要忽略不在特定目录中的所有文件(例如,不应使用/ usr / lib或/ usr / include,而应仅使用/ mysdkroot /)
  • 使用库提供的find_package()功能,而不是在cmake上查找文件或标头的特定内容
  • 我们不编辑库制造商提供的FindXXX.cmake或xxxConfig.cmake
  • 重要的是,我不想编辑每个查找包/文件/ lib调用,都指定要搜索的路径

我可以使用NO_DEFAULT_PATH并指定查找路径来完成一半的工作,但是我对此没有完整的解决方案,因为我始终依赖于FindXXX.cmake或xxxConfig.cmake的实现方式。例如,如果调试/发布文件具有不同的名称,例如,在我的/ mysdkroot /中,我仅具有调试文件,并且在系统中仅存在发布,则对于某些库,它可能会首先找到该发布,而不是首先找到调试,这是因为我无法将搜索范围缩小到该文件夹​​。

2 个答案:

答案 0 :(得分:3)

NO_DEFAULT_PATH是一个好的开始。但是,我将启用一种查找软件包的方法,那就是使用CMAKE_PREFIX_PATH

NO_PACKAGE_ROOT_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_PACKAGE_REGISTRY
NO_CMAKE_SYSTEM_PATH
NO_CMAKE_SYSTEM_PACKAGE_REGISTRY

这会禁用它们,除了CMAKE_PREFIX_PATH中指定的路径。

然后将您的前缀路径设置为sdk:

set(CMAKE_PREFIX_PATH "/mysdkroot")

然后,实际上,您仍然取决于如何实现这些findXXX.cmake和那些XXX-config.cmake。幸运的是,您可以使用命令多态性完全改变其行为:

set(current-find-package "")

function(find_package)
    set(current-find-package "${ARGV1}")
    # The leading underscore mean the original command
    _find_package(${ARGV})
endfunction()

# function usually used in findXX.cmake modules
function(find_library)
    if("${current-find-package}" STREQUAL "SomePakage")
        # TODO: remove unwanted paths in ARGV
        _find_library(${ARGV} NO_DEFAULT_PATH)
    endif()
endfunction()

尽管这可以解决问题,但我建议不要滥用,或者要非常小心使用它。您不想引入令人惊讶的行为。


您主要关注的是XX-config.cmakefindXX.cmake试图在您的SDK路径之外查找库。

首先,XX-config.cmake通常行为正确。如果找到XX-config.cmake,它将不会尝试在路径之外查找库。它已经知道在哪里可以找到那些库。

然后,FindXX.cmake的行为可能不正确,因为它们主要是在不同的cmake时代手写的。

我的建议是替换行为不理想的模块。只需提供自己的自定义FindXX.cmake模块即可正常运行。如果维护者提供的服务没有按照您的意愿进行,请不要使用它们,只需提供您自己的服务即可。

答案 1 :(得分:1)

  

确保cmake仅从特定的根目录中查找库和标头。

取决于“根目录”是真正的“根”的方式,您可以尝试将CMAKE_FIND_ROOT_PATH变量设置为该目录:

set(CMAKE_FIND_ROOT_PATH "/mysdkroot")

伴随将CMAKE_FIND_ROOT_PATH_MODE_*变量设置为ONLY,您可以强制相应的find_*命令仅在给定目录下搜索:

# 'find_path' will search only under CMAKE_FIND_ROOT_PATH.
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE "ONLY") 
# 'find_library' will search only under CMAKE_FIND_ROOT_PATH.
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY "ONLY")
# 'find_package' will search 'XXXConfig.cmake' (not 'FindXXX.cmake'!) only under CMAKE_FIND_ROOT_PATH.
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "ONLY")

此方法的局限性在于CMake将CMAKE_FIND_ROOT_PATH目录解释为文件系统根目录,而不是安装前缀。也就是说,CMake假定(在Linux环境上)库位于/mysdkroot/usr/lib下,标头位于/mysdkroot/usr/include下。

您可以结合使用CMAKE_FIND_ROOT_PATHCMAKE_PREFIX_PATH设置来向CMake告知安装目录

set(CMAKE_FIND_ROOT_PATH /mysdk)
set(CMAKE_PREFIX_PATH /root) # Not sure whether setting prefix to `/` would work.

具有与

相似的效果
set(CMAKE_PREFIX_PATH /mysdk/root)

但是,如果CMake在给定的前缀下找不到某些内容,那么它将不会搜索/usr/include(将CMAKE_FIND_ROOT_PATH_MODE_INCLUDE设置为ONLY)。 相反,它将尝试/mysdk/usr/include。而且,如果您的系统上没有给定的目录,则在该目录下找不到任何内容。


请注意,不能确定100%CMake所找到的内容都不会位于特定根目录之外。您可能希望FindXXX.cmake以“正常”的方式编写,该方式使用find_*命令,但是没有什么可以阻止这些脚本的编写方式不同。