news 2026/9/14 15:47:59

Bazel 如何用 mod 命令查看模块依赖图并定位模块依赖来源?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bazel 如何用 mod 命令查看模块依赖图并定位模块依赖来源?

Bazel 如何用 mod 命令查看模块依赖图并定位模块依赖来源?

【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel

使用 bzlmod 管理外部依赖的项目里,MODULE.bazel往往只列出直接依赖,而rules_ccplatforms这类模块是经由传递依赖间接进入项目的;某个版本为什么被升级、某个仓库又是由哪个扩展生成的,仅看依赖声明很难说清楚。Bazel 的mod命令面向这个问题:它展示整个模块依赖图,回答“某模块为什么出现在图里”,并能查看模块背后的 repo 定义、扩展的使用方式。本文的命令与示例输出全部来自 mod 命令文档,适用对象是已使用MODULE.bazel管理外部依赖的 Bazel 项目。

示例项目与命令格式

文档中的全部示例基于一个my_project示例项目,其MODULE.bazel如下:

module( name = "my_project", version = "1.0", ) bazel_dep(name = "bazel_skylib", version = "1.1.1", repo_name = "skylib1") bazel_dep(name = "bazel_skylib", version = "1.2.0", repo_name = "skylib2") multiple_version_override(module_name = "bazel_skylib", versions = ["1.1.1", "1.2.0"]) bazel_dep(name = "stardoc", version = "0.5.0") bazel_dep(name = "rules_java", version = "5.0.0") toolchains = use_extension("@rules_java//java:extensions.bzl", "toolchains") use_repo(toolchains, my_jdk="remotejdk17_linux")

后续所有输出示例都来自这个配置。注意bazel_skylib声明了两个版本并配合multiple_version_override同时保留,这会让同一个模块名在图中出现多个版本,是演示版本解析行为的典型设置。

命令的统一格式为:

bazel mod <subcommand> [<options>] [<arg> [<arg>...]]

<arg>表示一个或多个模块或仓库,可写成四种形式:

  • <root>:根模块,即当前项目;
  • <name>@<version>:指定版本的模块;模块带 non-registry override 时,版本位写_(如bazel_tools@_);
  • <name>:该模块所有存在的版本;
  • @<repo_name>--base_module上下文下的 apparent 仓库名;@@<repo_name>:canonical 仓库名。

其中 apparent 名与 canonical 名的区别见 仓库名文档:canonical 名是仓库在整个 workspace 内始终可寻址的名字,apparent 名是仓库在某个模块上下文中的“别名”。在需要指定模块的位置,仓库名也可以代替对应模块;反之亦然。

查看完整依赖树:graph 与 deps

graph从根模块展开整张依赖图,deps显示指定模块解析后的直接依赖(输出形态与graph类似):

bazel mod graph

文档示例输出:

<root> (my_project@1.0) ├───bazel_skylib@1.1.1 │ └───platforms@0.0.4 ├───bazel_skylib@1.2.0 │ └───platforms@0.0.4 ... ├───rules_java@5.0.0 │ ├───platforms@0.0.4 ... │ ├───rules_cc@0.0.1 │ │ ├───bazel_skylib@1.1.1 ... │ │ └───platforms@0.0.4 ... │ └───rules_proto@4.0.0 │ ├───bazel_skylib@1.1.1 ... │ └───rules_cc@0.0.1 ... └───stardoc@0.5.0 ├───bazel_skylib@1.1.1 ... └───rules_java@5.0.0 ...

树中...表示该节点已在别处展开、不再重复展开,只是降噪标记;点边(如└╌╌)表示两条节点间是间接(传递)依赖边。从图里能直接读出的事实:stardoc并不是项目直接依赖的模块,platforms经由多条路径进入项目。

常用的图参数:

  • --from <arg>[,<arg>...]:默认从<root>展开;指定后,所列模块直接挂在根节点下,图只从这些模块开始展开。例如bazel mod graph --from rules_java --include_unused会展开出rules_java@5.0.0的子树,并用点边附上未被使用的rules_java@4.0.0
  • --depth <N>:输出深度。1只显示根与直接依赖。默认值:explain为 1,deps为 2,其余为无穷;
  • --include_unused:包含解析后已不被使用的模块(如被 override 换掉的版本);
  • --include_builtin:包含@bazel_tools等内置模块,默认关闭,因为内置模块被所有模块隐式依赖、会显著放大输出;
  • --cycles:在图中包含循环依赖边,默认关闭。

定位依赖来源:explain 与 all_paths

要弄清“项目为什么会用到某个模块”,用explain。它显示指定模块在依赖图中出现的全部位置,以及直接依赖它的模块。文档说明explain的输出是all_paths的裁剪版,只包含:根模块、从根模块通向目标模块的直接依赖、目标模块的直接依赖者、目标模块本身:

bazel mod explain @skylib1 --verbose --include_unused

文档示例输出:

<root> (my_project@1.0) ├───bazel_skylib@1.1.1 ├───rules_java@5.0.0 │ ├───rules_cc@0.0.1 │ │ └───bazel_skylib@1.1.1 ... (was 1.0.3, cause multiple_version_override) │ └───rules_proto@4.0.0 │ ├───bazel_skylib@1.1.1 ... (was 1.0.3, cause multiple_version_override) │ └───rules_cc@0.0.1 ... └───stardoc@0.5.0 ├───bazel_skylib@1.1.1 ... (was 1.0.3, cause multiple_version_override) ├╌╌rules_cc@0.0.1 │ └───bazel_skylib@1.1.1 ... (was 1.0.3, cause multiple_version_override) └╌╌rules_proto@4.0.0 ├───bazel_skylib@1.1.1 ... (was 1.0.3, cause multiple_version_override) └───rules_cc@0.0.1 ...

这里@skylib1是按MODULE.bazelrepo_name = "skylib1"起的 apparent 名。从输出可以看到:skylib1(即bazel_skylib@1.1.1)的直接依赖者是rules_cc@0.0.1rules_proto@4.0.0,二者又分别经由rules_java@5.0.0stardoc@0.5.0进入项目。

all_paths显示从--from模块到目标模块的全部依赖路径;当多条路径共享相同后缀时,只展示最短的一条。例如:

bazel mod all_paths bazel_skylib@1.1.1 --from rules_proto

文档示例输出:

<root> (my_project@1.0) └╌╌rules_proto@4.0.0 ├───bazel_skylib@1.1.1 └───rules_cc@0.0.1 └───bazel_skylib@1.1.1 ...

path语义相同,但只显示其中一条路径,适合快速拿到“一条”来源链路。

追溯版本为什么被替换:--verbose 与 --include_unused

Bazel 使用 Go 模块系统中的 Minimal Version Selection(MVS)算法选版本:取所有依赖者声明过的最高版本,且不选高于该版本的新版本(见 模块版本选择文档);MODULE.bazel中的 override 则会直接改写选择结果,且只有根模块的 override 生效。

--verbose把这类版本解析信息直接标注在图上:某模块版本在解析中变化时,输出会注明替换成的版本(或原始版本)、替换原因,以及原因来自 MVS 时请求新版本的模块:

bazel mod graph --include_unused --verbose

文档示例输出(节选):

<root> (my_project@1.0) ... ├───stardoc@0.5.0 ├───bazel_skylib@1.1.1 ... (was 1.0.3, cause multiple_version_override) ├───rules_java@5.0.0 ... (was 4.0.0, cause <root>, bazel_tools@_) ├───bazel_skylib@1.0.3 (to 1.1.1, cause multiple_version_override) │ └───platforms@0.0.4 ... └───rules_java@4.0.0 (to 5.0.0, cause <root>, bazel_tools@_) ├───bazel_skylib@1.0.3 ... (to 1.1.1, cause multiple_version_override) └───bazel_skylib@1.1.1 ... (was 1.0.3, cause multiple_version_override)

(to 1.1.1, cause multiple_version_override)(was 1.0.3, ...)成对出现:前者表示该声明版本被替换,后者表示该节点是替换后的结果。--include_unused让被换掉、解析后不再使用的模块也留在图中(标注(unused)),例如bazel_skylib@1.0.3rules_java@4.0.0,便于对照“谁被换掉了、被谁换掉”。

查看模块背后的仓库定义:show_repo 与 show_extension

show_repo显示指定仓库的定义,输出为 Starlark 规则及该规则定义所在的文件位置,例如:

bazel mod show_repo rules_cc stardoc bazel mod show_repo @jq_linux_arm64

文档示例输出:

## rules_cc@0.0.1: # <builtin> http_archive( name = "rules_cc+", urls = ["https://bcr.bazel.build/test-mirror/github.com/bazelbuild/rules_cc/releases/download/0.0.1/rules_cc-0.0.1.tar.gz", "https://github.com/bazelbuild/rules_cc/releases/download/0.0.1/rules_cc-0.0.1.tar.gz"], integrity = "sha256-Tcy/0iwN7xZMj0dFi9UODHFI89kgAs20WcKpamhJgkE=", strip_prefix = "", remote_patches = {"https://bcr.bazel.build/modules/rules_cc/0.0.1/patches/add_module_extension.patch": "sha256-g3+zmGs0YT2HKOVevZpN0Jet89Ylw90Cp9XsIAY8QqU="}, remote_patch_strip = 1, ) # Rule http_archive defined at (most recent call last): # /home/user/.cache/bazel/_bazel_user/6e893e0f5a92cc4cf5909a6e4b2770f9/external/bazel_tools/tools/build_defs/repo/http.bzl:355:31 in <toplevel>

show_repo同样适用于use_repo导入的仓库和use_repo_rule创建的仓库。涉及 apparent 名时,可以用--base_module <arg>指定相对哪个模块解释参数中的 apparent 名,例如查看rules_java上下文的@remote_java_tools

bazel mod show_repo --base_module=rules_java @remote_java_tools

输出中该仓库的 apparent 名会以##前缀单独一行显示(文档示例中为## @remote_java_tools:)。其他选项:--all_repos显示整张依赖图中所有仓库的定义;--all_visible_repos显示--base_module(默认根模块)可见的所有仓库定义。输出格式除默认text(Starlark)外,还有--output streamed_proto(length-delimitedRepositoryproto 流)与--output streamed_jsonproto(NDJSON 格式)。

要弄清一个扩展生成了哪些仓库、哪些模块通过use_repo导入了它们,用show_extension。参数形式为<arg><label_to_bzl_file>%<extension_name>,其中 label 是 repo-relative label:

bazel mod show_extension @@rules_java+5.0.0//java:extensions.bzl%toolchains

文档示例输出(节选):

<root> (my_project@1.0) ├───$@@rules_java.5.0.0//java:extensions.bzl%toolchains │ ├───remotejdk17_linux │ ├╌╌remotejdk11_linux │ ...(some lines omitted)... ├───rules_java@5.0.0 # │ └───$@@rules_java.5.0.0//java:extensions.bzl%toolchains ... │ ├───local_jdk │ ├───remote_java_tools │ ...(some lines omitted)...

输出的两部分信息:扩展生成的仓库列表(连同通过use_repo导入它们的模块),以及每个模块中该扩展的使用位置——所在文件、行号与use_repo调用的具体内容。--extension_usages <arg>[,...]可把使用列表过滤到指定模块。

如果想在依赖树上直接观察扩展的使用情况,graph还支持--extension_info,取值hidden(默认,不显示)、usages(在各模块下以$<extension>形式显示扩展)、repos(再显示use_repo导入的仓库)、all(再显示未被任何模块导入的扩展生成仓库,挂在扩展首次出现处,用点边连接);配合--extension_filter <extension>[,...]可只显示使用了指定扩展的模块及通向它们的路径,写成--extension_filter=(空列表)则等价于过滤所有扩展。

常用输出选项

以下选项只影响打印图的子命令(graphdepsall_pathspathexplain):

  • --output <mode>text(默认,人可读的树状输出)、json(JSON 对象,同样拍平为树)、graph(Graphviz dot 表示)。文档给出的 SVG 导出方式:

    bazel mod graph --output graph | dot -Tsvg > /tmp/graph.svg

    该命令需要本机已安装 Graphviz 的dot可执行程序。

  • --charset <charset>:默认utf8,也可用ascii;差异仅在于text格式画图的字符,ascii面向无法使用 Unicode 的旧平台。

定位工作流可以归纳为:graph(必要时加--from--depth)看全貌,explain/all_paths回答“某模块被谁依赖、经由哪条路径进来”,--verbose --include_unused回答“版本为什么变成这样”,最后用show_reposhow_extension查看仓库与扩展的实际定义。更多子命令参数说明见 mod 命令文档。

【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 15:46:47

让AI看着你的屏幕干活:UI-TARS 桌面自动化从安装到跑通全记录

让AI看着你的屏幕干活&#xff1a;UI-TARS 桌面自动化从安装到跑通全记录 【免费下载链接】UI-TARS-desktop The Open-Source Multimodal AI Agent Stack: Connecting Cutting-Edge AI Models and Agent Infra 项目地址: https://gitcode.com/GitHub_Trending/ui/UI-TARS-des…

作者头像 李华
网站建设 2026/9/14 15:45:21

基于SSM与Flask的校园事务自助指南服务系统设计与实现

不需要去行政楼跑三趟才知道要盖哪个章&#xff0c;也不用在公告栏前一张一张翻纸质通知——把你所在高校里所有办事流程整理成在线指南&#xff0c;按分类展示、按关键词检索、按步骤追踪&#xff0c;这就是这个校园事务自助指南服务系统在做的事。项目本身是典型的Java后端项…

作者头像 李华
网站建设 2026/9/14 15:43:29

Autoware 完整指南:从克隆仓库到跑通自动驾驶软件栈

Autoware 完整指南&#xff1a;从克隆仓库到跑通自动驾驶软件栈 【免费下载链接】autoware Autoware - the worlds leading open-source software project for autonomous driving 项目地址: https://gitcode.com/GitHub_Trending/au/autoware 想把一套完整的自动驾驶系…

作者头像 李华
网站建设 2026/9/14 15:40:52

web-print-pdf:从浏览器打印到专业PDF生成的分页与字体方案

在接触web-print-pdf之前&#xff0c;我花了大半年时间跟浏览器打印死磕&#xff1a;页面上布局好好的票据&#xff0c;一进打印预览就表头断页、边框缺线&#xff1b;font-family里明明写了中文字体&#xff0c;生成PDF后中文全部变成豆腐块&#xff1b;页码想放到页面底部居中…

作者头像 李华