West 清单
本页详细介绍 west 的多仓库模型、清单文件和 west manifest 命令。west.manifest 模块的 API 文档见 west.manifest。更一般的入门介绍和命令概览见 基础知识。
多仓库模型
West 对 west workspace 内仓库及其历史的视图如下图所示(不过,此示例的部分内容专门对应上游 Zephyr 对 west 的用法):
清单仓库的历史是“浮”在灰色平面上方的一条 Git 提交线。实线箭头从父提交指向子提交。下方平面包含工作区各仓库的 Git 提交历史,每个项目仓库用一个矩形框表示。各仓库内的父子提交关系也用实线箭头表示。
清单仓库中的每个提交都包含一个清单文件(对于上游 Zephyr,清单仓库就是 zephyr 仓库本身)。每个提交中的清单文件指定它期望各项目仓库使用的对应提交。图中以虚线箭头表示这种关系,每条虚线箭头都从清单仓库的一个提交指向项目仓库的对应提交。
请注意以下重要细节:
可以添加项目(例如清单仓库提交
D与E之间的P1),也可以移除项目(同一对清单仓库提交之间的P2)项目与清单仓库的历史不必一起前进或后退:
从
A → B,P2保持不变;从F → G,P1和P3也保持不变。从
A → B,P3向前推进。从
C → D,P3向后回退。
回退项目历史的一个用途,是退回到引入回归问题之前的修订版本,从而“撤销”该问题。
可以“跳过”项目仓库中的提交:从
B → C,P3在其历史中向前跨越了多个提交。上图中,没有项目仓库在“同一时刻”具有两个修订版本:每份清单文件对其关注的每个项目都恰好引用一个提交。可以使用分支名称作为清单修订版本来放宽此限制,但代价是失去对清单仓库历史进行二分定位的能力。
清单文件
West 清单是 YAML 文件,顶层包含 manifest 节及若干子节,例如:
manifest:
remotes:
# short names for project URLs
projects:
# a list of projects managed by west
defaults:
# default project attributes
self:
# configuration related to the manifest repository itself,
# i.e. the repository containing west.yml
version: "<schema-version>"
group-filter:
# a list of project groups to enable or disable
用 YAML 术语来说,清单文件包含一个具有 manifest 键的映射。其他键及其内容均被忽略(west v0.5 还要求 west 键,但从 v0.6 起会忽略它)。
清单包含 defaults、remotes、projects 和 self 等子节。用 YAML 术语来说,manifest 键的值也是一个映射,以这些“子节”为键。从 west v0.10 起,这些“子节”键全部可选。
projects 的值是由 west 管理的仓库及其元数据的列表。稍后会讨论它;首先介绍可减少 projects 列表中重复输入的 remotes 节。
远程仓库
remotes 子节包含一个序列,指定获取项目所用的基础 URL。
每个 remotes 元素都有名称和“基础 URL”,用于组成各项目完整的 Git 获取 URL。可以在远程基础 URL 后追加项目专用路径,形成项目获取 URL。(如下文所述,项目也可以直接指定完整获取 URL。)
例如:
manifest:
# ...
remotes:
- name: remote1
url-base: https://git.example.com/base1
- name: remote2
url-base: https://git.example.com/base2
remotes 的键及用法见下表。
键 |
描述 |
|---|---|
|
必需;远程仓库的唯一名称。 |
|
为使用此远程仓库的每个项目的获取 URL 添加的前缀。 |
上例给出两个远程仓库,名称为 remote1 和 remote2,基础 URL 分别是 https://git.example.com/base1 和 https://git.example.com/base2。也可以使用 SSH 基础 URL;例如,如果 remote1 也支持通过 SSH 使用 Git,就可以采用 git@example.com:base1。任何 Git 接受的形式都可以。
项目
projects 子节包含描述 west 工作区中项目仓库的序列。每个项目具有唯一名称。可以指定克隆和获取项目时使用的 Git 远程 URL、要跟踪的修订版本,以及项目在本地文件系统中的存储位置。请注意,west 项目 不同于模块。
以下示例采用上文定义的 remotes。
manifest:
# [... same remotes as above...]
projects:
- name: proj1
description: the first example project
remote: remote1
path: extra/project-1
- name: proj2
description: |
A multi-line description of the second example
project.
repo-path: my-path
remote: remote2
revision: v1.3
- name: proj3
url: https://github.com/user/project-three
revision: abcde413a111
- name: proj4
url: https://github.com/user/project-four
revision: pull/69/head # GitHub Pull Request
在此清单中:
proj1使用远程仓库remote1,因此 Git 获取 URL 为https://git.example.com/base1/proj1。在远程url-base后追加/和项目name,即可形成此 URL。本地会将此项目克隆到相对于 west 工作区根目录的
extra/project-1路径,因为其path属性显式指定了该值。项目未指定
revision,因此默认使用master。West 下次更新此项目时,会获取该分支的当前顶端提交,并将其检出为分离的HEAD。proj2同时具有remote和repo-path,因此其获取 URL 为https://git.example.com/base2/my-path。存在repo-path属性时,构造获取 URL 会用它覆盖默认的name。项目没有
path属性,因此默认使用name,将其克隆到名为proj2的目录。West 更新项目时,会检出v1.3标签指向的提交。proj3显式指定了url,因此从https://github.com/user/project-three获取。其本地路径默认为名称
proj3。下次更新时会检出提交abcde413a111。
可用的项目键及用法见下表。其中有时会提到 defaults 子节,下一节将介绍它。
键 |
描述 |
|---|---|
|
必需;项目的唯一名称。名称不能是保留值“west”或“manifest”,且在清单文件中必须唯一。 |
|
可选,项目的说明性描述。在 west v1.2.0 中添加。 |
|
必需(二者选一,不能同时指定)。 如果项目有 如果项目有 如果项目二者都没有, |
|
可选。如果指定,则将其追加到远程仓库的 |
|
可选。指定 项目修订版本可以是任何可获取的 Git 引用:分支、标签、SHA、拉取请求等。 未另行指定时,默认 将 |
|
可选。相对于 west 工作区顶层目录的路径,指定在本地何处克隆仓库。如果缺失,使用项目 |
|
可选。指定正整数,会将克隆仓库的浅历史限制为给定提交数。仅在 |
|
可选。指定项目内一个 YAML 文件的相对路径,该文件描述项目提供的附加 west 命令。按惯例名为 |
|
可选。如果为 |
|
可选,项目所属组的列表。详情见 项目组。 |
|
可选。可以让 |
|
可选,值可以是任意 YAML 值。参见 仓库用户数据。 |
脚注
默认值
defaults 子节可为项目属性提供默认值,特别是默认远程仓库名称和修订版本。前述清单也可使用 defaults 改写为:
manifest:
defaults:
remote: remote1
revision: v1.3
remotes:
- name: remote1
url-base: https://git.example.com/base1
- name: remote2
url-base: https://git.example.com/base2
projects:
- name: proj1
description: the first example project
path: extra/project-1
revision: master
- name: proj2
description: |
A multi-line description of the second example
project.
repo-path: my-path
remote: remote2
- name: proj3
url: https://github.com/user/project-three
revision: abcde413a111
可用的 defaults 键及用法见下表。
键 |
描述 |
|---|---|
|
可选。如果项目没有设置 |
|
可选。如果项目未设置 |
自身
self 子节可用于控制清单仓库本身。
例如,来看 zephyr 仓库 west.yml 中的这个片段:
manifest:
# ...
self:
path: zephyr
west-commands: scripts/west-commands.yml
这确保 zephyr 仓库克隆到路径 zephyr;不过如上文所述,从默认清单 URL https://github.com/zephyrproject-rtos/zephyr 克隆时,本来就会如此。由于 zephyr 仓库确实包含扩展命令,其 self 条目声明了对应 west-commands.yml 相对于仓库根目录的位置。
可用的 self 键及用法见下表。
键 |
描述 |
|---|---|
|
可选。指定 如果未指定,默认使用清单仓库 URL 中路径部分的基本名称。例如 URL 为 |
|
可选,与项目序列元素中的同名键类似。 |
|
可选,同样类似于 |
版本
version 子节声明清单文件使用了某个 west 版本引入的功能。尝试用旧版 west 加载时会失败,并显示说明所需最低 west 版本的错误消息。
示例如下:
manifest:
# Marks that this file uses version 0.10 of the west manifest
# file format.
#
# An attempt to load this manifest file with west v0.8.0 will
# fail with an error message saying that west v0.10.0 or
# later is required.
version: "0.10"
清单节使用 west source code repository 中的 pykwalify 模式 manifest-schema.yml 进行验证。
下表列出有效的 version 值,以及相应版本引入的清单文件功能。
|
新功能 |
|---|---|
|
首次支持 |
|
支持 |
|
不建议使用 west v0.9.x。 提供此模式版本,是为了让用户显式要求兼容 west v0.9.0。但 west v0.10.0 及后续版本对 v0.9.0 引入的功能采用了不兼容行为。应尽可能避开版本“0.9”。 |
|
支持:
|
|
支持 |
|
支持 |
|
与 |
|
支持 |
备注
未引入清单文件格式新功能的 west 版本,不会改变有效 version 值列表。例如,version: "0.11" 无效,因为 west v0.11.x 没有引入清单文件格式的新功能。
像上文一样用引号包围 version 值,会强制 YAML 解析器将其视为字符串。如果没有引号,YAML 中的 0.10 就只是浮点值 0.1。如果转换为字符串后值相同,可以省略引号,但最好保留。不确定时始终使用引号。
如果清单中不包含 version,每个新发布的 west 版本都会尝试使用该版本已有的功能加载它。如果 west 版本过旧,无法加载清单,错误消息可能更难理解。
组过滤器
参见 项目组。
活动与非活动项目
west 清单中定义的项目可以是 非活动 或 活动 的。区别在于,west 通常会忽略非活动项目。例如,west update 不更新非活动项目,west list 默认不打印它们的信息。非活动项目中的任何 清单导入 也会被 west 忽略。
有两种方式可使项目变为非活动状态:
使用
manifest.project-filter配置选项。如果通过此选项激活或停用项目,就会忽略通过groups:停用项目的相关规则。也就是说,如果manifest.project-filter中的正则表达式适用于某项目,该项目的组就不再影响其活动状态。详情见 内置配置选项 中该选项的条目。
否则,如果项目有组,且所有组均被禁用,则项目处于非活动状态。
详情见下一节。
项目组
可以使用 上文 简要介绍的 groups 和 group-filter 键,将项目分组,并启用或禁用组。
例如,可以通过 west forall --group,让 west forall 命令只对组内项目执行。这也可让项目变为非活动状态;关于非活动项目,见上一节。
下一节介绍项目组,随后一节介绍 启用和禁用的项目组。基本示例见 项目组示例。最后,组过滤器与导入 简要说明 group-filter 与 清单导入 功能的交互。
组基础
groups: 和 group-filter: 键在清单中的形式如下:
manifest:
projects:
- name: some-project
groups: ...
group-filter: ...
groups 键的值是组名列表。组名为字符串。
可使用 group-filter 启用或禁用项目组。如果项目的所有组均被禁用,且未通过 manifest.project-filter 配置选项另行激活,则该项目处于非活动状态。
例如,在以下清单片段中:
manifest:
projects:
- name: project-1
groups:
- groupA
- name: project-2
groups:
- groupB
- groupC
- name: project-3
各项目所属组如下:
project-1:一个组,名为groupAproject-2:两个组,名为groupB和groupCproject-3:没有组
项目组名称不能包含逗号 (,)、冒号 (:) 或空白。
组名不能以短横线 (-) 或加号 (+) 开头,但可以在其他位置包含这些字符。例如,foo-bar 和 foo+bar 是有效组名,-foobar 和 +foobar 则无效。
除此之外,组名可以是任意字符串,且区分大小写。
一项限制是,任何项目都不能同时使用 import: 和 groups:。(这是为了避免某些异常边界情况。)
启用和禁用的项目组
所有项目组默认启用。可以在清单文件和 配置 中启用或禁用组。
在清单文件中,manifest: group-filter: 是列出待启用和禁用组的 YAML 列表。
要启用组,在名称前加上加号 (+)。例如,以下清单片段启用 groupA:
manifest:
group-filter: [+groupA]
对于默认已启用的组,这样写虽然多余,但可用来覆盖导入清单文件中的设置。更多信息见 组过滤器与导入。
要禁用组,在名称前加上短横线 (-)。例如,以下清单片段禁用 groupA 和 groupB:
manifest:
group-filter: [-groupA,-groupB]
备注
由于 group-filter 是 YAML 列表,上述片段也可以写成:
manifest:
group-filter:
- -groupA
- -groupB
不过,这种语法更难阅读,因此不推荐。
除清单文件外,还可以使用 manifest.group-filter 配置选项控制组的启用和禁用。此选项是以逗号分隔的组列表,用于启用和/或禁用组。
要启用组,将其名称加上 + 前缀后加入列表;要禁用组,则加上 - 前缀。例如,将 manifest.group-filter 设为 +groupA,-groupB,会启用 groupA 并禁用 groupB。
配置选项的值会覆盖清单文件中的数据。可以将其理解为把 manifest.group-filter 配置选项追加到 YAML 的 manifest: group-filter: 列表,采用“最后一项优先”的语义。
实用示例:减少工作区下载
默认情况下,west update 获取清单中定义的所有活动项目。大型工作区可能包含并非每种工作流都需要的可选模块、厂商 HAL、实验组件,或特定平台的依赖项及其漏洞。
项目组可以控制 west 操作期间,哪些已分组的项目被视为活动项目。
例如,考虑以下清单片段:
manifest:
projects:
- name: hal_nordic
groups:
- nordic
- name: hal_stm32
groups:
- stm32
- name: experimental_lib
groups:
- optional
面向 Nordic 设备的工作区,可以在运行 west update 前禁用 stm32 和 optional 组:
west config manifest.group-filter -- "-stm32,-optional"
配置过滤器后,运行:
west update
这会跳过仅属于已禁用组的项目。
备注
项目组只影响清单中显式分配到匹配组的项目。没有匹配组定义的项目,无论 manifest.group-filter 配置值如何,都保持活动状态。
备注
修改 manifest.group-filter 不会自动删除工作区中已经克隆的仓库。它影响后续 west 操作中项目是否被视为活动项目。
此工作流有助于减少不必要的下载,并简化大型多项目环境中的工作区管理。
项目组示例
本节给出涉及项目组和活动项目的示例,同时使用 manifest: group-filter: YAML 列表和 manifest.group-filter 配置列表,展示二者如何配合。
请注意,下列清单中的 defaults 和 remotes 数据仅用于使示例完整、独立,与讨论本身无关。
备注
以下所有示例均假定未设置 manifest.project-filter 选项。
示例 1:未禁用任何组
完整清单文件如下:
manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
- groupA
- groupB
- name: baz
defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com
未设置 manifest.group-filter 配置选项(可运行 west config -D manifest.group-filter 确保这一点)。
所有组默认启用,因此没有被禁用的组。三个项目(foo、bar 和 baz)全部处于活动状态。请注意,项目 baz 没有组,因此无法使其变为非活动状态。
示例 2:通过清单禁用一个组
完整清单文件如下:
manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
- groupA
- groupB
group-filter: [-groupA]
defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com
未设置 manifest.group-filter 配置选项(可运行 west config -D manifest.group-filter 确保这一点)。
由于 groupA 被禁用,项目 foo 为非活动状态。groupB 仍启用,因此项目 bar 为活动状态。
示例 3:通过清单禁用多个组
完整清单文件如下:
manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
- groupA
- groupB
group-filter: [-groupA,-groupB]
defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com
未设置 manifest.group-filter 配置选项(可运行 west config -D manifest.group-filter 确保这一点)。
foo 和 bar 的所有组均被禁用,因此二者都为非活动状态。
示例 4:通过配置禁用组
完整清单文件如下:
manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
- groupA
- groupB
defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com
将 manifest.group-filter 配置选项设为 -groupA (可运行 west config manifest.group-filter -- -groupA 确保这一点;额外的 -- 必不可少,否则参数解析器会将 -groupA 视为值为 roupA 的命令行选项 -g)。
manifest.group-filter 配置选项禁用了 groupA,因此项目 foo 为非活动状态。groupB 仍启用,因此项目 bar 为活动状态。
示例 5:通过配置覆盖已禁用的组
完整清单文件如下:
manifest:
projects:
- name: foo
- name: bar
groups:
- groupA
- name: baz
groups:
- groupA
- groupB
group-filter: [-groupA]
defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com
将 manifest.group-filter 配置选项设为 +groupA (可运行 west config manifest.group-filter +groupA 确保这一点)。
此时,groupA 被启用:manifest.group-filter 配置选项的优先级高于清单文件中的 manifest: group-filter: [-groupA] 内容。
因此,项目 foo 和 bar 均为活动状态。
示例 6:通过配置覆盖多个已禁用的组
完整清单文件如下:
manifest:
projects:
- name: foo
- name: bar
groups:
- groupA
- name: baz
groups:
- groupA
- groupB
group-filter: [-groupA,-groupB]
defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com
将 manifest.group-filter 配置选项设为 +groupA,+groupB (可运行 west config manifest.group-filter "+groupA,+groupB" 确保这一点)。
此时,配置值覆盖清单文件对这两个组的设置,因此 groupA 和 groupB 均启用。
因此,项目 foo 和 bar 均为活动状态。
示例 7:通过配置禁用多个组
完整清单文件如下:
manifest:
projects:
- name: foo
- name: bar
groups:
- groupA
- name: baz
groups:
- groupA
- groupB
defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com
将 manifest.group-filter 配置选项设为 -groupA,-groupB (可运行 west config manifest.group-filter -- "-groupA,-groupB" 确保这一点)。
此时,groupA 和 groupB 均被禁用。
因此,项目 foo 和 bar 均为非活动状态。
组过滤器与导入
本节简要介绍 manifest: group-filter: 值与 清单导入 结合时的行为。完整细节见 清单导入细节。
警告
以下语义适用于 west v0.10.0 及后续版本。West v0.9.x 的语义不同,不建议在 v0.9.x 中结合使用 group-filter 和 import。
概括而言:
如果只导入一份清单,它在
group-filter中禁用的组,也会在你的清单中被禁用可以通过清单文件的
manifest: group-filter:值、工作区的manifest.group-filter配置选项,或同时使用二者覆盖此设置
以下是一些示例。
示例 1:不覆盖
使用以下 parent/west.yml 清单:
# parent/west.yml:
manifest:
projects:
- name: child
url: https://git.example.com/child
import: true
- name: project-1
url: https://git.example.com/project-1
groups:
- unstable
child/west.yml 的内容如下:
# child/west.yml:
manifest:
group-filter: [-unstable]
projects:
- name: project-2
url: https://git.example.com/project-2
- name: project-3
url: https://git.example.com/project-3
groups:
- unstable
解析后的清单中,只有 child 和 project-2 为活动项目。
child/west.yml 禁用了 unstable 组,且 parent/west.yml 未覆盖该设置。因此,解析后清单的最终 group-filter 为 [-unstable]。
project-1 和 project-3 属于 unstable 组,且不属于其他组,因此为非活动状态。
示例 2:通过清单覆盖导入的 group-filter
使用以下 parent/west.yml 清单:
# parent/west.yml:
manifest:
group-filter: [+unstable,-optional]
projects:
- name: child
url: https://git.example.com/child
import: true
- name: project-1
url: https://git.example.com/project-1
groups:
- unstable
child/west.yml 的内容如下:
# child/west.yml:
manifest:
group-filter: [-unstable]
projects:
- name: project-2
url: https://git.example.com/project-2
groups:
- optional
- name: project-3
url: https://git.example.com/project-3
groups:
- unstable
只有 child、project-1 和 project-3 项目为活动状态。
parent/west.yml 覆盖了 child/west.yml 中的 [-unstable] 组过滤器,因此 unstable 组被启用。project-1 和 project-3 属于 unstable 组,因此为活动状态。
同一 parent/west.yml 文件禁用了 optional 组,因此 project-2 为非活动状态。
parent/west.yml 指定的最终组过滤器为 [+unstable,-optional]。
示例 3:通过配置覆盖导入的 group-filter
使用以下 parent/west.yml 清单:
# parent/west.yml:
manifest:
projects:
- name: child
url: https://git.example.com/child
import: true
- name: project-1
url: https://git.example.com/project-1
groups:
- unstable
child/west.yml 的内容如下:
# child/west.yml:
manifest:
group-filter: [-unstable]
projects:
- name: project-2
url: https://git.example.com/project-2
groups:
- optional
- name: project-3
url: https://git.example.com/project-3
groups:
- unstable
如果运行:
west config manifest.group-filter +unstable,-optional
则只有 child、project-1 和 project-3 项目为活动状态。
manifest.group-filter 配置选项覆盖了 child/west.yml 中的 -unstable 组过滤器,因此 unstable 组被启用。project-1 和 project-3 属于 unstable 组,因此为活动状态。
同一配置选项禁用了 optional 组,因此 project-2 为非活动状态。
parent/west.yml 与 manifest.group-filter 配置选项共同指定的最终组过滤器为 [+unstable,-optional]。
项目中的 Git 子模块
可使用 上文 简要介绍的 submodules 键,让 west update 同时处理项目 Git 仓库中配置的所有 Git submodules。submodules 键可以位于 projects 内,例如:
manifest:
projects:
- name: some-project
submodules: ...
submodules 键可以是布尔值或映射列表。下面依次介绍。
方式 1:布尔值
这是使用 submodules 最简单的方式。
如果 projects 属性 submodules 为 true,每当 west update 更新项目本身时,也会递归更新其 Git 子模块。如果为 false 或未指定,则不起作用。
例如,假设源代码仓库 foo 含有一些子模块,你希望 west update 将它们全部保持同步,同时更新同一工作区中名为 bar 的另一个项目。
可通过以下清单文件实现:
manifest:
projects:
- name: foo
submodules: true
- name: bar
此处,west update 会初始化并更新 foo 中的全部子模块。如果 bar 有子模块,它们会被忽略,因为 bar 未设置 submodules 值。
方式 2:映射列表
submodules 键可以是映射列表,每个列表元素对应一个所需子模块。列出的每个子模块都会递归更新。未列出的子模块仍可通过 git 命令手动跟踪和更新;无论它们是否存在,west 都会完全忽略。
path 键必须与某个子模块相对于所属 west 项目的路径完全一致,该路径可在 git submodule status 的输出中查看。name 键是可选的,west 目前不使用它,也不会将其传给 git submodule 命令。name 键曾在 west 0.9.0 中短暂变为必需,但在 0.9.1 中改为可选。
例如,假设源代码仓库 foo 有许多子模块,你希望 west update 只同步其中一部分,同时更新同一工作区中名为 bar 的另一个项目。
可通过以下清单文件实现:
manifest:
projects:
- name: foo
submodules:
- path: path/to/foo-first-sub
- name: foo-second-sub
path: path/to/foo-second-sub
- name: bar
此处,west update 只会递归初始化并更新 foo 中路径为 path/to/foo-first-sub 和 path/to/foo-second-sub 的子模块。bar 中的所有子模块仍被忽略。
仓库用户数据
West v0.12 及后续版本支持项目中的可选 userdata 键。
West v0.13 及后续版本支持在 manifest: self: 节中使用此键。
它供需要用户特定项目元数据的程序使用。除将其按 YAML 解析外,west 本身完全忽略此值。
此键的值可以是任意 YAML。West 解析后,会通过相应 west.manifest.Project 对象的 userdata 属性,将其提供给使用 West API 的程序。
清单片段示例:
manifest:
projects:
- name: foo
- name: bar
userdata: a-string
- name: baz
userdata:
key: value
self:
userdata: blub
Python 用法示例:
manifest = west.manifest.Manifest.from_file()
foo, bar, baz = manifest.get_projects(['foo', 'bar', 'baz'])
foo.userdata # None
bar.userdata # 'a-string'
baz.userdata # {'key': 'value'}
manifest.userdata # 'blub'
清单导入
可以使用上文简要介绍的 import 键,将其他清单文件中的项目纳入 west.yml。此键可以是 project 或 self 节的属性:
manifest:
projects:
- name: some-project
import: ...
self:
import: ...
使用“self: import:”可从包含 west.yml 的仓库中加载其他文件。使用“project: ... import:”可加载该项目 Git 历史中定义的其他文件。
West 按以下顺序从各个清单文件解析最终清单:
self中导入的文件你的
west.yml文件projects中导入的文件
解析期间,west 会忽略其他文件中已定义的项目。例如,west.yml 中名为 foo 的项目,会使 west 忽略从 projects 列表导入的其他同名 foo 项目。
import 键可以是布尔值、路径、映射或序列。下面通过示例依次介绍:
其工作机制的更 形式化描述 位于示例之后。
故障排查提示
如果使用此功能时对 west 的行为感到困惑,可以尝试 解析清单,查看导入完成后的最终结果。
Option 1: Boolean
这是使用 import 最简单的方式。
如果 projects 属性 import 为 true,west 会从项目根目录的 west.yml 导入项目。如果为 false 或未指定,则不起作用。例如,以下清单会从 p1 Git 仓库的 v1.0 修订版本导入 west.yml:
manifest:
# ...
projects:
- name: p1
revision: v1.0
import: true # Import west.yml from p1's v1.0 git tag
- name: p2
import: false # Nothing is imported from p2.
- name: p3 # Nothing is imported from p3 either.
在 self 中将 import 设为 true 或 false 都是错误的,例如:
manifest:
# ...
self:
import: true # Error
示例 1.1:基于 Zephyr 发行版的下游
你有一个希望配合 Zephyr v1.14.1 LTS 使用的源代码仓库,希望通过 west 维护整个环境,又不想修改任何主线仓库。
换言之,需要的 west 工作区如下:
my-downstream/
├── .west/ # west directory
├── zephyr/ # mainline zephyr repository
│ └── west.yml # the v1.14.1 version of this file is imported
├── modules/ # modules from mainline zephyr
│ ├── hal/
│ └── [...other directories..]
├── [ ... other projects ...] # other mainline repositories
└── my-repo/ # your downstream repository
├── west.yml # main manifest importing zephyr/west.yml v1.14.1
└── [...other files..]
可使用以下 my-repo/west.yml 实现:
# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: v1.14.1
import: true
假设 my-repo 托管在 https://git.example.com/my-repo,就可以按以下方式在计算机上创建工作区:
west init -m https://git.example.com/my-repo my-downstream
cd my-downstream
west update
运行 west init 后,my-downstream/my-repo 会被克隆。
运行 west update 后,zephyr 仓库 v1.14.1 修订版本的 west.yml 中定义的所有项目,也会克隆到 my-downstream。
此时可以按需向 my-repo 添加并提交任意代码,包括自己的 Zephyr 应用程序、驱动程序等。参见 应用开发。
示例 1.2:“滚动发布”的 Zephyr 下游
这与 示例 1.1:基于 Zephyr 发行版的下游 类似,只是 zephyr 仓库改用 revision: main:
# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: main
import: true
可以用同样的方式创建工作区:
west init -m https://git.example.com/my-repo my-downstream
cd my-downstream
west update
这次,每次运行 west update,zephyr 仓库的特殊 manifest-rev 分支都会更新,指向从 https://github.com/zephyrproject-rtos/zephyr 新获取的 main 分支顶端。
随后会使用新 manifest-rev 中的 zephyr/west.yml 内容,从 Zephyr 导入项目。这样可以跟上 Zephyr 项目的最新变化。代价是运行 west update 的结果不再可复现,因为每次运行时远程 main 分支都可能改变。
还必须理解,解析导入时,west 会完全 忽略工作树中的 zephyr/west.yml。从项目导入时,west 始终使用最近一次 manifest-rev 提交中保存的清单内容。
只有位于清单仓库工作树中的清单,才能直接从文件系统导入。示例见 示例 2.2:包含清单文件目录的下游。
示例 1.3:基于 Zephyr 发行版、带模块分叉的下游
此清单与 示例 1.1:基于 Zephyr 发行版的下游 类似,但存在以下区别:
基于 Zephyr 2.0 的下游
包含该版本中
modules/hal/nordic模块 的下游分叉
# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
- name: my-remote
url-base: https://git.example.com
projects:
- name: hal_nordic # higher precedence
remote: my-remote
revision: my-sha
path: modules/hal/nordic
- name: zephyr
remote: zephyrproject-rtos
revision: v2.0.0
import: true # imported projects have lower precedence
# subset of zephyr/west.yml contents at v2.0.0:
manifest:
defaults:
remote: zephyrproject-rtos
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
# ...
- name: hal_nordic # lower precedence, values ignored
path: modules/hal/nordic
revision: another-sha
使用此清单文件时,名为 hal_nordic 的项目:
从
https://git.example.com/hal_nordic克隆,而不是https://github.com/zephyrproject-rtos/hal_nordic。由
west update更新到提交my-sha,而不是主线提交another-sha
也就是说,顶层清单定义了 hal_nordic 这样的项目后,west 会忽略后续解析导入时遇到的其他同名定义。
这也意味着,在 my-repo/west.yml 中定义 hal_nordic 时,必须复制 path: modules/hal/nordic 值。zephyr/west.yml 中的值会被完全忽略。如果实际使用时对此感到困惑,故障排查建议见 解析清单。
运行 west update 时,west 会:
更新 zephyr 的
manifest-rev,使其指向v2.0.0标签导入该
manifest-rev中的zephyr/west.yml在本地检出除
hal_nordic外所有 zephyr 项目的v2.0.0对应修订版本将
hal_nordic更新到my-sha,而不是another-sha
方式 2:相对路径
import 值也可以是指向清单文件或清单文件目录的相对路径。该路径相对于 import 键所在的 projects 或 self 仓库根目录。
示例如下:
manifest:
projects:
- name: project-1
revision: v1.0
import: west.yml
- name: project-2
revision: main
import: p2-manifests
self:
import: submanifests
这会导入以下内容:
manifest-rev中的project-1/west.yml内容;运行west update后,该引用指向标签v1.0由
west update获取的main分支最新提交中,目录树project-2/p2-manifests下的所有 YAML 文件,按文件名排序清单仓库
submanifests中实际存在于文件系统的 YAML 文件,按文件名排序
注意,projects 导入通过 manifest-rev 从 Git 获取数据,而 self 导入从文件系统获取数据。这是因为 west 一如既往地将清单仓库的版本控制交给你管理。
示例 2.1:基于 Zephyr 发行版、使用显式路径的下游
这是以显式方式编写与 示例 1.1:基于 Zephyr 发行版的下游 等效的清单。
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: v1.14.1
import: west.yml
import: west.yml 表示使用 zephyr 项目内的 west.yml 文件。此例虽是刻意构造的,但展示了基本思路。
实际使用中,要导入的清单文件不叫 west.yml 时,这种方式很有用。
示例 2.2:包含清单文件目录的下游
你的 Zephyr 下游有许多附加仓库,多到希望将其拆分到多个清单文件,但仍在一个清单仓库中统一跟踪,如下所示:
my-repo/
├── submanifests
│ ├── 01-libraries.yml
│ ├── 02-vendor-hals.yml
│ └── 03-applications.yml
└── west.yml
除 zephyr/west.yml 中的项目外,还希望把 my-repo/submanifests 中的全部文件加入主清单 my-repo/west.yml。同时,希望跟踪 Zephyr 仓库 main 分支的最新开发代码,而不使用固定修订版本。
实现方式如下:
# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: main
import: true
self:
import: submanifests
解析时按以下顺序导入清单文件:
my-repo/submanifests/01-libraries.ymlmy-repo/submanifests/02-vendor-hals.ymlmy-repo/submanifests/03-applications.ymlmy-repo/west.ymlzephyr/west.yml
备注
本例中,.yml 文件名加上数字前缀,以确保按指定顺序导入。
可以自由选择名称。West 导入目录内文件前,会先按名称排序。
注意,submanifests 中的清单在 my-repo/west.yml 和 zephyr/west.yml 之前 导入。一般而言,self 节中的 import 会先于 projects 中的清单文件和主清单文件处理。
这意味着 my-repo/submanifests 中定义的项目优先级最高。例如,若 01-libraries.yml 定义了 hal_nordic,zephyr/west.yml 中的同名项目就会被直接忽略。故障排查建议仍可参见 解析清单。
这可能看起来有些奇怪,但它允许“事后”重新定义项目,下一个示例会展示这一点。
示例 2.3:持续集成覆盖
持续集成系统需要从开发者的分叉仓库,而不是主线开发仓库,获取并测试 west 工作区中的多个仓库,以检查这些改动能否协同工作。
以 示例 2.2:包含清单文件目录的下游 为起点,CI 脚本在 my-repo/submanifests 中添加文件 00-ci.yml,内容如下:
# my-repo/submanifests/00-ci.yml:
manifest:
projects:
- name: a-vendor-hal
url: https://github.com/a-developer/hal
revision: a-pull-request-branch
- name: an-application
url: https://github.com/a-developer/application
revision: another-pull-request-branch
CI 脚本在 my-repo/submanifests 中生成此文件后运行 west update。00-ci.yml 中定义的项目比 my-repo/submanifests 中其他定义优先,因为 00-ci.yml 的名称排在其他文件名之前。
因此,即使别处也定义了同名项目,west update 仍会始终在 a-vendor-hal 和 an-application 项目中检出开发者的分支。
方式 3:映射
import 键还可以包含具有以下键的映射:
file:可选。要导入的清单文件或目录名称。未指定时默认为west.yml。name-allowlist:可选。指定一个要包含的项目名称,或项目名称序列。path-allowlist:可选。指定一个要匹配的项目路径,或路径序列。它采用 shell 风格的通配模式,目前通过 pathlib 实现。请注意,这意味着是否区分大小写取决于平台。name-blocklist:可选。类似name-allowlist,但包含要排除而不是纳入的项目名称。path-blocklist:可选。类似path-allowlist,但包含要排除而不是纳入的项目路径。path-prefix:可选(v0.8.0 新增)。如果指定,会将其加在项目及所有导入项目的工作区路径前面,可用于将这些项目放入工作区子目录。
同时指定时,允许列表优先于阻止列表。例如,项目即使按路径被阻止,只要按名称被允许,仍会被导入。
示例 3.1:使用名称允许列表的下游
以下是一对分别代表主线和下游的清单文件。但下游不希望使用全部主线项目。假定主线 west.yml 托管在 https://git.example.com/mainline/manifest。
# mainline west.yml:
manifest:
projects:
- name: mainline-app # included
path: examples/app
url: https://git.example.com/mainline/app
- name: lib
path: libraries/lib
url: https://git.example.com/mainline/lib
- name: lib2 # included
path: libraries/lib2
url: https://git.example.com/mainline/lib2
# downstream west.yml:
manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
import:
name-allowlist:
- mainline-app
- lib2
- name: downstream-app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3
等效的单文件清单如下:
manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
- name: downstream-app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3
- name: mainline-app # imported
path: examples/app
url: https://git.example.com/mainline/app
- name: lib2 # imported
path: libraries/lib2
url: https://git.example.com/mainline/lib2
如果未使用允许列表,主线清单中的 lib 项目也会被导入。
示例 3.2:使用路径允许列表的下游
以下示例展示如何使用 path-allowlist,仅允许导入主线中的库。
# mainline west.yml:
manifest:
projects:
- name: app
path: examples/app
url: https://git.example.com/mainline/app
- name: lib
path: libraries/lib # included
url: https://git.example.com/mainline/lib
- name: lib2
path: libraries/lib2 # included
url: https://git.example.com/mainline/lib2
# downstream west.yml:
manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
import:
path-allowlist: libraries/*
- name: app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3
等效的单文件清单如下:
manifest:
projects:
- name: lib # imported
path: libraries/lib
url: https://git.example.com/mainline/lib
- name: lib2 # imported
path: libraries/lib2
url: https://git.example.com/mainline/lib2
- name: mainline
url: https://git.example.com/mainline/manifest
- name: app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3
示例 3.3:使用路径阻止列表的下游
以下示例展示如何通过工作区中共同的路径前缀阻止所有主线厂商 HAL,再为目标芯片添加自己的版本,同时保留其余所有项目。
# mainline west.yml:
manifest:
defaults:
remote: mainline
remotes:
- name: mainline
url-base: https://git.example.com/mainline
projects:
- name: app
- name: lib
path: libraries/lib
- name: lib2
path: libraries/lib2
- name: hal_foo
path: modules/hals/foo # excluded
- name: hal_bar
path: modules/hals/bar # excluded
- name: hal_baz
path: modules/hals/baz # excluded
# downstream west.yml:
manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
import:
path-blocklist: modules/hals/*
- name: hal_foo
path: modules/hals/foo
url: https://git.example.com/downstream/hal_foo
等效的单文件清单如下:
manifest:
defaults:
remote: mainline
remotes:
- name: mainline
url-base: https://git.example.com/mainline
projects:
- name: app # imported
- name: lib # imported
path: libraries/lib
- name: lib2 # imported
path: libraries/lib2
- name: mainline
repo-path: https://git.example.com/mainline/manifest
- name: hal_foo
path: modules/hals/foo
url: https://git.example.com/downstream/hal_foo
示例 3.4:导入到子目录
你希望导入一份清单及其项目,并将所有内容放入 west workspace 的子目录。
例如,假设希望从项目 foo 导入以下清单,将该项目及其项目 bar 和 baz 加入工作区:
# foo/west.yml:
manifest:
defaults:
remote: example
remotes:
- name: example
url-base: https://git.example.com
projects:
- name: bar
- name: baz
你希望将这三个项目仓库都放入 external-code 子目录,而不是工作区顶层,如下所示:
workspace/
└── external-code/
├── foo/
├── bar/
└── baz/
可通过以下清单实现:
manifest:
projects:
- name: foo
url: https://git.example.com/foo
import:
path-prefix: external-code
等效的单文件清单如下:
# foo/west.yml:
manifest:
defaults:
remote: example
remotes:
- name: example
url-base: https://git.example.com
projects:
- name: foo
path: external-code/foo
- name: bar
path: external-code/bar
- name: baz
path: external-code/baz
方式 4:序列
import 键还可以包含由文件、目录和映射组成的序列。
示例 4.1:使用清单文件序列的下游
此示例通过显式命名文件的序列,实现与 示例 2.2:包含清单文件目录的下游 等效的清单。
# my-repo/west.yml:
manifest:
projects:
- name: zephyr
url: https://github.com/zephyrproject-rtos/zephyr
import: west.yml
self:
import:
- submanifests/01-libraries.yml
- submanifests/02-vendor-hals.yml
- submanifests/03-applications.yml
示例 4.2:导入顺序说明
以下更复杂的示例展示 west 导入清单文件的顺序:
# my-repo/west.yml
manifest:
# ...
projects:
- name: my-library
- name: my-app
- name: zephyr
import: true
- name: another-manifest-repo
import: submanifests
self:
import:
- submanifests/libraries.yml
- submanifests/vendor-hals.yml
- submanifests/applications.yml
defaults:
remote: my-remote
对于此示例,west 按以下顺序解析导入:
首先是
my-repo/submanifests中列出的文件,按出现顺序处理(例如,由于这是文件序列,libraries.yml先于applications.yml),因为self: import:总是最先导入然后是
my-repo/west.yml(包含my-library等项目,前提是submanifests中尚未定义它们)随后是
zephyr/west.yml,因为它是my-repo/west.yml的projects列表中的第一个import键最后是
another-manifest-repo/submanifests中的文件(按文件名排序),因为它是最后一个项目import
清单导入细节
本节以更形式化的方式,描述 west 如何解析使用 import 的清单文件。
概述
import 键可以出现在 west 清单的 projects 和 self 节中。一般形式如下:
# Top-level manifest file.
manifest:
projects:
- name: foo
import:
... # import-1
- name: bar
import:
... # import-2
# ...
- name: baz
import:
... # import-N
self:
import:
... # self-import
导入键是可选的。如果 import-1, ..., import-N 中任意项缺失,west 就不从相应项目导入额外清单数据。如果缺少 self-import,则除顶层文件外,不再导入清单仓库中的其他文件。
解析清单导入最终得到:
projects列表,由顶层文件与导入文件定义的projects合并而成一组扩展命令,取自顶层文件和所有导入文件中的
west-commands键group-filter列表,由顶层和所有导入的过滤器合并而成
导入按以下顺序进行:
先导入
self-import指定的清单。然后处理顶层清单文件的定义。
再依次导入
import-1、……、import-N指定的清单。
当单个 import 键引用多个清单文件时,按以下顺序处理:
如果值是指向目录的相对路径(或
file为目录的映射),其中的清单文件按字典序处理,即按文件名排序。如果值是序列,则按元素出现的顺序递归导入。
必要时,此过程会递归执行。例如,如果 import-1 产生的清单文件包含 import 键,会先按相同规则递归解析,再继续处理其内容。
以下各节介绍这些结果。
Projects
本节介绍最终 projects 列表的生成方式。
项目通过名称识别。如果同名项目出现在多份清单中,采用首个定义,忽略后续定义。例如,import-1 中名为 bar 的项目会被忽略,因为顶层 west.yml 已经定义了同名项目。
import-1 到 import-N 指定文件的内容,从各项目最新 manifest-rev 修订版本的 Git 数据中导入。运行 west update 可将这些版本分别更新到 rev-1 至 rev-N。如果某个 manifest-rev 引用缺失或过时,west update 还会从远程获取 URL 获取项目数据并更新该引用。
还请注意,从根清单到定义项目 P 的仓库,所有导入清单都必须更新,west 才能更新 P 本身。例如,若 baz/west.yml 定义了 P,west update P 就需要同时更新 baz 项目的 manifest-rev 和 P 的本地 Git 克隆中的 manifest-rev 分支。令人困惑的是,更新 baz 可能使 P 从 baz/west.yml 中消失,此时 west update P “应当”因无法识别项目而失败!
因此,如果 P 定义在导入清单中,就不能运行 west update P;必须通过不带项目参数的 west update,将其与其他所有项目一起更新。
默认情况下,如果项目修订版本是本地已有的 SHA 或标签,west 不会通过网络获取该项目数据,因此除非确有需要,更新额外项目不应花费太多时间。更多信息见 update.fetch 配置选项文档。
扩展
处理导入时发现的所有通过 west-commands 键定义的扩展命令,均可在解析后的清单中使用。
如果导入清单文件的 self: 节含有 west-commands: 定义,其中的扩展命令会在导入该清单时加入可用扩展集合。因此,它们优先于之后添加的所有同名扩展命令。
组过滤器
解析后的清单具有 group-filter 值,由顶层清单和所有导入清单中的 group-filter 值连接而成。
导入顺序越靠前的清单文件优先级越高,因此在最终 group-filter 中越靠后连接。
换言之,设:
由
self-import解析得到的子清单具有组过滤器self-filter顶层清单文件具有组过滤器
top-filter从
import-1至import-N解析得到的子清单,分别具有组过滤器filter-1至filter-N
则最终解析后的 group-filter 值为 filterN + ... + filter-2 + filter-1 + top-filter + self-filter,其中 + 表示列表连接。
重要
过滤器在上述列表中的顺序很重要。
最终连接列表中,某个组的最后一个过滤器元素“胜出”,决定该组启用还是禁用。
例如,在 [-foo] + [+foo] 中,组 foo 被 启用;但在 [+foo] + [-foo] 中,组 foo 被 禁用。
为简明起见,west 和本文档可能按上述规则省略连接后冗余的组过滤器元素。例如,根据上述原因,[+foo] + [-foo] 可以简写为 [-foo]。又如,由于所有组默认启用,[-foo] + [+foo] 可简写为空列表 []。
清单命令
west manifest 命令用于操作清单文件,接受一个操作及其专用参数。
以下各节介绍每种操作,并提供简单用法的基本命令形式。所有选项的完整说明可运行 west manifest --help 查看。
解析清单
--resolve 操作输出一份清单文件,等效于当前清单及其全部 导入清单:
west manifest --resolve [-o outfile]
此操作主要用于查看执行全部 import 后的“最终”清单内容。
要打印每个导入清单文件及解析期间项目处理方式的详细信息,使用 -v 设置最高详细程度:
west -v manifest --resolve
冻结清单
--freeze 操作输出冻结清单:
west manifest --freeze [-o outfile]
“冻结”清单是每个项目修订版本均为 SHA 的清单文件。使用 --freeze 可生成与当前清单等效的冻结清单。-o 选项指定输出文件;未指定时使用标准输出。
验证清单
--validate 操作在当前清单文件有效时成功,否则失败并报错:
west manifest --validate
错误消息可以帮助诊断问题。
这里的“无效”是指清单文件语法不符合本页所述规则。
如果清单有效,但行为不符合预期,可以通过 -v 提高详细程度,了解 west 对清单作出了哪些决策,以及原因:
west -v manifest --validate
获取清单路径
--path 操作打印顶层清单文件的路径:
west manifest --path
输出类似 /path/to/workspace/west.yml,路径格式取决于操作系统。