【问题标题】:CMake find_package() search paths when cross compiling on windows在 Windows 上交叉编译时 CMake find_package() 搜索路径
【发布时间】:2019-07-30 00:15:09
【问题描述】:

我正在尝试使用 cmake 在 windows 上与 arm-none-eabi-gcc 进行交叉编译,并且由于某种原因 find_package() 正在搜索我的 $PATH 中所有目录的版本,而 不是 CMAKE_FIND_ROOT_PATH 我在工具链文件中提供。具体来说,在工具链文件中,我有以下几行:

SET(CMAKE_INSTALL_PREFIX "C:/toolchains/cm0p_root" CACHE PATH "Cmake install prefix")
set(CMAKE_FIND_ROOT_PATH ${CMAKE_INSTALL_PREFIX})
...
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

我使用相同的工具链编译并安装了我的库,并且所有内容都正确安装到 cmp0_root 目录。

我的项目 CMakeLists.txt 文件中有这个:

find_package(myLIB REQUIRED)
target_link_libraries(testProject PUBLIC myLIB::myLIB)

并且 find_package() 找不到库。如果我将两个版本中的任何一个与 HINTS 或 PATHS 一起放置,它就会成功

find_package(myLIB REQUIRED HINTS /)
find_package(myLIB REQUIRED PATHS "C:/toolchains/cm0p_root")

并使用命令行选项-D CMAKE_FIND_DEBUG_MODE=ON 我可以看到它正在搜索以下路径:

Checking prefix [C:/toolchains/cm0p_root/git-sdk-64/mingw64/]
Checking prefix [C:/toolchains/cm0p_root/Users/myname/]
Checking prefix [C:/toolchains/cm0p_root/Program Files/ConEmu/]
Checking prefix [C:/toolchains/cm0p_root/Python/Python36-32/]
Checking prefix [C:/toolchains/cm0p_root/Python/Python36-32/Scripts/]
Checking prefix [C:/toolchains/cm0p_root/Windows/]
Checking prefix [C:/toolchains/cm0p_root/LLVM/]
Checking prefix [C:/toolchains/cm0p_root/Program Files (x86)/IAR Systems/Embedded Workbench 8.0/common/]
Checking prefix [C:/toolchains/cm0p_root/Program Files (x86)/IAR Systems/Embedded Workbench 8.0/avr/]
Checking prefix [C:/toolchains/cm0p_root/Program Files (x86)/IAR Systems/Embedded Workbench 8.2/arm/]
Checking prefix [C:/toolchains/cm0p_root/Program Files (x86)/MSBuild/12.0/Bin/]

还有更多,但很明显 CMake 将 FIND_ROOT_PATH 前缀到我所有 Windows $PATH 变量的开头!该列表更长,但它从不搜索C:/toolchains/cm0p_root/,这是我需要的(我猜为什么提示有效)。

如何让 CMake 不搜索所有这些目录?我正在交叉编译,据我所知,它应该只搜索我的“假”根目录,因为CMAKE_FIND_ROOT_PATH_MODE_PACKAGE 设置为ONLY

【问题讨论】:

  • 变量 CMAKE_FIND_ROOT_PATH 表示 root 目录用于搜索,但实际的 prefixes 是通过 appending 到根目录 some子目录。您可以在find_package documentation 中找到计算前缀的算法。默认情况下,CMake 不会在 / 子目录下搜索,因此 CMake 不会将您的根目录解释为搜索前缀。您将/ 添加到变量CMAKE_PREFIX_PATH,因此您的root 路径也将被视为前缀
  • 我混淆了 CMAKE_FIND_ROOT_PATH,认为根路径被用作文档中搜索路径的前缀。在您发表评论后重新阅读它会更有意义。所以更好的工具链 sn-p 会添加以下行:set(CMAKE_SYSTEM_PREFIX_PATH /)?我使用了CMAKE_SYSTEM_PREFIX_PATH,因为它似乎更适合工具链文件,文档说应该在项目中设置CMAKE_PREFIX_PATH
  • 嗯,我不确定变量 CMAKE_SYSTEM_PREFIX_PATH 的预期用途是什么,但根据它的文档,它看起来就像是一个工具链。顺便说一句,您为什么将程序完全安装到根目录中?就像你在C:/ 中安装了一些东西。通常,在 Windows 上,C:/Program Files/<program-name> 用作安装前缀。您要交叉编译的操作系统是什么?
  • 我不是直接安装到根目录,而是使用 GNUInstallDirs 模块。所以头文件放入C:/toolchains/cm0p_root/include,库放入C:/toolchains/cm0p_root/lib,cmake配置文件放入C:/toolchains/cm0p_root/share/<name>*/等等。我正在为裸机 ARM 皮质和 AVR 进行交叉编译。我希望使用可以安装软件包的“sysroot”,这样我就不需要庞大的整体源代码树。例如,我使用的一个简单的实时调度程序需要在每个源代码树中复制,但最好在每个架构中编译和“安装”一次。
  • set(CMAKE_SYSTEM_NAME Generic)set(CMAKE_SYSTEM_PROCESSOR cortex-m0plus) 应该将 CMAKE_CROSSCOMPILING 设置为 true。但同样,不是为 linux 编译,只是一个裸机设备。除非 is 显式设置为 linux,否则可能在内部以 windows 方式构造前缀。这似乎是个坏主意,因为我知道的大多数裸机工具链都使用 gnu 文件夹结构(甚至在 Windows 上)。

标签: cmake


【解决方案1】:

根据 Tsyvarev 的评论创建答案

变量CMAKE_FIND_ROOT_PATH 表示搜索的根目录,但实际前缀是通过将目录附加到根目录来计算的。具体的实现可以在find package search procedure documentation中找到。

相关步骤是前两个(来自 CMake 文档):

  1. <PackageName>_ROOT CMake 变量和<PackageName>_ROOT 环境变量中指定的搜索路径,其中<PackageName> 是要查找的包。包根变量作为堆栈维护,因此如果从查找模块中调用,来自父查找模块的根路径也将在当前包的路径之后搜索。如果通过NO_PACKAGE_ROOT_PATH 或通过设置
  2. 在 cmake 特定缓存变量中指定的搜索路径。这些旨在通过-DVAR=value 在命令行上使用。这些值被解释为分号分隔的列表。如果通过NO_CMAKE_PATH 或将CMAKE_FIND_USE_CMAKE_PATH 设置为FALSE,则可以跳过此操作:
    • MAKE_PREFIX_PATH
    • CMAKE_FRAMEWORK_PATH
    • CMAKE_APPBUNDLE_PATH

我们关心的变量是MAKE_PREFIX_PATH,它被初始化为CMAKE_SYSTEM_PREFIX_PATH的值:

分号分隔的目录列表,指定要由 find_package()、find_program()、find_library()、find_file() 和 find_path() 命令搜索的安装前缀。每个命令都将添加其自己的文档中指定的适当子目录(如 bin、lib 或 include)。

因此,用于此目的的更好的工具链将清除 CMAKE_SYSTEM_PREFIX_PATH 中的值,例如:

SET(CMAKE_INSTALL_PREFIX "C:/toolchains/cm0p_root" CACHE PATH "Cmake install prefix")
set(CMAKE_FIND_ROOT_PATH ${CMAKE_INSTALL_PREFIX})
set(CMAKE_SYSTEM_PREFIX_PATH /)
...
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

关于是否应该完成的说明:
这种技术并没有真正成功。很难维护,因为每个不兼容的编译选项组合都需要一个单独的“sysroot”。相反,至少现在,我使用Conan 来缓存和使用预编译的依赖项。对于较小的东西,我只使用 CPM,它是原生 CMake FetchContent 模块的一个很好的包装器

【讨论】:

    猜你喜欢
    • 2017-05-08
    • 2011-08-24
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多