cmake 交叉编译与 sysroot returns 错误的包含路径

cmake cross-compilation with sysroot returns wrong include paths

我在尝试交叉编译(针对 arm 目标)并通过 cmake 包含包时遇到问题。

在本地编译以及在没有包依赖性的情况下进行交叉编译时,编译工作正常。

我的工具链文件是:

cmake_minimum_required(VERSION 3.3)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_FIND_ROOT_PATH /path/to/sysroot/)
set(CMAKE_SYSROOT /path/to/sysroot/)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
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)

而在 CMakeFileList 我有几个 find_packages:

find_package(pack1 REQUIRED)
find_package(pack2 REQUIRED)
message("--${pack1_INCLUDE_DIRS}--")
message("--${pack2_INCLUDE_DIRS}--")
include_directories(${pack1_INCLUDE_DIRS})
include_directories(${pack2_INCLUDE_DIRS})

显示包含目录变量时,只有列表中的第一个变量带有 sysroot 路径前缀。我得到了这样的东西:

--/path/to/sysroot/usr/include;/usr/include;/usr/include/xmlrpcpp--

当然编译失败了,因为一些头文件与目标系统不对应。

为什么 cmake 没有为整个目录列表添加前缀(它们存在于 sysroot 文件夹中)?

CMAKE_SYSROOTset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 是否足以让 cmake 只在这个目录中查找,或者我在这里遗漏了什么?

注意:在工具链指令中有无set(CMAKE_FIND_ROOT_PATH /path/to/sysroot/)没有区别。

编辑 1:

明确设置包含路径(${pack1_INCLUDE_DIRS}${pack2_INCLUDE_DIRS})以仅指向 sysroot 路径确实解决了编译问题,但随后导致链接器错误(无明确消息),这表明1) 额外的 /usr/include 条目是问题所在,2) ${pack1_LIBRARIES} 变量也不正确。

编辑 2:

关注@Tsyvarev 的回答解释了为什么这不能直接实现。一种解决方案(有点老套)是从 find_package 中提取要包含的库的名称,并强制 cmake 在 sysroot 文件夹中查找它们。下面的代码适用于我的用例:

#Reset libraries towards sysroot only
foreach(lib_path ${pack1_LIBRARIES} ${pack2_LIBRARIES})
    string(REPLACE "/" ";" lib_path_list ${lib_path}) #Breakdown path in list
    list(REVERSE lib_path_list)
    list(GET lib_path_list 0 lib) #Get last element (library name)
    find_library(new_path ${lib} PATHS ${CMAKE_SYSROOT}) #Force to look for it in actual sysroot path
    list(APPEND LIBRARIES ${new_path}) #Add it to LIBRARIES list
    unset(new_path CACHE) #Clear variable to allow new search
endforeach()

以下配置不会递归地将所有子目录附加到您的包含路径。

set(CMAKE_SYSROOT /path/to/sysroot/)

在您的代码中,include "*.h" 应该相对于 /path/to/sysroot/

不使用工具链文件,而是尝试从您的 cmake 命令行传递 --sysroot,这应该始终有效。

变量 CMAKE_SYSROOT(和 CMAKE_FIND_ROOT_PATH)re-roots 仅那些路径,这些路径被不同的 find_* 命令搜索find_libraryfind_pathfind_package(只修改包文件的搜索路径)。

例如如果 find_library 默认在 /usr/lib 下搜索,那么设置 CMAKE_SYSROOT 后它将在 ${CMAKE_SYSROOT}/usr/lib 下搜索。

但是,如果有人打电话

include_directories("/usr/include")

那么/usr/include路径即使在cross-compiling时也保持不变。

如果find_package(pack1)MODULE模式下是运行并且使用Findpack1.cmake脚本定位pack1包的设置,那么Findpack1.cmake脚本将使用 find_libraryfind_path 调用。因此,设置 CMAKE_SYSROOT 将强制此脚本在 sysroot 和 return 适当路径下搜索库和 headers。

但是如果find_package(pack1)CONFIG模式下是运行并且使用pack1Config.cmake脚本定位pack1包的设置,那么pack1Config.cmake 可以使用库的 绝对路径 和包含目录。在那种情况下,CMake 不会转换这些绝对路径,因此当 cross-compiling.

时它们会出错

实际上,CMake 提供了有助于编写 可重定位 XXXConfig.cmake 脚本的机制和规则。但并非所有配置脚本都遵循这些规则。

如果一个项目pack1提供 pack1Config.cmake脚本non-relocatablecross-compiling,那么你需要使用相同的 sysroot 将此项目构建为 cross-compiled。