gcc交叉编译时设置了“--sysroot“会产生哪些影响

gcc交叉编译时设置了"–sysroot"会产生哪些影响

在做交叉编译的时候,常常涉及到一个gcc编译选项--sysroot,这个选项是用来设置目标平台根目录的。--sysroot选项的官方说明如下

--sysroot=dir
Use dir as the logical root directory for headers and libraries. For example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it instead searches dir/usr/include and dir/usr/lib.

If you use both this option and the -isysroot option, then the --sysroot option applies to libraries, but the -isysroot option applies to header files.

The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker does not support this option, the header file aspect of --sysroot still works, but the library aspect does not.

--sysroot的说明可以看出,其会对编译和链接过程中,查找头文件和链接库造成影响。

例如:
原本默认会从/usr/include目录中搜索头文件、从/usr/lib中搜索依赖库,
当设置了--sysroot=dir后则会从dir/usr/include搜索头文件、从dir/usr/lib中搜索依赖库。

未设置--sysroot设置了--sysroot=dir
头文件搜索路径/usr/includedir/usr/include
依赖库搜索路径/usr/libdir/usr/lib

通过gcc -print-search-dirs查看默认动态库搜索路径

$ ./aarch64-linux-gnu-gcc --sysroot=/home/admin/tx2-rootfs -print-search-dirs |
 grep libraries | sed 's/libraries: =//g' | tr ':' '\n' | xargs readlink -f
/usr/local/lib/linaro-7.3.1/lib/gcc/aarch64-linux-gnu/7.3.1
/usr/local/lib/linaro-7.3.1/lib/gcc/aarch64-linux-gnu
/usr/local/lib/linaro-7.3.1/lib/gcc
/usr/local/lib/linaro-7.3.1/aarch64-linux-gnu/lib/aarch64-linux-gnu
/usr/local/lib/linaro-7.3.1/aarch64-linux-gnu/lib64
/home/admin/tx2-rootfs/lib/aarch64-linux-gnu/7.3.1
/home/admin/tx2-rootfs/lib/aarch64-linux-gnu
/home/admin/tx2-rootfs/lib64
/home/admin/tx2-rootfs/usr/lib/aarch64-linux-gnu/7.3.1
/home/admin/tx2-rootfs/usr/lib/aarch64-linux-gnu
/home/admin/tx2-rootfs/usr/lib64
/usr/local/lib/linaro-7.3.1/aarch64-linux-gnu/lib
/home/admin/tx2-rootfs/lib
/home/admin/tx2-rootfs/usr/lib

gcc选项--sysroot-I的影响

gcc官方文档关于-I依赖库搜索路径的介绍如下:

-I dir
-iquote dir
-isystem dir
-idirafter dir
Add the directory dir to the list of directories to be searched for header files during preprocessing. If dir begins with ‘=’ or $SYSROOT, then the ‘=’ or $SYSROOT is replaced by the sysroot prefix; see --sysroot and -isysroot.

Directories specified with -iquote apply only to the quote form of the directive, #include "file". Directories specified with -I, -isystem, or -idirafter apply to lookup for both the #include "file" and #include <file> directives.

You can specify any number or combination of these options on the command line to search for header files in several directories. The lookup order is as follows:

    1. For the quote form of the include directive, the directory of the current file is searched first.
    2. For the quote form of the include directive, the directories specified by -iquote options are searched in left-to-right order, as they appear on the command line.
    3. Directories specified with -I options are scanned in left-to-right order.
    4. Directories specified with -isystem options are scanned in left-to-right order.
    5. Standard system directories are scanned.
    6. Directories specified with -idirafter options are scanned in left-to-right order.
You can use -I to override a system header file, substituting your own version, since these directories are searched before the standard system header file directories. However, you should not use this option to add directories that contain vendor-supplied system header files; use -isystem for that.

The -isystem and -idirafter options also mark the directory as a system directory, so that it gets the same special treatment that is applied to the standard system directories.

If a standard system include directory, or a directory specified with -isystem, is also specified with -I, the -I option is ignored. The directory is still searched but as a system directory at its normal position in the system include chain. This is to ensure that GCC’s procedure to fix buggy system headers and the ordering for the #include_next directive are not inadvertently changed. If you really need to change the search order for system directories, use the -nostdinc and/or -isystem options.

经过测试和验证发现,
-Idir编译器只会从dir路径下搜索头文件;
-I=dir-I$SYSROOT/dir则会受--sysroot影响。

gcc选项--sysroot-L的影响

gcc官方文档关于-L依赖库搜索路径的介绍比较简单

-Ldir
Add directory dir to the list of directories to be searched for -l.

经过测试和验证,发现结果和-I选项类似
-Ldir编译器只会从dir路径下搜索依赖库;
-L=dir-I$SYSROOT/dir则会受--sysroot影响。

使用CMAKE进行交叉编译时的建议

1. CMAKE设置--sysroot通过CMAKE_SYSROOT()配置

CMAKE官方文档推荐在工具链文件中设置,如用来交叉编译tx2的工具链文件tx2.cmake内容如下

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

set(SYSROOT_PATH  /home/admin/tx2-rootfs)
set(CMAKE_SYSROOT "${SYSROOT_PATH}")
message(STATUS  "Using sysroot path as ${SYSROOT_PATH}")

set(CMAKE_STAGING_PREFIX /home/admin/workspace/staging/)
set(CMAKE_INSTALL_PREFIX /usr/local)

set(TOOLCHAIN_PATH /usr/local/lib/linaro-7.3.1)
set(TOOLCHAIN_HOST ${TOOLCHAIN_PATH}/bin/aarch64-linux-gnu)

set(TOOLCHAIN_CC "${TOOLCHAIN_HOST}-gcc")
set(TOOLCHAIN_CXX "${TOOLCHAIN_HOST}-g++")

set(CMAKE_C_COMPILER ${TOOLCHAIN_CC})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_CXX})

add_link_options("LINKER:-rpath-link,/home/admin/tx2-rootfs/lib/aarch64-linux-gnu:/home/admin/tx2-rootfs/usr/lib/aarch64-linux-gnu")

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)
  • 在执行cmake的时候指定该工具链文件,假如工具链文件的路径为/home/admin/workspace/tx2.cmake
$ cd /home/admin/workspace/myprj/build
$ cmake -DCMAKE_TOOLCHAIN_FILE=/home/admin/workspace/tx2.cmake ..
  • 或者在你CMakeLists.txt定义project(myprj)前添加include(tx2.cmake)亦可
cmake_minimum_required (VERSION 3.19)
include(tx2.cmake)
project (myprj CXX)

2. CMAKE中用来添加头文件搜索路径的宏INCLUDE_DIRECTORIES()并不会受到--sysroot选项影响

这是因为如果想要--sysroot产生作用,则需要-I=include_dir-I$SYSROOT/include_dir,而如果通过INCLUDE_DIRECTORIES(“$SYSROOT/include_dir”)则CMAKE将这个$SYSROOT/include_dir识别为一个相对于当前工程的相对路径,并且会在编译阶段将路径补全成相对于当前工程目录的绝对路径,例如当前工程路径为/home/admin/workspace/myprj在编译阶段传递到gcc的参数就变成了-I/home/admin/workspace/myprj/\$SYSROOT/include_dir而不是真正想要的-I$SYSROOT/include_dir

推荐做法
直接通过CMAKE本身的包管理工具find_package(pkg)然后将搜索到的包导出的头文件目录列表添加到include_directories(${pkg_INCLUDE_DIR})

find_package(pkg)
include_directories(${pkg_INCLUDE_DIR})

注意:示例中查找的包名为pkg,则头文件路径会保存在名为pkg_INCLUDE_DIR的变量中,大小写敏感

3. 解决链接时无法找到动态库依赖嵌套问题

如果所编译的可执行程序所依赖的动态库也需要依赖其他动态库,但连接器没有发现,就会报下面错误。

warning: lib*.so.1, needed by lib*.so, not found (try using -rpath or -rpath-link)

解决此类问题的关键点

  • 修复sysroot目录中/usr/lib/aarch64-linux-gnu中错误的动态库符号链接
  • 添加链接选项-Wl,-rpath-link

原理分析

以找不到libm.so.6为例,到/home/admin/tx2-rootfs/usr/lib/aarch64-linux-gnu下查看libm.so

$ ls -la 
lrwxrwxrwx  1 admin admin       32 Jun  5 01:25 libm.so -> /lib/aarch64-linux-gnu/libm.so.6

发现libm.so指向了一个无效的链接,类似的无效符号链接有很多,为了保证以后链接不会出问题,需要:

  1. 修复这些符号链接到正确的路径
  2. 创建/lib/aarch64-linux-gnu符号链接

可是即使修复了指向无效动态库链接的问题,这个链接警告和报错还是没有实际解决。这时就要借助
-rpath-rpath-link选项了
在CMAKE官方文档中,说可以通过设置CMAKE_INSTALL_RPATHCMAKE_BUILD_WITH_INSTALL_RPATH这两个变量来向gcc增加-Wl,rpath,选项

set(CMAKE_INSTALL_RPATH "dir")
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)

可是实际操作发现,只能设置-rpath而不能设置-rpath-link。
为了支持-rpath-link,推荐使用add_link_options增加-rpath-link选项

 add_link_options("LINKER:-rpath-link,/home/admin/tx2-rootfs/lib/aarch64-linux-gnu:/home/admin/tx2-rootfs/usr/lib/aarch64-linux-gnu")

add_link_option 宏在cmake 3.13版本以后才支持的
注意:由于--sysroot选项不会作用于-rpath-link,所以要填写完整路径名

谢谢关注

  • 24
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是在 Ubuntu 18.04 操作系统下,使用 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf 交叉编译 Qt 5.6.2 的流程: 1. 下载 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf 工具链,并解压到某个目录下。 2. 安装 Qt 5.6.2 的依赖库: ``` sudo apt-get update sudo apt-get install build-essential perl python git sudo apt-get install libfontconfig1-dev libfreetype6-dev libx11-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libx11-xcb-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-xinerama0-dev libxcb-xkb-dev libxslt1-dev libgl1-mesa-dev libglu1-mesa-dev libsqlite3-dev libmysqlclient-dev libpq-dev libiodbc2-dev libasound2-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libxrandr-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-bad1.0-dev libgstreamer-plugins-ugly1.0-dev gstreamer1.0-libav gstreamer1.0-alsa gstreamer1.0-pulseaudio libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-bad1.0-dev libgstreamer-plugins-ugly1.0-dev ``` 3. 下载 Qt 5.6.2 的源代码,并解压到某个目录下。 4. 进入 Qt 5.6.2 的源代码目录,执行以下命令: ``` ./configure -release -opengl es2 -device linux-rasp-pi2-g++ -device-option CROSS_COMPILE=/path/to/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -sysroot /path/to/sysroot -opensource -confirm-license -make libs -prefix /usr/local/qt5arm -no-xcb -no-pch -no-icu -no-gif -no-libjpeg -no-libpng -no-harfbuzz -no-openssl -no-qml-debug -nomake examples -nomake tests ``` 其中,/path/to/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf 是 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf 工具链的路径,/path/to/sysroot交叉编译环境的根文件系统路径。 5. 执行 make 命令进行编译: ``` make -j4 ``` 其中,-j4 表示使用 4 个线程进行编译。 6. 执行 make install 命令进行安装: ``` sudo make install ``` 7. 完成后,在 /usr/local/qt5arm 目录下生成 Qt 5.6.2 的安装文件。把该目录添加到交叉编译环境的 PATH 环境变量中即可使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值