第三章 内核源码获取与编译:从QNX官网获取源码、构建系统(Buildfile)入门、首次编译内核镜像

好,咱们进入实战环节了。前两章聊了不少理论,现在该动手了。这一章的核心就三件事:拿到源码、搞懂Buildfile、编译出第一个内核镜像。听起来简单,但里面坑不少。我当年第一次搞QNX内核编译,光环境配置就折腾了两天。嗯,咱们一步步来。

3.1 从QNX官网获取源码

QNX的源码获取,跟Linux那套不太一样。它不是随便git clone就能搞定的。你得先有合法的授权。

3.1.1 获取途径

我个人习惯走下面两条路:

  • QNX Software Center (QSC):这是官方推荐的图形化工具。安装后登录你的BB账号,就能看到可下载的组件。我建议你直接搜"QNX 7.0 Kernel Source"或者"QNX 8.0 Kernel Source",看你的目标版本。
  • 命令行方式:如果你跟我一样喜欢命令行,可以用qnxsoftwarecenter命令。比如:
qnxsoftwarecenter -install com.qnx.qnx700.kernel.source

这里要注意,QNX的源码包是分模块的。你不需要全下,只下载跟内核相关的就行。我见过有人把整个QNX 7.0的源码包全下了,十几个G,结果大部分都用不上。

注意: 获取源码前,请确认你的BB账号有合法的QNX开发授权。我曾经帮一个客户排查问题,搞了半天发现他用的盗版授权,编译出来的内核在目标板上跑不起来。白费功夫。

3.1.2 源码目录结构

下载完成后,你会看到类似这样的目录结构:

qnx700/
├── src/
│   ├── kernel/
│   │   ├── base/        # 内核基础代码
│   │   ├── procnto/     # 进程管理器
│   │   ├── io-pkt/      # 网络协议栈
│   │   └── ...
│   ├── lib/
│   └── ...
├── build/
│   └── ...
└── ...

核心代码都在src/kernel/下面。你想想看,整个QNX微内核,其实就几十万行C代码。跟Linux那种上千万行的庞然大物比,简直是小清新。

3.2 构建系统(Buildfile)入门

Buildfile是QNX的灵魂。说白了,它就是一份构建脚本,告诉编译器:你要编译哪些模块、链接哪些库、最终生成什么镜像。

3.2.1 Buildfile的基本结构

一个典型的Buildfile长这样:

# 我的第一个Buildfile
[image=0x10800000]
[virtual=armle-v7,raw]  # 目标架构

# 内核模块
include ../../build/common/startup.bui
include ../../build/common/kernel.bui

# 文件系统
[type=link]
/lib=/

# 启动参数
[+script] .script = {
    procnto -vv
    waitfor /dev/servers/system
    ...
}

嗯,这里要注意几个关键点:

  • [image=...]:指定镜像的加载地址。这个地址取决于你的硬件平台。我踩过坑,地址写错了,内核加载后直接死机。
  • [virtual=...]:指定目标架构和格式。比如armle-v7就是ARMv7小端模式。
  • include:引入其他构建片段。QNX官方提供了很多现成的.bui文件,你直接引用就行。

3.2.2 自定义Buildfile

我个人习惯,不要直接修改官方的Buildfile。而是创建一个自己的my_build.bui,然后通过include引用官方模块。这样升级QNX版本时,你的定制化配置不会丢失。

小技巧: 你可以用qcc -V命令查看当前QNX支持的编译器变体。比如qcc -V gcc_ntoarmv7le就是ARMv7的交叉编译器。

3.3 首次编译内核镜像

好,源码有了,Buildfile也写好了。现在开始编译。

3.3.1 设置环境变量

编译前,先设置环境变量。我一般这样搞:

export QNX_TARGET=/opt/qnx700/target/qnx7
export QNX_HOST=/opt/qnx700/host/linux/x86_64
export PATH=$QNX_HOST/usr/bin:$PATH

这里有个坑:路径不能有空格。我见过有人把QNX安装在C:\Program Files\下面,结果编译时各种奇葩错误。建议装在一个无空格的路径下。

3.3.2 执行编译

环境变量设置好后,执行:

cd /path/to/your/buildfile/dir
make -j4

如果一切顺利,你会看到类似这样的输出:

Building IFS image...
Creating image file: qnx-ifs.bin
Done.

生成的qnx-ifs.bin就是你的内核镜像。你可以把它烧录到目标板上测试了。

3.3.3 常见编译错误及解决

我第一次编译时,遇到了不少问题。这里列几个典型的:

错误信息 原因 解决方法
undefined reference to 'xxx' 缺少某个模块的链接 检查Buildfile中的include是否完整
cannot find -lc C库路径不对 检查$QNX_TARGET是否指向正确的目标目录
image too large 镜像超过了指定地址范围 调整[image=...]中的地址,或者裁剪不必要的模块
核心要点: 编译内核镜像,本质上就是把各个模块拼装成一个二进制文件。你裁剪得越狠,镜像越小,启动越快。但前提是,你不能把必要的模块裁掉。否则内核跑不起来。

3.4 实战:编译一个最小内核

咱们来点实际的。我带你编译一个最小内核,只包含最基本的模块:进程管理、内存管理、中断处理。其他像网络、文件系统什么的,统统不要。

Buildfile如下:

# 最小内核Buildfile
[image=0x10800000]
[virtual=armle-v7,raw]

# 只包含核心模块
include ../../build/common/startup.bui
include ../../build/common/kernel_minimal.bui

# 不包含任何文件系统
[type=link]
/lib/=

# 启动参数
[+script] .script = {
    procnto -vv
}

编译命令:

make -j4

生成的镜像大概只有几百KB。你想想看,一个完整的QNX内核镜像通常要几MB。裁剪后能小这么多,这就是微内核架构的优势。

注意: 最小内核只能跑在开发板上做测试。生产环境中,你至少需要文件系统和网络支持。否则你的程序怎么加载?怎么调试?

3.5 本章小结

这一章,咱们干了三件事:

  1. 获取源码:通过QSC或命令行下载内核源码包。
  2. 理解Buildfile:它是QNX的构建脚本,决定了你的内核长什么样。
  3. 编译镜像:从环境变量设置到执行make,再到处理常见错误。

我个人觉得,Buildfile是QNX最值得花时间研究的部分。你把它搞透了,后面做内核裁剪和性能调优,就事半功倍。下一章,咱们会深入内核配置选项,看看哪些功能可以关掉,哪些参数可以调优。

嗯,今天就到这儿。动手试试吧,有问题咱们下章聊。