【问题标题】:CMake and FIND_PACKAGECMake 和 FIND_PACKAGE
【发布时间】:2019-07-16 12:05:15
【问题描述】:

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

假设:

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

我可以使用 NO_DEFAULT_PATH 完成一半并指定查找路径,但我无法对此提供完整的证明解决方案,因为我总是依赖于 FindXXX.cmake 或 xxxConfig.cmake 的实现方式。例如,如果调试/发布文件具有不同的名称,例如在我的 /mysdkroot/ 中,我只有调试文件并且在系统中只存在发布,那么对于某些库,它可能会首先找到发布,而不是首先找到调试和其他问题,因为我无法将搜索范围缩小到仅该文件夹。

【问题讨论】:

  • 您是否尝试将CMAKE_PREFIX_PATH 设置为您的sdk 根目录并禁用所有其他find_package 搜索提示? cmake doc 提供跳过某些位置的所有参数。
  • 是的,我忘了提到 CMAKE_PREFIX_PATH,这是所有这些工作的基础,正如 Guillaume 所提到的,带有 find_xxx 标志的我们获得了我们想要的,但这需要做很多工作获得一个应该是 cmake 原生的功能

标签: c++ cmake


【解决方案1】:

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 模块。如果维护者提供的不符合您的要求,请不要使用它们,只需提供您自己的即可。

【讨论】:

  • 这是一个解决方案,而且确实可行,如果我们覆盖所有 find_xxx 功能并使用您提到的标志更改查找行为,那么我们将获得所需的行为......但这太多了努力做一件应该是cmake原生的事情......这是我的观点。感谢纪尧姆的贡献。
  • @Nuno 阅读您的问题,您所要求的存在一个根本问题:您不想依赖这些库实现的破坏行为,但您不想改变它们行为并依赖他们。选择一个。
  • 我想依赖他们,我不想编辑他们的脚本......这就是我的意思。请记住,如果您将正确提及的所有标志都放在 find_package(...) 函数上,这不会影响目标库在其查找脚本中可能具有的几个 find_xxx() 函数,因此正确处理问题的唯一方法是你的建议,覆盖 find_xxx() 函数
  • @Nuno 如果您认为他们没有按照您的意愿行事,为什么还要依赖他们?另外,问题出在 Find 模块上,而不是 config 模块上。
  • 是的,你是完全正确的,我完全同意你的附加说明,但有时这个 FindXXX 脚本是你唯一拥有的东西,实施它们很痛苦......我可以给你一个例如,protobuf 和 JPEG 库是我记得的两个给我带来问题的库,因为它们没有正确实现查找功能
【解决方案2】:

确保 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_* 命令,但没有什么能阻止这些脚本以不同方式编写。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    • 2016-02-02
    • 1970-01-01
    • 2016-01-19
    • 1970-01-01
    • 2018-02-06
    相关资源
    最近更新 更多