SpyGlass 重复定义报错:module redefined 速查
更新时间:2026-10-23。FAQ 速查页,属于 EDA 工具排错系列。SpyGlass(Synopsys 的 RTL 静态检查工具,lint/CDC/RDC 都要先 elaborate 设计)的「重复定义」发生在读入 Verilog/VHDL 源文件之后、规则检查之前:同一个 module/entity 名被 elaborator 见到了两份完整定义,它不知道该信哪份,于是报 duplicate 并常常直接中断。这类问题的病根几乎都不在 RTL 本身,而在 filelist 组织与库管理。工具全貌见 SpyGlass RTL lint 实操,报错的相邻类型「路径都找不到」见 SpyGlass 找不到路径,「语法就过不去」见 SpyGlass 语法解析错误。
本文要回答的问题
Module 'xxx' is already defined里两个路径各是怎么进工程的?- filelist 递归 include 互相套娃,怎么快速数出同一个文件被编了几次?
- 标准单元库和项目里自写的 stub 模块同名,SpyGlass 会选哪一份?
- `include 的头文件也被列进 filelist,为什么会让模块出现两份定义?
- 用
-lib声明库与重复定义模块,本质差别在哪里?
一、报错原文与典型现象
SpyGlass 的重复定义信息进 spyglass.log 与 elaboration 报告,错误号一带常见为 ElabDuplicate/DuplicateModule 一类,关键特征是同一条报错里给出两个文件路径——第一次定义的位置和这次撞上的位置都列出来。典型文案(模块名与路径已占位):
1. 同一模块在工程里被定义两次(最常见,直接中断):
[ElabDuplicate] Module 'uart_rx' is already defined.
First definition : rtl/uart/uart_rx.v, line 12
Duplicate : legacy/uart_v1/uart_rx.v, line 9
Elaboration aborted due to duplicate module definition.2. filelist 同一文件被包含多次(Warning 级,但常是上面 Error 的前奏):
[FilelistWarn] File 'common/defines.vh' is included more than once in file list.3. 库模块与设计模块同名冲突:
[ElabDuplicate] Module 'sync_2ff' redefined: design source 'rtl/cdc/sync_2ff.v'
conflicts with library cell of the same name from 'libs/stdcells.v'.先分清两条线索:报错里给的两个路径是排查的出发点——把这两个路径记下来,后面所有动作都围绕「它们为什么同时进来」展开;Warning 级与 Error 级要分开态度——filelist 重复包含的 Warning 不一定会炸,但它提示文件组织已经有冗余,而 duplicate module 的 Error 是 elaboration 直接中止,不解决就走不到 lint/CDC 检查那一步。
二、原因速查表
| 报错现象 | 可能原因 | 处置 |
|---|---|---|
| 两个路径是同一个文件 | filelist 里该文件被列了两次(顶层与递归 -f 各一次) | filelist 去重,统一入口 |
| 两个路径分属新旧 IP 目录 | IP 两个版本的目录同时进 filelist | 只保留目标版本目录 |
| 撞名一方在 libs/ 下 | 标准单元/模型库与自写 stub 模块同名 | stub 改名或用 -lib 声明库 |
| 撞名一方是 .vh 头文件 | `include 的头文件又被直接列进 filelist | 头文件只走 `include,不进 filelist |
| 换宏定义后出现重复 | generate/`ifdef 宏让模块被条件编译出两份 | 核对宏组合,两份定义互斥化 |
| 大面积模块同时 duplicate | 递归 include 的 filelist 互相套娃成环 | 画 include 链,拆掉重复引用 |
| 报错路径含 build 输出目录 | 上次生成的中间文件被当源文件编进 | 源清单与生成物目录隔离 |
| 库文件名与设计同名但内容相同 | 同一文件经库和设计两条路各进一次 | 只保留一条进入路径 |
三、排查决策树
读这张图抓住「先按两个路径分家」:红色入口是报错本身,蓝色判定只问一句——报错里两份位置是不是同一个文件。同一路径,说明文件被编了多次,去查 filelist 组织;不同路径,说明两份内容在抢同一个模块名,去查命名冲突。两条橙色修复线分别对应组织层与命名层,紫色收尾是统一复验。
四、逐条排查展开
第一步:对报错里的两个路径做 grep 计数。 这是最快的定位动作。拿第一次定义的文件名在所有 filelist 里数出现次数:
grep -rn "uart_rx.v" filelists/命中两行以上,看是不是顶层 filelist 用 -f sub.f 递归引入了子 filelist,而子 filelist 里列过的文件又在顶层被列了一次——递归套娃是大工程最常见的重复来源。命中只有一行,说明文件本身只进了一次,问题在别处(转第二步之后)。
第二步:把 include 链画出来,拆套娃。 filelist 互相 -f 引用超过两层时,靠肉眼很难看清谁被引了几次。用一条命令把所有 -f/-F 引用捞出来:
grep -rn "^-f\|^-F" filelists/按结果从顶层往下展开,凡是同一个 .f 出现在两条链上,它名下的所有文件都会被编两次。修法是收敛入口:公共子 filelist 只被引用一次,或给 filelist 也套「守卫」——团队约定每个 .f 文件只在唯一一处被 -f,其余地方删掉引用。
第三步:同名不同文件,按三类撞名分开处置。 报错里两个路径不同、模块名相同,逐一对号:
- 库与 stub 撞名:
libs/下的标准单元仿真模型(如sync_2ff这类常见名)和项目里自写的占位 stub 同名。正确修法不是把库文件硬编两遍,而是用 SpyGlass 的库声明机制:在工程约束(project 文件或命令行)里用-lib/库选项把标准单元声明为库,库单元只在设计里没定义时才被引用,天然避开重复判定;自写 stub 若本来就是临时占位,直接改名更干净。 - IP 新旧版本撞名:
ip/uart_v1/与ip/uart_v2/两个目录同时进 filelist,两边都有uart_rx。处置是版本收敛——filelist 只挂目标版本目录,老版本从构建里整体摘除,而不是逐文件挑。 - 头文件被直编:
defines.vh一类文件本应由 RTL 里include 引入,有人又把它加进 filelist。如果该头文件里恰好带模块定义(或经它include 了带模块的文件),模块就出现两份。纪律是:只含宏/参数的头文件不进 filelist,filelist 只列实现文件。
第四步:宏导致的条件编译双份,核对宏组合。 有些重复只在特定宏组合下出现:比如同一模块在 ifdef FAST_SIM 与 else 两个分支里各写了一份定义,而某次构建两个宏同时被打开,两份都生效。判据是报错里两个路径指向同一文件的相邻 ifdef 分支,或两个文件被同一组宏同时选中。处置是把两份定义改成**互斥**(用 ifndef 守卫或收敛为一份定义加参数化),并在构建脚本里固定宏组合,不允许两个互斥宏同时打开。
第五步:隔离生成物目录。 报错路径若落在 build/、gen/ 一类输出目录下,说明上次运行生成的中间文件(展开后的预处理文件、自动生成的 wrapper)被当成源文件编进了工程,与原始 RTL 撞名。修法是 filelist 只锚定源码根目录,生成物目录进 .gitignore 并在每次构建前清空,杜绝「源一份、生成一份」同时可见。
第六步:干净环境复验。 修完重跑 elaboration(spyglass 命令行加 -batch 跑 goal 前的读入阶段即可),确认 log 里 duplicate 类 Error 清零、filelist 重复 Warning 也消失。Warning 留着不处理,等于给下一次套娃复发留了门。
五、预防与纪律
- filelist 单一入口:顶层只
-f一次公共子清单,团队约定每个.f只允许被引用一处,review 时检查新增引用。 - 库走库声明,不硬编:标准单元、仿真模型统一用
-lib/库选项声明,禁止把库文件与设计 RTL 混列在同一张 filelist。 - 头文件不进 filelist:
.vh/.svh只经include 引入;filelist 只列.v/.sv` 实现文件,二者分工写进工程 README。 - IP 版本单点锚定:filelist 里 IP 路径统一走一个版本变量(如
IP_VER),切换版本改变量,不允许两个版本目录同时出现。 - CI 加一道重名预检:提交前跑
grep -h "^module" $(cat filelists/top.f) | sort | uniq -d,有输出即拦截——把重复挡在 SpyGlass 启动之前。
这一篇在知识体系里的位置
本篇是 EDA 排错速查簇的一员,同工具相邻问题见 SpyGlass 找不到路径 与 SpyGlass 语法解析错误,工具机制背景见 SpyGlass RTL lint 实操,跨工具语义对照见静态时序侧的 PrimeTime 重复定义速查。
一句话总结
SpyGlass 报「重复定义」先读报错里的两个路径:同一路径是 filelist 把同一文件编了多次,用 grep -rn 计数、展开 -f 链拆递归套娃;不同路径是同名撞车,按「库与 stub 撞名走 -lib 库声明、IP 新旧版本只留一版、头文件不进 filelist、宏双份改互斥」分类处置;长期靠单一 filelist 入口、库声明纪律与 CI 重名预检把重复挡在启动之前。