第二章:开发环境搭建——QNX SDP安装与配置、Android Studio与车载SDK、Linux交叉编译工具链搭建

好,咱们直接进入正题。开发环境搭建这事儿,说简单也简单,说复杂也复杂。我见过太多项目,前期环境没搞利索,后面调试时各种翻车。所以这一章,我带你一步步把三个核心环境搭好:QNX SDP、Android Studio 加车载 SDK、还有 Linux 交叉编译工具链。

2.1 QNX SDP 安装与配置

QNX 这玩意儿,说实话,第一次接触时我也觉得有点“高冷”。但做车载 HMI,尤其是仪表和域控,你绕不开它。

2.1.1 下载与安装

首先,你得去黑莓官网申请 QNX SDP 的试用版或正式版。我个人习惯用 7.0 或 7.1 版本,比较稳定。

  • 系统要求:建议 Ubuntu 18.04 或 20.04,64位。Windows 上也能跑,但坑多,我不推荐。
  • 安装包:一个 .bin 文件,大概 2-3GB。
  • 安装命令
chmod +x qnx-sdp-7.0.0-xxx.bin
sudo ./qnx-sdp-7.0.0-xxx.bin

安装过程中会让你选安装路径。我一般放在 /opt/qnx700 下,方便管理。

注意:安装路径不要有中文或空格,否则后面编译时你会哭的。我曾经有个同事,路径里加了个空格,折腾了两天才发现。

2.1.2 环境变量配置

装完只是第一步。你得让系统知道 QNX 在哪。编辑 ~/.bashrc,加上这几行:

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

然后 source ~/.bashrc 让它生效。验证一下:

qcc --version

如果能看到版本号,恭喜你,环境通了。

小技巧:我习惯在 /opt/qnx700 下建一个 workspace 目录,所有项目都放里面。这样路径清晰,不容易乱。

2.1.3 常见坑与避坑指南

嗯,这里要注意。QNX 的编译器对代码风格比较敏感。比如,有些 Linux 下的 #include 写法,在 QNX 里可能找不到头文件。我曾经在移植一个开源库时,发现 <sys/socket.h> 在 QNX 下路径不一样,得改成 <sys/socket.h> 但加个 -I 参数指定路径。

另外,QNX 的 Makefile 和 Linux 的有点区别。我建议直接用 QNX 自带的 qmakecmake 配合 -DCMAKE_TOOLCHAIN_FILE 来搞。

2.2 Android Studio 与车载 SDK

现在车载中控屏,十有八九是 Android 系统。所以 Android Studio 是必备的。但光有 Studio 不够,还得配上车载 SDK。

2.2.1 Android Studio 安装

这个简单,去官网下载最新版就行。我目前用的是 Arctic Fox 2020.3.1,稳定且功能全。

  • JDK:建议用 JDK 11 或 17。别用太老的,否则 Gradle 会报错。
  • SDK Manager:安装 Android 10 (API 29) 或 Android 12 (API 31),车载常用这两个版本。
重点:车载开发一定要装 Android Automotive OS 的模拟器镜像。普通手机镜像没有车载的 API,比如 CarServiceVehicleHal 这些。

2.2.2 车载 SDK 集成

车载 SDK 一般由车厂或 Tier1 提供。比如,我做过的一个项目,用的是某头部车厂的 SDK,里面封装了空调、车窗、座椅控制等接口。

集成步骤大致如下:

  1. 把 SDK 的 .aar.jar 文件放到 app/libs 目录下。
  2. build.gradle 里添加依赖:
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
    implementation 'com.android.car:car:1.0.0'
}
  1. AndroidManifest.xml 里声明权限:
<uses-permission android:name="android.car.permission.CAR_CONTROL" />

然后就可以在代码里调用车载 API 了。比如控制空调:

Car car = Car.createCar(context);
CarHvacManager hvac = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
hvac.setTemperature(22.5f);
个人经验:车载 SDK 的文档往往不全。我建议你拿到 SDK 后,先反编译看看里面的接口定义,或者直接找车厂的技术支持要示例代码。别自己瞎猜,浪费时间。

2.2.3 模拟器与真机调试

模拟器调试很方便,但有些功能模拟不了,比如真实的 CAN 总线信号。所以真机调试是必须的。

连接真机时,记得打开开发者选项和 USB 调试。如果遇到设备识别不了,多半是驱动问题。Windows 下装个 adb 驱动就行,Linux 下加个 udev 规则。

2.3 Linux 交叉编译工具链搭建

做车载 HMI,经常需要把代码编译成 ARM 架构的二进制,然后丢到车机上去跑。这时候交叉编译工具链就派上用场了。

2.3.1 工具链选择

常见的工具链有:

工具链 适用平台 备注
gcc-arm-linux-gnueabihf ARM 32位 老平台常用
aarch64-linux-gnu ARM 64位 新平台主流
Linaro 工具链 ARM 全系列 性能优化好

我个人偏爱 Linaro 的,因为它在浮点运算上优化得不错。车载 HMI 经常要处理图形和音频,浮点性能很关键。

2.3.2 安装与配置

以 aarch64 为例,安装命令:

sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

然后写个测试程序:

// hello.c
#include <stdio.h>
int main() {
    printf("Hello from ARM!\n");
    return 0;
}

编译:

aarch64-linux-gnu-gcc -o hello hello.c

file 命令查看:

file hello
# 输出: ELF 64-bit LSB executable, ARM aarch64

看到 ARM aarch64 字样,说明编译成功了。

避坑指南:我曾经在编译一个依赖了 OpenSSL 的库时,忘了指定 --sysroot,结果链接器找不到头文件。后来我建了一个 sysroot 目录,把目标板上的 /usr/include/usr/lib 拷贝过来,再用 --sysroot 指定,才搞定。

2.3.3 与 CMake 集成

实际项目中,我们一般用 CMake 来管理构建。写一个 toolchain.cmake 文件:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

set(CMAKE_FIND_ROOT_PATH /path/to/sysroot)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

然后编译时:

cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
make

这样就能生成 ARM 架构的可执行文件了。

2.4 三个环境的协同工作

实际开发中,这三个环境不是孤立的。比如,你在 Android Studio 里写 HMI 界面,但底层的车身控制逻辑可能跑在 QNX 上,中间通过 IPC 或网络通信。这时候,你需要在 Linux 上用交叉编译工具链把 QNX 的代码编译好,然后集成到 Android 的 APK 里。

嗯,听起来有点绕。但说白了,就是各司其职:

  • QNX SDP:负责实时控制和安全相关的模块。
  • Android Studio:负责上层 HMI 和用户交互。
  • 交叉编译工具链:负责把 Linux 或 QNX 的代码编译成目标架构的二进制。

我建议你在项目初期就把这三个环境的路径、版本、依赖关系理清楚,写成一个文档。别嫌麻烦,后面调试时能省你大量时间。

总结一下:环境搭建是基础,基础不牢,地动山摇。花半天时间把环境配好,比后面花两天时间找 bug 划算得多。

好,这一章就到这里。下一章我们开始讲 QNX 下的进程通信和资源管理,那是车身控制的核心。