Makefile关键语法示例
Makefile关键语法示例
摘要:本文50个Makefile关键语法示例,适用于UVM SoC验证环境:
基础语法和变量
# 1. 变量定义
TOP_DIR = $(PWD)
UVM_HOME = /tools/uvm-1.2# 2. 变量引用
SIM_DIR = $(TOP_DIR)/sim# 3. 条件赋值(仅在未定义时赋值)
SIMULATOR ?= vcs# 4. 立即赋值 vs 延迟赋值
IMMEDIATE := $(shell date)
DEFERRED = $(shell date)# 5. 追加赋值
VLOG_OPTS = +define+UVM_NO_DPI
VLOG_OPTS += -sverilog# 6. 多行变量
define RUN_TESTcd $(SIM_DIR) && \./simv +UVM_TESTNAME=$(TEST)
endef
目标和依赖
# 7. 基本规则
compile: rtl testbenchvcs -f filelist.f# 8. 伪目标
.PHONY: clean run all# 9. 多目标规则
rtl testbench: directories@echo "Building $@"# 10. 模式规则
%.sv: %.sv.templatesed 's/@@VERSION@@/$(VERSION)/g' $< > $@
递归调用
# 11. 递归Make
subsystem:$(MAKE) -C sub_blocks all# 12. 传递变量到子Make
export UVM_HOME
child:$(MAKE) -C testbench compile# 13. 并行递归
SUBDIRS = rtl dv sw
$(SUBDIRS):$(MAKE) -C $@ all# 14. 条件递归
ifdef RUN_SUBSYS$(MAKE) -C subsystem_tb run
endif
文件操作
# 15. 创建目录
$(SIM_DIR):@mkdir -p $@# 16. 生成文件列表
filelist.f: $(wildcard rtl/*.sv)@echo "// Auto-generated" > $@@find rtl -name "*.sv" >> $@# 17. 批量文件转换
SVFILES = $(patsubst %.v,%.sv,$(wildcard *.v))# 18. 文件存在性检查
ifeq ($(wildcard config.mk),)$(error config.mk not found!)
endif
函数使用
# 19. shell函数
GIT_HASH = $(shell git rev-parse --short HEAD)# 20. subst函数
NEW_PATH = $(subst /old/,/new/,$(PATH))# 21. filter函数
SV_ONLY = $(filter %.sv,$(ALL_FILES))# 22. foreach函数
TESTS = test1 test2 test3
RUN_ALL = $(foreach test,$(TESTS),run_$(test))# 23. call函数
define compile_blockvlog -work $(1) $(2)
endef
$(call compile_block,work_lib,rtl/*.sv)
条件判断
# 24. ifeq条件
ifeq ($(SIMULATOR),vcs)SIM_OPTS = -debug_all
elseSIM_OPTS = -gui
endif# 25. ifdef条件
ifdef COVERAGEVLOG_OPTS += -cm line+cond+fsm+branch
endif# 26. 多条件判断
ifneq ($(SIMULATOR),)
ifneq ($(TEST),)RUN_CMD = ./run_sim.sh
endif
endif
高级模式规则
# 27. 双后缀规则
.sv.o:sv2c $< -o $@# 28. 静态模式规则
OBJS = foo.o bar.o
$(OBJS): %.o: %.cgcc -c $< -o $@# 29. 次要扩展
.SECONDEXPANSION:
$(TESTS): test_%: $$(wildcard %_*.sv)compile_test $@
特殊变量
# 30. 自动变量
%.log: %.test@echo "Running $<"./$< > $@@echo "Output saved to $@"# 31. 目标相关变量
debug: CFLAGS += -g
debug: all# 32. 模式特定变量
%.tb.sv: VLOG_OPTS += +define+TESTBENCH
Include和依赖生成
# 33. include指令
-include config.mk# 34. 自动依赖生成
%.d: %.sv@vlog -M -Mp $@ $<# 35. sinclude(静默include)
sinclude $(DEPS)
实用技巧
# 36. 时间戳
TIMESTAMP = $(shell date +%Y%m%d_%H%M%S)
LOG_FILE = sim_$(TIMESTAMP).log# 37. 检查工具存在
VLOG := $(shell which vlog)
ifeq ($(VLOG),)$(error vlog not found in PATH)
endif# 38. 多级目录创建
DIRS = $(SIM_DIR)/logs $(SIM_DIR)/waves $(SIM_DIR)/coverage
$(DIRS):@mkdir -p $@# 39. 参数化编译
compile_%:vlog +define+CONFIG_$* rtl/config_$*.sv
UVM特定应用
# 40. UVM测试运行
run_%: compile./simv +UVM_TESTNAME=$*_test \+UVM_VERBOSITY=UVM_MEDIUM# 41. 覆盖率合并
merge_cov:urg -dir sim/*.vdb -report coverage.html# 42. 波形控制
ifdef DUMP_WAVESIM_OPTS += +DUMP_WAVE=$(WAVE_FORMAT)
endif# 43. 种子管理
SEED ?= $(shell echo $$RANDOM)
run: ./simv +ntb_random_seed=$(SEED)
错误处理
# 44. 忽略错误
clean:-rm -rf $(SIM_DIR)/*# 45. 错误检查
check_env:@test -n "$(UVM_HOME)" || \(echo "Error: UVM_HOME not set" && exit 1)
并行和性能
# 46. 并行执行
.PARALLEL: $(TESTS)
all: $(TESTS)# 47. 作业服务器
.NOTPARALLEL: regression
调试和输出
# 48. 静默规则
.SILENT: clean# 49. 调试打印
debug_vars:$(info TOP_DIR = $(TOP_DIR))$(info SIMULATOR = $(SIMULATOR))$(warning This is a warning)# 50. 完整示例:多级Makefile系统
# 顶层Makefile
BLOCKS = cpu dma pcie
.PHONY: all $(BLOCKS)
all: $(BLOCKS)@echo "All blocks compiled"$(BLOCKS):@echo "========== Building $@ =========="$(MAKE) -C blocks/$@ all TOP=$(TOP_DIR)regression: all@for test in $(TESTS); do \$(MAKE) run_$$test || exit 1; \doneclean:@for dir in $(BLOCKS); do \$(MAKE) -C blocks/$$dir clean; \done
这些例子涵盖了UVM SoC验证中常用的Makefile技巧,包括递归构建、自动依赖、条件编译、并行执行等关键功能。
如何使用Makefile实现UVM测试用例的批量运行和结果收集?能否提供一个更复杂的Makefile例子,包含多个子模块和条件编译?
可以通过在顶层 Makefile 中定义一组 Testcase、循环运行每个 testcase,并把日志分目录保存,最后 grep 出 PASS/FAIL,再汇总成 CSV 报表。下面给出一个较复杂的示例,涵盖:
- 多个子模块(blocks/cpu, blocks/dma, blocks/pcie)的递归 build
- 条件编译开关(COVERAGE、WAVE)
- test 批量运行(pattern rule +run_%)
- 日志分目录管理
- PASS/FAIL 收集并生成 CSV 报表
# Top-level Makefile for UVM SoC Verification
# Usage:
# make # build + run all tests + report
# make COVERAGE=1 # enable coverage
# make WAVE=1 # enable waveform dump
# make clean#—— 1. 配置与变量 ——#
SIM_CMD ?= vcs
SIM_FLAGS ?= -full64 -quiet
ifeq ($(COVERAGE),1)
SIM_FLAGS += -cm line+cond+fsm+branch
endif
ifeq ($(WAVE),1)
SIM_FLAGS += +vpd
endif# 子模块列表(递归 build)
BLOCKS := cpu dma pcie# 要跑的 UVM 测试用例
TESTS := basic smoke stress# 日志与结果目录
LOG_DIR := logs
PASS_LOG := $(LOG_DIR)/pass.log
FAIL_LOG := $(LOG_DIR)/fail.log
RESULT_CSV := $(LOG_DIR)/results.csv#—— 2. 伪目标定义 ——#
.PHONY: all build run_tests report clean help $(BLOCKS) $(addprefix run_,$(TESTS))
.DEFAULT_GOAL := all#—— 3. 默认流程 ——#
all: build run_tests report#—— 4. 子模块递归 build ——#
build: $(BLOCKS)
$(BLOCKS):@echo "[BUILD] block=$@"$(MAKE) -C blocks/$@ build#—— 5. 批量运行测试 ——#
run_tests: clean-logs $(addprefix run_,$(TESTS))clean-logs:@rm -rf $(LOG_DIR)@mkdir -p $(LOG_DIR)@> $(PASS_LOG) > $(FAIL_LOG)# pattern rule: run_<test>
run_%: ## Run UVM test $*@echo "[RUN ] test=$*"@mkdir -p $(LOG_DIR)/$*@$(SIM_CMD) $(SIM_FLAGS) \-o simv_$* +UVM_TESTNAME=$* +UVM_VERBOSITY=UVM_MEDIUM \2>&1 | tee $(LOG_DIR)/$*/run.log || true@grep -E "UVM_FATAL|UVM_ERROR" $(LOG_DIR)/$*/run.log \&& echo "$*:FAIL" >> $(FAIL_LOG) \|| echo "$*:PASS" >> $(PASS_LOG)#—— 6. 生成汇总报表 ——#
report: run_tests@echo "test,result" > $(RESULT_CSV)@sed 's/:PASS/,PASS/' $(PASS_LOG) >> $(RESULT_CSV)@sed 's/:FAIL/,FAIL/' $(FAIL_LOG) >> $(RESULT_CSV)@echo "[REPORT] Generated: $(RESULT_CSV)"#—— 7. 清理 ——#
clean:@echo "[CLEAN] all"@rm -rf simv_* $(LOG_DIR)@for d in $(BLOCKS); do \$(MAKE) -C blocks/$$d clean; \done#—— 8. 帮助信息 ——#
help:@echo "Usage:"@echo " make [COVERAGE=1] [WAVE=1] # build, run all tests, gen report"@echo " make run_<testname> # run single test"@echo " make clean # clean all artifacts"
说明:
- 通过
SIM_FLAGS
的条件追加实现覆盖率和波形开关。 build
目标依赖$(BLOCKS)
,对每个子目录递归调用子 Makefile。- 用
run_%
模式规则批量跑basic
、smoke
、stress
,日志分别保存在logs/basic/run.log
等目录下。 - grep 日志中
UVM_FATAL
或UVM_ERROR
来判断失败,并分别写入pass.log
/fail.log
。 report
目标将结果拼成一个标准 CSV (test,result
) 方便后续自动化处理或 Jenkins 报告。
这个示例可以根据项目需求扩展更多子模块、更多测试、或加入并行执行(.PARALLEL:
)等特性。