☰
Verible 源码索引指南:用 Kythe 为 Verible 及任意 Bazel 项目构建离线交叉引用索引
2026/10/14 17:02:57 网站建设 项目流程
  • 开发工具
  • Lint
  • 静态分析
  • 硬件开发

【免费下载链接】verible

Verible is a suite of SystemVerilog developer tools, including a parser, style-linter, formatter and language server

项目地址:https://gitcode.com/gh_mirrors/ve/verible
点击查看免费下载

本文基于仓库中的 doc/indexing.md 展开,系统讲解如何用 Google 开源的 Kythe 工具链为 Verible 的 C++ 源码建立可搜索、可导航的交叉引用索引:从安装 Kythe 快照、配置vnames.json、用 Bazel action listener 抽取 kzip 编译事实,到索引生成 GraphStore、产出 serving table 并启动 Web UI 查看代码跳转,全程可离线复现。读完后你可以独立为 Verible 或任何 Bazel 项目搭建一套本地代码索引服务,并顺带了解 Verible 如何为 SystemVerilog 源码本身抽取 Kythe 事实。

两种场景:在线索引与离线自建

doc/indexing.md 开篇即给出一个实用结论:如果你只是想在浏览器中搜索、跳转 Verible 源码,官方索引已经部署在 Google 开源代码检索服务的verible/verible页面(cs.opensource.google),无需自己索引。只有当你需要离线环境下工作、或想深入理解索引原理时,才需要按本文手动构建。

文档还给出一个更轻量的替代方案:如果你只是想本地编辑代码、获得 IDE 的语言感知,不需要完整索引,直接调用 .github/bin/make-compilation-db.sh 生成编译数据库即可。该脚本的实际做法(见脚本第 31–42 行)是先用 Bazel 构建所有会生成文件的 target,再用bant compile-flags -o compile_flags.txt生成一份比compile_commands.json更简单、对各类工具更易消化的编译标志文件,并额外补上 flex 生成的FlexLexer.h头文件搜索路径。

提示:以下手动索引步骤不仅适用于 Verible,文档明确说明其可以泛化到任意 Bazel 构建的项目。

理解 Kythe 的核心数据结构(仓库内证据)

在动手前,先弄懂索引管线里出现的几个名词。Verible 仓库在 third_party/proto/kythe/ 中直接内嵌了 Kythe 的两份 proto 定义(storage.proto与analysis.proto),它们是理解整条管线的最佳材料:

  • VName(向量名):定义于 storage.proto,由signature、corpus、root、path、language五个字符串字段组成,是 Kythe 标识代码实体的最小坐标系统。例如某个 Verible 函数节点的路径通常是它相对仓库根目录的相对路径。
  • Entry(条目):定义于 storage.proto,将一个事实(fact_name/fact_value)关联到图对象上;带edge_kind和target时表示一条边(如ref、def),这就是“交叉引用”的数据形态。索引器输出的本质就是一串 Entry 流。
  • CompilationUnit(编译单元):定义于 analysis.proto,描述一次编译的输入文件(required_input)、编译参数(argument)、源文件列表(source_file)等,是 C++ 提取器(extractor)的输入单元,也是 kzip 的基本载体。

后文的kzip、graphstore、serving table分别对应这条管线中“提取产物 → 索引存储 → 可服务数据”三个阶段。

第一步:初始化 Kythe(安装工具链与 Web 前端)

文档给出的安装方式是下载 Kythe 官方发布的快照包(release tarball,含预编译二进制),解压并移动到/opt/kythe:

tar xzf kythe-v*.tar.gz rm -rf /opt/kythe mv kythe-v*/ /opt/kythe

这与仓库 CI 脚本 .github/bin/install-kythe.sh 的做法一致:CI 根据KYTHE_VERSION变量从 Kythe 官方发布页下载对应版本的kythe-*.tar.gz并解压到kythe-bin/目录;若版本设为master则改为下载源码 zip(注意 top-of-tree 源码包不含预编译二进制,自行构建 Kythe 本身会带来极其庞大的依赖,如 LLVM,CI 脚本中也特意标注了这一点)。

为了让 Web UI 能正常渲染页面,还需要构建 Kythe 的 Web 前端资源,并把静态文件复制进/opt/kythe/web/ui:

bazel build //kythe/web/ui mkdir -p /opt/kythe/web/ui cp -r bazel-bin/kythe/web/ui/resources/public/* /opt/kythe/web/ui cp -r kythe/web/ui/resources/public/* /opt/kythe/web/ui chmod -R 755 /opt/kythe/web/ui

这里bazel build //kythe/web/ui需要在克隆下来的 Kythe 源码树内执行。后续所有http_server启动命令都依赖/opt/kythe/web/ui中的静态资源(见 kythe-browse.sh 第 56 行的public_resources参数)。

vnames.json:可选的路径重命名配置

doc/indexing.md 提到vnames.json文件用于在抽取过程中重命名文件路径(通过 RE2 模式匹配输入路径,再用模板生成新的 VName,其 proto 定义见 storage.proto 的VNameRewriteRule)。文档同时说明:对 Verible 而言不需要重命名,但你可以自行添加合适的重命名规则。

仓库根目录的 vnames.json 当前内容就是一个空数组[],印证了“默认不启用任何重命名”这一事实。如果你的项目源码路径与期望的索引路径不一致(例如源码放在子目录或 vendored 位置),就可以在这里添加规则。

第二步:运行提取器,为 Verible 抽取 kzip

抽取阶段利用 Bazel 的--experimental_action_listener机制:在正常构建/测试的同时,由 Kythe 的 C/C++ 提取器旁路记录每个目标的编译信息并打包成 kzip。文档给出的命令是:

# run on all targets bazel test --experimental_action_listener=:extract_cxx //... # run on specific target (e.g. some cc_binary or cc_library) bazel test --experimental_action_listener=:extract_cxx //verible/verilog/analysis:default_rules

抽取产物是 kzip 文件,输出到bazel-out/local-fastbuild/extra_actions/extractor目录,每个 target 一个 kzip:

find -L bazel-out -name '*cxx.kzip'

从源码结构看有一点需要注意:当前仓库顶层 BUILD 文件中并未定义:extract_cxx这个 listener 目标;实际的 CI 流程(.github/bin/run-kythe.sh 第 40–58 行)是通过--override_repository把下载好的 Kythe 发布目录注入为kythe_release仓库,并使用其中自带的extract_kzip_cxx、extract_kzip_protobuf两个 listener,同时用--define="kythe_corpus=github.com/chipsalliance/verible"指定 corpus 名称,最后用kzip merge把所有 kzip 合并成单一归档作为构建产物。换言之,文档中的:extract_cxx写法对应于在顶层 BUILD 中自行接入 Kythe listener 的用法;如果你的 Bazel 版本或 Kythe 版本行为有差异,可以参照 CI 脚本的@kythe_release//:extract_kzip_cxx方式。两种写法的差异也提示:--experimental_action_listener属于实验性机制,具体可用目标名取决于你引入的 Kythe 版本。

第三步:索引 kzip,生成 GraphStore

拿到 kzip 后,逐个用 Kythe 的 C++ 索引器把其中的编译事实解析成 Entry 流,再写入 LevelDB 后端的 GraphStore:

for i in $(find -L bazel-out -name '*cxx.kzip'); do # Indexing C++ compilations /opt/kythe/indexers/cxx_indexer --ignore_unimplemented "$i" > entries # Write entry stream into a GraphStore /opt/kythe/tools/write_entries --graphstore leveldb:.kythe_graphstore < entries done
  • cxx_indexer --ignore_unimplemented:将单个 kzip 中的编译单元索引为事实流;--ignore_unimplemented用于跳过尚未实现的语言特性而不至于整体失败。
  • write_entries --graphstore leveldb:.kythe_graphstore:把标准输入的事实流持久化到本地 LevelDB 数据库(.kythe_graphstore目录)。

这一步正是把 analysis.proto 中描述的 CompilationUnit 转译为 storage.proto 中 Entry 的过程,产出的.kythe_graphstore是可搜索的代码图存储。

第四步:生成 Serving Table

GraphStore 不能直接被前端服务,需要进一步转换为 serving table:

# Generate corresponding serving tables /opt/kythe/tools/write_tables --graphstore .kythe_graphstore --out .kythe_serving

write_tables读取 GraphStore 输出到.kythe_serving目录,形成面向查询优化的表结构。至此数据侧工作全部完成,整条链路的形态是:

bazel 构建 + extractor → *.kzip → cxx_indexer + write_entries → .kythe_graphstore → write_tables → .kythe_serving → http_server → Web UI

第五步:启动 Web UI 查看交叉引用

最后运行 Kythe 的 HTTP 服务器即可在浏览器中查看定义跳转与交叉引用:

# --listen localhost:8080 allows access from only this machine; change to # --listen 0.0.0.0:8080 to allow access from any machine /opt/kythe/tools/http_server \ --public_resources /opt/kythe/web/ui \ --listen localhost:8080 \ --serving_table .kythe_serving
  • --public_resources /opt/kythe/web/ui:指向第一步构建并复制的 Web 前端静态资源;
  • --listen localhost:8080:默认只允许本机访问;改为0.0.0.0:8080即可让局域网内其他机器访问。

延伸:Verible 如何索引 SystemVerilog 源码本身

值得一提的是,Kythe 官方提取器覆盖 C++,而 Verible 作为 SystemVerilog 工具集,还内置了自己的索引器:verible/verilog/tools/kythe/ 下的verible-verilog-kythe-extractor从 SystemVerilog 源文件集合中抽取符合 Kythe schema 的索引事实(依赖 verible/verilog/tools/kythe/BUILD 中定义的kythe-facts、indexing-facts-tree、scope-resolver等库,并直接依赖 third_party/proto/kythe 中的 proto 库)。其命令行参数(见 README)包括:

verible-verilog-kythe-extractor [options] --file_list_path FILE --printextraction 是否打印中间层抽取出的索引事实树,默认 false --print_kythe_facts 输出格式:json(默认)或 proto --file_list_path SystemVerilog 文件列表路径(文件应按定义依赖顺序排列) --file_list_root 文件列表中相对路径的前缀(绝对位置),默认为调用位置 --include_dir_paths 逗号分隔的 include 搜索目录,顺序敏感,找到即停 --output_path 输出文件路径,为空或 "-" 时写入 stdout

仓库根目录的 kythe-browse.sh 就是这条链路的端到端封装,用法为kythe-browse.sh PATH DIR INCLUDE_DIRs(PATH 为文件列表,DIR 为文件列表根,INCLUDE_DIRs 为 include 目录),内部流程(第 44–57 行)是:

  1. bazel build -c opt //verible/verilog/tools/kythe:all构建提取器;
  2. 运行verible-verilog-kythe-extractor --file_list_path ... --file_list_root ... --print_kythe_facts json --include_dir_paths ...输出 JSON 事实到./kythe-out/entries;
  3. 用 Kythe 的entrystream --read_format=json | write_entries -graphstore ./kythe-out/graphstore写入 GraphStore;
  4. write_tables -graphstore ./kythe-out/graphstore -out=./kythe-out/tables生成 serving table;
  5. http_server -serving_table ./kythe-out/tables -public_resources=/opt/kythe/web/ui -listen=localhost:${BROWSE_PORT}启动浏览界面,端口由环境变量BROWSE_PORT(默认 8080)控制。

该脚本假定从 Verible 项目根目录运行、Kythe 二进制安装在/opt/kythe(可用预构建 release 二进制,或自建后修改public_resources指向)。

适用前提与小结

  • 本文步骤基于仓库当前 doc/indexing.md 的流程,前提是 Kythe 快照安装在/opt/kythe,且使用 Bazel 构建的 Verible 源码树;--experimental_action_listener的行为与可用目标名可能随 Bazel / Kythe 版本演进,仓库 CI(run-kythe.sh)提供了当前实际采用的接入方式作为参照。
  • 若目标只是本地编辑/IDE 支持,优先走 make-compilation-db.sh 生成compile_flags.txt,成本远低于完整索引。
  • 整条管线(kzip → cxx_indexer → write_entries → write_tables → http_server)与具体项目无关,替换掉 Bazel 构建对象即可复用到其他 Bazel 项目;索引 SystemVerilog 则额外需要 Verible 自带的verible-verilog-kythe-extractor。
  • 开发工具
  • Lint
  • 静态分析
  • 硬件开发

【免费下载链接】verible

Verible is a suite of SystemVerilog developer tools, including a parser, style-linter, formatter and language server

项目地址:https://gitcode.com/gh_mirrors/ve/verible
点击查看免费下载

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询