本篇笔记先做些应用开发的基础准备工作,官网英文教程见此。
官方把这个教程放偏后的位置,导致我之前自己去学习 Cmake 和 Ninja 的相关知识,多做了一些重复工作。
我正在学习 Zephyr,一个很可能会用到很多物联网设备上的操作系统,如果你也感兴趣,可点此查看帖子zephyr学习笔记汇总。
Zephyr 根目录包含源码,内核配置选项以及编译定义。
根目录下的 application 目录负责 Zephyr 上的应用程序,包含所有与应用程序相关的文件,包括配置选项和源码。
一个应用程序目录一般是这样:
/app
├── CMakeLists.txt
├── prj.conf
└── src
└── main.c
CMakeLists.txt: 这个文件主要告诉 CMake 编译系统如何找到其他应用程序文件,包括硬件相关的内核配置文件,是否可以在硬件上运行或者debug程序等等。
Kernel configuration files: 每个应用文件都会提供一个配置文件(以 .conf 结尾),用于定义内核配置选项数值。如果忽视这个文件,或者无有效数值,则内核会使用默认的配置数值。
应用程序源码:应用程序的源码使用 C 或者汇编,通常都会放在 src 的子目录下。
// 待补充,后面新建自己程序时再看。
Zephyr 编译系统会编译并链接所有组件成为单个应用镜像。这里使用 ninja 来演示。
1.进入应用程序目录 /app.
2.输入如下命令,将会按照 应用程序的 CMakeLists.txt 文件的设置,编译出应用程序的 zephyr.elf 镜像。
mkdir build
cd build
cmake -GNinja ..
ninja
如果需要,可以使用 CONF_FILE 参数,来指定相关的 .conf 文件来配置编译应用程序。这样设置将会覆盖原本的 .config 文件。例如:
# On Linux/macOS
export CONF_FILE=prj.alternate.conf
# On Windows
set CONF_FILE=prj.alternate.conf
cmake -GNinja ..
ninja
如果需要,可以为不同的硬件板子生成项目文件,通过定义环境变量 BOARD。
CONF_FILE 和 BOARD 参数都可以在编译应用时指定。
/app/build
├── build.ninja
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── rules.ninja
└── zephyr
运行 ninja 后,编译输出的文件将会写入 zephyr 子目录。(这不是 Zephyr 根目录,不是 Zephyr 源码目录。)
Zephyr 编译系统只重编译可能影响应用镜像的部分。因此重编译应用程序通常要比第一次要快。
如果需要强制重编译整个系统,可按照如下步骤:
1.打开控制台,进入编译目录/app/build。
2.输入如下命令,可删除应用程序生成的文件,但 .config 文件不会被删除掉。
ninja clean
或者,输入如下命令,可删除应用程序所有生成的文件,包括 .config 文件,它包含了应用程序根据板子类型生成的当前配置信息。
ninja pristine
3.之后可按照上面提到的“编译应用程序”步骤来编译。
应用程序既可以在真实硬件板子上运行,也可以在模拟设备上运行。
1.编译应用程序。
2.保证你的板子连接到主机。通常都是USB连接。
3.在 build 目录 /app/build,运行如下控制台命令,将会把编译好的 Zephyr 二进制文件写入,并且运行到板子上。
ninja flash
Zephyr 编译系统集成了板子支持文件,使用硬件特定的工具来烧写 Zephyr 二进制文件到你的硬件,之后运行。
每次你运行 flash 命令,你的应用程序将会重编译并重新烧写。
如果板子支持不完全,通过 Zephyr 编译系统就可能无法烧写。如果你收到错误消息,需要到你的板子文档上确认如何烧写。
注意:
当 Linux 上开发时,通常需要安装 特定的 udev 规则,来使能非ROOT用户通过USB设备接入你的板子。如果烧写失败,需要到你的板子文档上确认。
CMake 用来编译应用程序和内核。CMake 编译分为两步,第一步称作 配置,配置期间,CMakeLists.txt 编译脚本会执行。配置结束后,CMake 便有了内部模型,可以生成针对主机的编译脚本。
CMake 支持为很多编译系统生成脚本,但目前 Zephyr 只支持 Ninja 和 Make 这两个编译系统。配置之后,开始执行生成的编译脚本。这些编译脚本可以重编译应用程序,而不需要执行 CMake。不管怎么样,变动之后,编译前都必须再执行配置步骤。编译脚本会检测这些情况,并自动重新配置,有些时候必须要手动。
Zephyr 使用 CMake 的’target’概念来识别编译。target 可以是可执行文件,一个库文件,或者一个生成文件。对于应用开发者,library target 是最需要了解的。所有的源码都是通过包含 library target 来编译。
Library targets 可以通过如下 CMakeLists.txt 编译脚本来加入源码。
target_sources(app PRIVATE src/main.c)
在上面的 CMakeLists.txt 中,已存在的 library target 名为 app,为其配置包含源码文件 src/main.c。PRIVATE 关键字表明我们正在修改内部。使用 PUBLIC 关键字可以修改链接的其他库文件。这种情况下,使用 PUBLIC 会导致链接 app 的其他 libraries 包含入 src/main.c,这是我们所不期望的。PUBLIC 关键词在修改包含路径是比较有用。
每个应用程序都必须包含 CMakeLists.txt,这个文件是编译系统的入口。最后的 zephyr.elf 镜像既包含应用程序也包含内核库。
这一小节描述如何在 CMakeLists.txt 进行操作。按照如下步骤执行。
1.如果要针对某个硬件编译,可以写如下语句:
set(BOARD qemu_x86)
2.应用程序都需要配置文件,正常是使用 prj.conf 文件。如果要特殊要求,可以使用 CONF_FILE 变量来定义。
…