# zephyr-scripts **Repository Path**: Ethan-ZYS/zephyr-scripts ## Basic Information - **Project Name**: zephyr-scripts - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-07 - **Last Updated**: 2026-09-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # West 扩展命令说明 本仓库的自定义 west 扩展命令集中在 `manifest/scripts/`,通过 `manifest/scripts/west-commands.yml` 注册,供整个 west workspace 使用。 命令加载链路: ``` app//west_used.yml(或 west.yml) └─ self: import: scripts/west-common.yml # 引入命令声明(相对 manifest 仓库根) └─ self: west-commands: scripts/west-commands.yml └─ 加载 scripts/*.py 中注册的 WestCommand ``` > 注意:`self: import:` 的路径是相对 **manifest 仓库根**(`topdir/manifest`)解析的, > 所以 app 清单放在 `app/` 目录里也能正确拉到命令。命令只在 `manifest/scripts/` 一处维护。 --- ## 命令一览 | 命令 | 作用 | 实现文件 | | ---------------------------------------- | ------------------------------------------------------ | --------------- | | `west driver --api ` | 生成硬件驱动模块骨架(区分 zpp / zephyr API 两种风格) | `module.py` | | `west library ` | 生成**无设备树**的纯软件库模块骨架(如事件系统) | `module.py` | | `west app ` | 生成应用骨架(含固件打包 / clangd db 处理) | `app.py` | | `west use-app /` | 切换当前激活的 app 清单(生成 profiles 副本) | `use_app.py` | | `west completion-extra` | 生成/合并 shell 补全片段 | `completion.py` | | `west freeze` | 冻结清单:默认按本地 HEAD,`--declared` 按清单声明版本 | `freeze_app.py` | | `west outdated` | 查看冻结清单里哪些依赖落后、落后几个提交 | `outdated.py` | | `west fw-build` | 封装 `west build`,构建后打包固件 / 复制 clangd db | `fw_build.py` | > 术语约定: > > - **driver** = 硬件驱动模块,**依赖设备树**(dts/bindings + DT_DRV_COMPAT),按 API 风格分两种; > - **library** = 无设备树的纯软件模块(如 zevent 事件库),不生成 dts/bindings。 --- ## 1. `west driver` — 新建硬件驱动模块(依赖设备树) 驱动模块**使用设备树**(生成 dts/bindings + DT_DRV_COMPAT),并按 API 风格分两种: | `--api` | 风格 | 参考仓库 | | ------------- | -------------------------------------------------------------------------------- | --------------------- | | `zpp`(默认) | zpp 封装 C++(`zpp::error`、concept、public/internal 分离) | `modules/uart_com` | | `zephyr` | 适配 Zephyr 原生 API(`device.h`/`devicetree.h`/`drivers/*`,双用途 CMakeLists) | `modules/godtek_temp` | ```sh west driver my_driver --api zpp --deps zpp # zpp 风格 west driver my_driver --api zephyr # 原生 Zephyr API 风格 west driver my_driver -d # 删除(目录 + manifest 条目) ``` | 参数 | 说明 | | ------------- | ------------------------------------------------- | | `name` | 模块名(会创建 `modules//`) | | `--api` | `zpp` 或 `zephyr`,驱动 API 风格(默认 `zpp`) | | `--deps` | 模块依赖(可重复,如 `--deps zpp`) | | `--url` | manifest 条目里的远程仓库地址(默认 `undefined`) | | `-d/--delete` | 删除模块(目录 + 从 manifest 移除) | ### zpp 风格(uart_com 参考) ``` modules/my_driver/ ├─ CMakeLists.txt # zephyr_include_directories + zephyr_sources_ifdef ├─ Kconfig # menuconfig + module = MY_DRIVER ├─ README.md ├─ doc/ ├─ dts/bindings/my_driver.yaml # devicetree binding(compatible) ├─ include/ │ ├─ public/my_driver/my_driver.hpp # 公共 API(zpp::error / concept) │ └─ internal/my_driver/types.hpp # 内部类型 ├─ src/ │ ├─ my_driver.cpp # 主实现(CONFIG_MY_DRIVER 编译) │ └─ test_my_driver.cpp # ztest 单测 ├─ tests/ # ztest + native_sim/native/64 │ ├─ CMakeLists.txt │ ├─ prj.conf │ ├─ testcase.yaml │ └─ boards/test_my_driver.overlay └─ zephyr/module.yaml # depends: [zpp] ``` ### zephyr API 风格(godtek_temp 参考) ``` modules/my_driver/ ├─ CMakeLists.txt # 双用途:作为模块 / 直接构建(ZEPHYR_EXTRA_MODULES) ├─ Kconfig # menuconfig + module = MY_DRIVER ├─ README.md ├─ doc/ ├─ dts/bindings/my_driver.yaml ├─ include/my_driver.h # DT_DRV_COMPAT 定义 ├─ src/ │ ├─ my_driver.cpp # 主实现(CONFIG_MY_DRIVER 编译) │ └─ test_my_driver.cpp # ztest 单测 ├─ tests/ # ztest + native_sim/native/64 │ ├─ CMakeLists.txt # include 模块目录,只编译测试源(驱动源走模块分支) │ ├─ prj.conf │ ├─ testcase.yaml │ └─ boards/test_my_driver.overlay └─ zephyr/module.yaml ``` 两种风格的 CMakeLists 双用途设计(来自 godtek_temp 的 `XXX_AS_MODULE` 手法): 作为模块被 app 引用时只注册驱动源;直接构建时通过 `ZEPHYR_EXTRA_MODULES` 自注册 并 `add_subdirectory(tests)` 构建测试。 创建完成后会自动: - 注册到当前 active manifest(`modules/` 条目); - `git init` 并初始化 `main` 分支。 --- ## 2. `west library` — 新建无设备树的纯软件库 库模块**不使用设备树**(不生成 dts/bindings),是纯软件逻辑,如事件系统。 参考仓库:`modules/zevent`。 ```sh west library my_lib --deps zpp # 创建 west library my_lib -d # 删除 ``` 参数与 `west driver` 相同(但没有 `--api`)。 生成结构(zevent 风格 INTERFACE 库): ``` modules/my_lib/ ├─ CMakeLists.txt # add_library(my_lib.lib INTERFACE) + zephyr_link_libraries ├─ Kconfig # menuconfig + module = MY_LIB ├─ README.md ├─ doc/ ├─ include/ │ ├─ public/my_lib/my_lib.hpp # 公共 API │ └─ private/ # 内部实现头 ├─ src/ │ ├─ my_lib.cpp # 主实现 │ └─ test_my_lib.cpp # ztest 单测 └─ tests/ # ztest + native_sim/native/64 ├─ CMakeLists.txt # target_link_libraries(app PRIVATE my_lib.lib) ├─ prj.conf ├─ testcase.yaml └─ boards/test_my_lib.overlay ``` 要点(zevent 风格): - 以 `add_library(.lib INTERFACE)` 定义纯头文件/接口库,用 `zephyr_link_libraries` 链接; - 测试同样 `target_link_libraries(app PRIVATE .lib)`; - 无 dts/bindings 目录。 --- ## 3. `west use-app` — 切换 app 清单 把某个 app 的清单文件激活为当前 workspace 的 manifest,并生成一份工作区 **profile 副本**(`/profiles/_`),`manifest.file` 指向副本, app 目录本身零修改。 ```sh west use-app # 列出所有 app 及其 manifest 文件 west use-app west.yml # 当前目录的 manifest(在 app// 里直接跑) west use-app app_i_core_link/west.yml # 激活该文件 west use-app app_i_core_link/west_used.yml -u # 激活并 west update west use-app app/app_i_core_link/west.yml # 全路径形式 ``` | 参数 | 说明 | | ---------------- | -------------------------------------------------------- | | `target`(可选) | `/`(app 名可带 `app/` 前缀);省略则列出候选 | | `-u/--update` | 激活后自动执行 `west update` | 要点: - 生成 profile 时自动注入 `self: west-commands: scripts/west-commands.yml`, 保证切到冻结版(原本无 self 段)后扩展命令仍然可用; - 等价手工操作:`west config manifest.file ../profiles/_`; - 裸文件名(如 `west.yml`)相对**当前目录**解析,所以在 `app//` 里 `west use-app west.yml` 即可激活当前 app;`/` 形式仍相对 topdir; - 若只删掉 profile 文件而 `manifest.file` 仍指向它,扩展命令会因 manifest 解析失败而全部失效(`unknown command`)——此时用 `west config manifest.file ../app//` 指回真实清单即可解锁。 --- ## 4. `west completion-extra` — shell 补全 为自定义扩展命令生成 bash/zsh 补全,或合并进 Zephyr 官方补全脚本。 **推荐一条命令搞定**(自动定位官方脚本 → 融合 → 写入文件 → 提示 source): ```sh west completion-extra # 等价于 install,写到 ~/.local/west_completion.sh west completion-extra install # 显式 install west completion-extra install -o /path/to/west_completion.sh # 指定输出 ``` 执行后按提示在 `~/.bashrc` 里加一行即可(只需一次): ```sh source ~/.local/west_completion.sh ``` 其余子命令: ```sh west completion-extra bash # 独立片段(仅自定义命令) west completion-extra zsh # 同上(zsh) west completion-extra merge-bash # 融合后打到 stdout(自动定位官方脚本) west completion-extra merge-bash -o merged.sh # 也可指定输入/输出 ``` | 参数 | 说明 | | ------------------------ | ----------------------------------------------------------------- | | `install`(默认) | 自动定位官方脚本 → 融合 → 写文件(默认 `~/.local/west_completion.sh`) | | `-o/--output FILE` | `install` / `merge-bash` 的输出文件 | | `bash` / `zsh` | 输出独立片段(**只有自定义命令**,请勿重定向覆盖官方脚本) | | `merge-bash [FILE]` | 融合进官方脚本;`FILE` 省略时自动定位,默认打到 stdout | `install`/`merge-bash` 的融合是幂等的(重复执行不会叠加 `custom_cmds` 块), 且只保留官方脚本里唯一的一次 `complete -F ... west` 注册,避免多个 `complete ... west` 互相覆盖。融合还会为每个自定义命令追加 `__comp_west_` 桩函数,否则**按命令名后面再按 TAB 不会补全任何参数** ——官方脚本只对内置命令(如 `build`)注册了参数补全函数,自定义命令默认没有。 桩函数优先**委托**给官方补全函数:按 `-` 拆后缀依次尝试(如 `fw-build` → `__comp_west_build`,所以 `west fw-build -b ` 能补板子、`-t` 能补 target), 匹配不到再回退到 `_filedir` 通用文件补全(如 `use-app`)。独立片段输出头部带 警告注释,说明不应覆盖官方脚本。 --- ## 5. `west freeze` — 冻结清单 一条命令两种模式,用 `--declared` 切换;**默认按本地实际 HEAD 冻结**。 | 模式 | 依据 | 输出默认名 | 适用 | | ------------ | ---------------------------- | -------------------------- | -------------------------------------- | | 默认 | 本地实际 HEAD | `west-version-frozen.yml` | 有本地改动/未推送 commit,复现真实构建 | | `--declared` | manifest-rev(清单声明版本) | `west-frozen.yml` | 依赖都已推送、复现声明版本 | 默认模式(原 `freeze-version`):把每个模块 pin 到**本地实际 checkout 的 HEAD**,而不是清单声明的版本。适合"对依赖库有本地改动、想让别人拿到你真正 构建用的代码"的场景。 `--declared` 模式(原 `freeze-app`):封装 `west manifest --freeze`,把清单 声明的 revision 解析为 SHA,输出到 app 目录,并校验 active manifest 确实属于 该 app(`--force` 可跳过)。 ```sh west freeze # 默认:按 HEAD,输出 west-version-frozen.yml west freeze -o west-frozen.yml # 指定输出 west freeze --allow-dirty # 有未提交改动时仍继续 west freeze --declared # 按声明版本,自动推断 app west freeze --declared app_i_core_link # 指定 app west freeze --declared app_photomagnetic -o west-frozen.yml west freeze --declared app_i_core_link --strip-self # 去掉 self 段(独立分发) ``` | 参数 | 说明 | | -------------- | --------------------------------------------------------------------------------- | | `app`(可选) | app 目录;省略时优先取当前目录所在的 app(在 `app//` 内运行时),否则从 active manifest 推断(`--declared` 模式下必须有结果) | | `-o/--output` | 输出文件;相对路径在能定位到 app 目录时相对 app,否则相对 active manifest 目录 | | `--declared` | 按清单声明版本(manifest-rev)冻结,而非本地 HEAD | | `--strip-self` | 仅 `--declared`:移除冻结结果中的 `self:` 段,产出自包含清单 | | `--allow-dirty`| 仅默认模式:有未提交改动时仍继续(HEAD 已冻结,未提交内容不会包含) | | `-f/--force` | 允许冻结"不属于该 app"的 active manifest | 行为: - 每个已 clone 模块的 `revision` = 本地 `HEAD`(默认)或清单声明版本(`--declared`); - 未 clone 模块保留清单原值并警告; - 默认模式**默认拒绝**存在未提交改动(dirty)的模块,防冻结出不完整快照 (`--allow-dirty` 可跳过); - 保留 `group-filter` / `project-filter`,`url` / `path` / `west-commands` / `groups` 字段原样保留。 --- ## 6. `west app` — 新建应用骨架 在 `app/` 生成一个新应用(结构参照 `app_i_core_link` / `app_photomagnetic`,但不含业务代码),并 `git init`。 ```sh west app my_app # 生成 app/my_app west app my_app -d # 删除 app/my_app ``` 生成内容: ``` app/my_app/ ├─ CMakeLists.txt VERSION prj.conf Kconfig README.md .gitignore zbuild.py west.yml ├─ src/main.cpp include/ boards/ dts/bindings/ ├─ cmake/firmware_package.cmake # 通用固件打包(重命名/合并 + clangd db) ├─ sysbuild/CMakeLists.txt sysbuild/mcuboot.conf sysbuild/mcuboot.overlay └─ sysbuild.conf ``` ### 固件打包(需求 1) `sysbuild/CMakeLists.txt` 在所有镜像构建完成后挂一个 `firmware_package` 目标,调用 `cmake/firmware_package.cmake`: - 产物重命名为 **`<项目名>_<版本号>.bin` / `.hex`**,输出到 **build 根目录** (`CMAKE_BINARY_DIR`,即 `build/`); - **项目名**取自应用 `CMakeLists.txt` 的 `project()`(正则读取); - **版本号**取自 `VERSION` 文件,规则 `..[+][-]`。 ### MCUboot 处理(需求 2) - 编译 MCUboot(sysbuild)时:`.bin` = 应用签名镜像 `zephyr.signed.bin`; `.hex` = `mcuboot/zephyr/zephyr.hex` 与 `app/zephyr/zephyr.signed.hex` 用 Zephyr 自带 `mergehex.py` 合并成的整片镜像; - 无 MCUboot 时:直接使用应用自身的 `zephyr.signed.*` / `zephyr.*`; - 同时把 `build//compile_commands.json` 复制到 **`build/compile_commands.json`**,因为 clangd 只从 build 根目录解析它。 > 注意:现有 `app_i_core_link` / `app_photomagnetic` **保持原样**,本机制仅对 > `west app` 新生成的应用生效。 ## 7. `west outdated` — 查看依赖落后情况 对比冻结清单里钉住的 SHA 与"该依赖应该跟的分支"的最新提交,找出哪些依赖过期、 落后几个提交。 ```sh west outdated app/app_i_core_link/west-frozen.yml # 默认先 fetch west outdated app/app_i_core_link/west-frozen.yml --no-fetch west outdated -r dev # 强制所有项目对比 dev west outdated --all # 连 zephyr import 进来的模块一起看 ``` 参考分支(ref)的确定顺序: 1. `--ref BRANCH` 强制指定; 2. 同名 app 的 **live 清单** `west.yml` 里该项目的 `revision`(如 `dev` / `main` / `master` / `feature/...`)——即该项目"应该跟的分支"; 3. 否则用远端默认分支(`origin/HEAD`)。 > 目标文件是 `west-frozen.yml` 时会自动配对同目录的 `west.yml` 取参考分支; > active manifest 是 profile(`profiles/_`)时也会回退到 `app//west.yml`。 输出为 `PROJECT / PINNED / REF / STATUS`,STATUS 取 `up-to-date`、`behind N`、 `ahead N`、`diverged +A/-B`、`not cloned` 等,按落后提交数排序。默认只比较 app 自己管理的项目,zephyr import 进来的(hal/crypto 等)用 `--all` 才显示。 | 参数 | 说明 | | ------------------ | --------------------------------------------------------- | | `manifest`(可选) | 要检查的清单文件;省略用 active manifest | | `-r/--ref` | 强制所有项目对比同一分支 | | `--fetch` | 先 fetch 各远端再比较(默认) | | `--no-fetch` | 只用本地已有的 remote-tracking ref 比较 | | `-a/--all` | 连 zephyr-imported 项目一起比较(对它们的默认分支) | 例:`function_handle` 钉在 `40b4887`,相对 `dev` 落后 95 个提交——正是之前 `hip4081` binding 缺失的根因。 ## 8. `west fw-build` — 封装 `west build` + 打包固件 参数**原样转发**给 `west build`,构建成功后做后处理(等价于 `app_i_core_link/sysbuild/CMakeLists.txt` 里的 `firmware_package` target,但对所有 app 通用、不需要改 app 的 CMake): ```sh west fw-build -b icl_t2601_a/stm32f429xx --sysbuild app/app_i_core_link/ west fw-build --sysbuild -p auto app/app_i_core_link west fw-build -b native_sim/native/64 app/app_icl_v2 --no-package # 只转发 ``` 后处理内容: 1. **`--sysbuild` 构建**:把 `build//compile_commands.json` **复制**到 `build/compile_commands.json`(clangd 只从 build 根目录解析)。 2. **app 目录有 `VERSION` 时**:把编译产物复制成 `build/_<版本号>.bin/.hex`: - `.bin` ← `/zephyr/zephyr.signed.bin`(无则 `zephyr.bin`); - `.hex` ← sysbuild 的合并产物 `build/merged_.hex`(无则 `zephyr.signed.hex` / `zephyr.hex`); - 版本号 = `MAJOR.MINOR.PATCHLEVEL`,`VERSION_TWEAK>0` 时追加 `.tweak`, `EXTRAVERSION` 非空时追加 `-extra`(指定了才拼)。 `--no-package` 可放在命令行任意位置,跳过上述后处理。 build 目录识别顺序:`-d/--build-dir` → `build.dir-fmt` 配置 → 当前目录(若本身是 Zephyr 构建)→ `build/`。 app 源目录识别顺序:`-s/--source-dir` → 构建目录 `CMakeCache.txt` 的 `APP_DIR`(sysbuild 根)/ `APPLICATION_SOURCE_DIR`(普通构建)→ `build_info.yml`。 注意 sysbuild 根的 `build_info.yml` 指向的是 sysbuild 模板、不是 app,所以以 CMakeCache 为准。 > db 复制到**实际使用的 build 目录**:从 workspace 根目录构建时是 > `/build/compile_commands.json`(对应根 `.clangd` 的 > `CompilationDatabase: build`);在 app 目录内构建时是 > `app//build/compile_commands.json`。 > 现有 `app_photomagnetic/cmake/copy_signed_firmware.cmake` 与 > `app_i_core_link/tools/firmware_make.py` **保持不动**,`fw-build` 是叠加的; > 新 app 或不想改 CMake 的 app 直接用 `west fw-build` 即可。 --- ## 常见问题 **Q: 自定义命令突然 `unknown command`?** A: 扩展命令依赖当前 manifest 能解析。若 `manifest.file` 指向了不存在的 profile 文件,命令会全部失效。先 `west config manifest.file` 查看,再指回 真实清单(如 `../app//west_used.yml`)解锁。 **Q: 两个西命令都叫 `module`?** A: 旧版 `module` 已拆分为 `driver` / `library` 两个命令,不再使用 `module`。 **Q: 补全只出几个自定义命令,官方命令没了?** A: 说明独立片段覆盖了官方补全脚本。用 `merge-bash` 合并进官方脚本, `.bashrc` 只保留 `source ~/.local/west_completion.sh` 一行。