gcc交叉编译工具链和QtCreator编译构建Linux的代码时用到的sysroot(System Root)目录是怎么回事儿?怎么样得到它?

引言

截止2025-02-06,我学习Linux嵌入式开发过程中遇到过几次sysroot目录了,比如下面三次:

①在gcc交叉编译工具链的目录:

/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/

下面存在sysroot目录,如下图所示:
在这里插入图片描述
②在QtCreator构建工程时发现工程的Makfile中有下面的配置:

LFLAGS = --sysroot=/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host/arm-buildroot-linux-gnueabihf/sysroot

③在研究gcc交叉编译工具链的头文件搜索路径时(https://blog.youkuaiyun.com/wenhao_ir/article/details/144844740),发现有目录:

/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include

以上情况说明这个目录很重要, 所以本篇博文需要研究下这个sysroot(System Root)目录。

什么是 sysroot 目录?

sysroot(System Root)是一个用于交叉编译的 伪根目录(Fake Root),它包含目标系统的 头文件(headers)库文件(libraries),让交叉编译工具链可以在第三方系统中正常编译出能运行于目标系统的用户空间的文件。
注意:sysroot 主要针对运行于用户空间的代码,关于这一点,本篇博文后面我有详细说明。

在交叉编译过程中,sysroot 目录的作用类似于目标设备的 /(根目录),但它是一个独立的目录,可以放于自己的交叉编译环境中使用。


sysroot 目录的结构

一个典型的 sysroot 目录包含以下子目录:

sysroot/
├── usr/
│   ├── include/       # 目标系统的 C/C++ 头文件(如 stdio.h, stdlib.h)
│   ├── lib/           # 目标系统的动态库(如 libc.so, libm.so, libpthread.so)
│   ├── lib64/         # (某些 64 位架构会有这个目录)
│   ├── bin/           # 目标系统的工具(可能包含交叉编译的 binutils)
│   ├── sbin/          # 部分系统工具
│   └── share/         # 共享数据
├── lib/               # 目标系统的核心库(如 ld-linux.so, libgcc_s.so)
├── etc/               # 目标系统的配置文件
└── ...                # 其他可能的目录,如 opt/, var/, dev/ 等

这个 sysroot 目录的内容与目标系统的 / 目录结构类似,但通常只包含 开发所需的库和头文件,不会包含完整的操作系统文件。
在这里插入图片描述


sysroot 的作用

1. 提供目标系统的库和头文件

在交叉编译时,编译器需要目标系统的头文件和库,而不能使用当前主机系统的文件。例如:

arm-buildroot-linux-gnueabihf-gcc -o my_program my_program.c --sysroot=/path/to/sysroot

这样,编译器会从 /path/to/sysroot/usr/include 查找头文件,并从 /path/to/sysroot/usr/lib 链接库文件,而不会使用主机的 /usr/include/usr/lib


2. 让交叉编译环境更独立

sysroot 目录让交叉编译工具链 不依赖主机系统,确保编译出的程序能够在 目标设备 上运行,而不会意外链接到 主机系统的库

例如:

  • 如果不使用 sysroot,编译器可能会使用主机 /usr/include 下的 stdio.h,而这个文件可能不适用于目标设备,导致程序无法运行。
  • 如果使用 sysroot,编译器会使用 sysroot/usr/include/stdio.h,确保与目标系统匹配。

如何生成 sysroot

1. 使用 Buildroot 生成

使用Buildroot构建嵌入式开发环境时,Buildroot 会编译生成交叉工具链,显然在编译生成交叉工具链时会一并生成 sysroot 目录。
在这里插入图片描述
上面这张截图的目录路径如下:

/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host

在这里插入图片描述
上面这张截图的目录路径如下:

/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host/arm-buildroot-linux-gnueabihf

2. 使用 Yocto 生成

Yocto 也会为每个目标设备生成 sysroot,路径类似:

<Yocto Build Directory>/tmp/sysroots/<target>

3. 手动创建

如果你没有现成的 sysroot,你可以:

  1. 目标设备 拷贝 libusr/include 目录:
    rsync -avz root@target:/lib /path/to/sysroot/
    rsync -avz root@target:/usr/include /path/to/sysroot/usr/
    
  2. 使用 debootstrapmultistrap 生成 sysroot
    sudo debootstrap --arch=armhf buster /path/to/sysroot http://deb.debian.org/debian/
    

如何在编译时使用 sysroot

如何查看交叉编译工具链使用的sysroot 目录的路径

交叉编译工具链(如 arm-buildroot-linux-gnueabihf-gcc)通常默认使用 sysroot 目录。你可以运行:

arm-buildroot-linux-gnueabihf-gcc --print-sysroot

示例输出:

/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot

在这里插入图片描述
表示 GCC 默认的 sysroot 目录就是 /home/book/.../sysroot,所以你不需要手动指定 --sysroot 选项。

手动指定 sysroot的方法

编译时可以手动指定 sysroot

arm-buildroot-linux-gnueabihf-gcc --sysroot=/path/to/sysroot -o my_program my_program.c

或者在 CMake 中:

set(CMAKE_SYSROOT "/path/to/sysroot")

sysroot主要是针对用户空间中的代码编译,而不是内核空间中的代码编译

1. sysroot 主要针对用户空间(User Space)

sysroot 是为了 交叉编译用户空间应用 而准备的,它通常包含:

  • C 标准库(如 glibc, uClibc, musl)
  • 用户空间头文件(如 /usr/include
  • 用户空间库(如 /usr/lib
  • 动态链接器(如 /lib/ld-linux.so.3

当你用交叉编译器(如 arm-buildroot-linux-gnueabihf-gcc)编译 Qt 应用、C 程序、Python 代码 等,它会去 sysroot 里面找 头文件和库


2. 内核空间(Kernel Space)需要完整的 Linux 源码

如果你要编写 Linux 内核驱动(Device Driver)光有 sysroot 是不够的,还需要:

  1. 完整的 Linux 内核源码
    • 例如 /home/book/linux-4.17.8/
  2. 正确配置的 .config 文件
    • 确保 make menuconfig 选择了合适的配置
  3. 内核编译后的 build 目录
    • 驱动程序需要 KERNEL_SOURCE/include 里面的内核头文件
    • 需要 KERNEL_SOURCE/Module.symvers 以解析符号

3. 如何编译驱动

编译内核模块(驱动)时,通常会使用:

make -C /path/to/kernel M=$(pwd) modules

其中 /path/to/kernel 需要指向 正确的 Linux 内核源码目录,而不是 sysroot

如果你误用了 sysroot,驱动编译时会报错:

fatal error: linux/module.h: No such file or directory

因为 sysroot 里没有完整的内核头文件


4. 小结

用途依赖于 sysroot?需要完整的 Linux 源码?
用户空间应用(Qt, C, Python)✅ 是❌ 否
内核驱动(Device Driver)❌ 否✅ 是
编译整个 Linux 内核❌ 否✅ 是

所以,sysroot 主要针对用户空间编译,而内核驱动需要完整的 Linux 源码和编译环境! 🚀

总结

  1. sysroot 是交叉编译工具链的 伪根目录,存放 目标系统的库和头文件
  2. sysroot 独立于主机系统,确保交叉编译的代码可以正确链接目标系统的库。
  3. GCC 默认使用 sysroot,可以通过 gcc --print-sysroot 查看当前的 sysroot 目录。
  4. sysroot 可以通过 Buildroot、Yocto 或手动拷贝 生成,并在编译时使用 --sysroot=路径 选项指定。
  5. sysroot 目录的正确使用,可以 避免链接主机库的问题,确保交叉编译程序能够在目标设备上正常运行。
  6. sysroot 主要针对用户空间编译,而内核空间代码的编译需要完整的 Linux 源码和编译环境
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值