2、开发环境搭建:Linux/Windows下的NuttX编译环境、工具链安装、NSH调试

说实话,搭建开发环境这件事,看着简单,但坑是真不少。我见过太多新手卡在这一步,折腾一整天连个Hello World都跑不起来。今天我就把压箱底的经验掏出来,带你一步步搞定NuttX的编译环境。

2.1 环境选择:Linux还是Windows?

我个人习惯用Linux,尤其是Ubuntu 20.04或22.04 LTS。为什么?因为NuttX的官方CI就是跑在Ubuntu上的,兼容性最好。你想想看,如果连官方测试环境都出问题,那得多闹心。

当然,Windows也能用。我有个同事就是Windows死忠粉,他用WSL2(Windows Subsystem for Linux 2)跑NuttX,效果也不错。但注意,别用原生的Windows命令行——那玩意儿对嵌入式工具链的支持太差了。

我的建议:

  • 首选:Ubuntu 20.04/22.04 原生安装
  • 次选:Windows + WSL2(Ubuntu 20.04)
  • 不推荐:原生Windows CMD/PowerShell

2.2 工具链安装:别踩这些坑

NuttX支持多种架构,ARM、RISC-V、x86都有。这里我以最常用的ARM Cortex-M系列为例,讲讲工具链怎么装。

2.2.1 安装ARM GCC工具链

别去官网手动下载!用包管理器最省心。在Ubuntu下,我一般这么干:

# 添加ARM工具链的PPA源
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt update

# 安装gcc-arm-none-eabi
sudo apt install gcc-arm-none-eabi

# 验证安装
arm-none-eabi-gcc --version

嗯,这里要注意。我曾经遇到过一个问题:系统自带的gcc-arm-none-eabi版本太老,编译NuttX新版本时会报错。所以建议装完后再确认一下版本号,至少要在 10.3-2021.10 以上。

避坑指南:我曾经在Ubuntu 18.04上直接apt install,结果装了个6.x的老版本。编译时各种奇奇怪怪的链接错误,折腾了两天才发现是工具链版本问题。所以,一定要用PPA源或者手动下载最新版

2.2.2 安装其他依赖

除了编译器,NuttX还需要一些辅助工具。我列个清单,你照着装就行:

sudo apt install \
  bison flex gettext texinfo \
  libncurses5-dev libncursesw5-dev \
  gperf automake libtool \
  pkg-config build-essential \
  u-boot-tools

这些工具干嘛用的?说白了,bison和flex是解析配置文件的,ncurses是给menuconfig提供界面的。你不需要全记住,但少一个都可能编译失败。

2.3 获取NuttX源码

源码管理这块,NuttX已经从SVN迁移到Git了。现在都是用GitHub来管理:

# 克隆主仓库
git clone https://github.com/apache/nuttx.git nuttx

# 克隆应用仓库(里面有很多示例和工具)
git clone https://github.com/apache/nuttx-apps.git apps

# 注意:nuttx和apps要放在同一级目录下
ls -la
# 输出应该类似:
# drwxr-xr-x  apps/
# drwxr-xr-x  nuttx/

为什么强调同一级目录?因为NuttX的构建系统默认会在../apps找应用代码。我第一次用的时候没注意,把apps放到了别处,结果编译时一直报找不到头文件。嗯,这种低级错误,犯过一次就记住了。

2.4 配置与编译:第一次跑起来

好,现在工具链和源码都齐了。我们来编译一个最简单的例子——在QEMU上跑NuttX。

2.4.1 配置工程

NuttX用make menuconfig来配置,跟Linux内核很像:

cd nuttx

# 先加载一个默认配置(这里用QEMU的Cortex-M3模拟器)
make distclean
tools/configure.sh -l qemu-armv7m:nsh

# 打开配置界面(可选,新手可以先跳过)
make menuconfig

-l参数什么意思?我解释一下:它表示加载本地配置。如果不加,会从远端拉配置,速度慢不说,还可能因为网络问题失败。

2.4.2 编译

# 开始编译
make -j$(nproc)

# 编译成功后,会生成 nuttx.bin 和 nuttx.elf
ls -la nuttx.bin

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

LD: nuttx
CP: nuttx.hex
CP: nuttx.bin
arm-none-eabi-objcopy -O binary nuttx nuttx.bin

看到LD: nuttx这行,就说明链接成功了。我第一次看到这个输出时,心里那个激动啊——虽然只是个空壳系统,但毕竟是自己亲手编译出来的。

小技巧:如果编译过程中报错,别慌。先看错误信息的前几行,大部分问题都是头文件路径不对或者工具链版本不匹配。我一般会先执行make clean再重新编译,有时候能解决一些奇怪的问题。

2.5 NSH调试:与NuttX对话

NSH(NuttShell)是NuttX的命令行交互界面。说白了,就是嵌入式版的bash。编译成功后,我们来试试怎么用。

2.5.1 在QEMU中运行

# 安装QEMU(如果还没装)
sudo apt install qemu-system-arm

# 启动NuttX
qemu-system-arm \
  -M lm3s6965evb \
  -kernel nuttx.bin \
  -nographic \
  -serial mon:stdio

启动后,你会看到NuttX的启动日志,最后出现一个nsh>提示符。恭喜,你已经成功进入了NuttX的Shell!

2.5.2 常用NSH命令

NSH的命令跟Linux Shell很像,但更精简。我列几个常用的:

命令 功能 示例
ls 列出文件 ls /dev
cd 切换目录 cd /etc
cat 查看文件内容 cat /etc/version
ps 查看进程 ps
free 查看内存 free
help 查看帮助 help

试试输入help,你会看到所有支持的命令列表。我个人最喜欢ps命令——它能让你直观地看到NuttX的任务调度情况,对理解RTOS很有帮助。

2.5.3 调试技巧:用printf大法

在嵌入式开发中,串口输出是最直接的调试手段。NuttX里用syslog来打印日志:

#include <nuttx/syslog/syslog.h>

void my_function(void)
{
    syslog(LOG_INFO, "Hello from NuttX! Current tick: %lu\n", 
           clock_systime_ticks());
}

为什么不用printf?因为printf在NuttX里默认是重定向到文件系统的,而syslog直接走串口。你想想看,如果系统还没挂载文件系统,printf就废了。这个坑我踩过,所以现在习惯用syslog

核心要点回顾:

  1. 环境选Linux(Ubuntu 20.04+),Windows用户用WSL2
  2. 工具链用PPA源安装,版本不低于10.3
  3. nuttx和apps要放在同一级目录
  4. make menuconfig配置,make -j$(nproc)编译
  5. NSH调试用syslog代替printf

好了,环境搭建就讲到这里。下一章我们会深入NuttX的任务管理,看看怎么创建和调度任务。到时候你会发现,今天搭的环境就是你的实验场——多跑多试,比看十遍文档都管用。