Makefile可以做什么?
Makefile可以根據指定的依賴規則和文件是否有修改來執行命令。常用來編譯軟件源代碼,只需要重新編譯修改過的文件,使得編譯速度大大加快。
Makefile的基本格式
目標:依賴 命令
目標是要生成的結果,依賴是生成結果需要的源文件和上一步驟的結果,命令是當目標不存在或者依賴更新時執行的命令。注意命令前必須用tab來縮進,不可以用空格。
示例一:
simv: tb.sv dut.v vcs -full64 -sverilog tb.sv dut.v
這個例子中,simv是目標,是我們要生成的仿真執行文件。tb.sv和dut.v是依賴,執行命令前會先檢查tb.sv和dut.v是否存在,以及是否有修改。當依賴文件有修改時,或者目標不存在時,則執行命令vcs -full64 -sverilog tb.sv dut.v來生成simv。
偽目標
有時候目標并不是真實要生成的文件,比如我們要用Makefile調用simv來仿真,并不存在一個目標文件,這種情況我們稱之為偽目標PHONY。
示例二:
sim: simv ./simv -xxx
這個例子中,sim并不是要生成的結果文件,而只是我們給操作起的一個名字。由于偽目標總是不存在,所以命令也一定會重新執行,即使simv沒有修改。
我們常常在Makefile的開頭來用.PHONY顯式指明偽目標。
示例三:
.PHONY: simsim: simv ./simv -xxx
這樣,我們在terminal里就可以用make sim來調用仿真命令。
默認目標
如果我們只是敲make(后面不跟目標),那么將調用Makefile里的第一個目標。那么我們為了防止出錯通常把第一個目標定義成all(執行完整的流程)或者help(顯示幫助菜單)。我更傾向于后者,可以幫助我們回憶如何使用Makefile腳本。
示例四:
.PHONY: help simhelp: echo "make help" echo "make simv to compile" echo "make sim to run simulation"simv: tb.sv dut.v vcs -full64 -sverilog tb.sv dut.vsim: ./simv -xxx
這樣,當我們不記得如何使用Makefile的時候,直接敲make就會有使用幫助菜單。另外,我們還可以看到,一個目標后面可以執行多條命令,比如這里的三條echo命令。
隱藏回顯
在執行命令前,make會先回顯命令(就是打印出命令)。上面的make help會輸出:
echo "make help"make helpecho "make simv to compile"make simv to compileecho "make sim to run simulation"make sim to run simulation
看起來有點重復了。在命令前加@可以關閉回顯示,這正是我們需要的。改進過的Makefile如示例五。
示例五:
.PHONY: helphelp: @echo "make help" @echo "make simv to compile" @echo "make sim to run simulation"
makefile內定義變量
當源文件比較多,且常需要增減,我們可以把依賴定義成一個變量,放成文件開頭,如下。
示例六:
tbfile := tb.sv env_pkg.sv test_pkg.svrtlfile := dut.v a.v b.v c.vsimv: $(tbfile) $(rtlfile) vcs -full64 -sverilog $(tbfile) $(rtlfile)
當要增減文件時,只需要修改文件開頭即可。
調用shell命令
如果rtl文件太多,還可以在Makefile里調用shell命令來幫助生成。如下面的例子:
示例七:
tbfile := $(shell ls *.sv)rtlfile := $(shell find rtl -name "*.v")simv: $(tbfile) $(rtlfile) vcs -full64 -sverilog $(tbfile) $(rtlfile)
例七中的tb和rtl文件寫兩遍,是不是有點麻煩。我們最好能簡化一下。在Makefile中有幾個特殊變量,如$@表示目標,$^表示依賴。所以示例七中的命令可以簡化成:
simv: $(tbfile) $(rtlfile)vcs -full64 -sverilog $^
學到到這里你已經可以寫出大部分的Makefile腳本了。
為makefile增加選項
但我們還需要進一步學習兩個重要功能:選項和目錄遞歸。
我們常需要在仿真時提供一些選項,比如testcase名,是否是post仿真,是否要dump波形。那么怎么實現呢?其實Makefile允許從命令行提供額外的變量,格式為OPTION=value。如下面的例子,假設有三個選項,TC、POST、DUMP:
示例八:
ifeq ($(POST),1)SRC := "netlist.v"else SRC := "rtl.v"endififeq ($(DUMP),1) DUMP_DEF := "+define+DUMP"else DUMP_DEF := ""endifsim: @echo "vcs -full64 -sverilog $(SRC) $(DUMP_DEF) +UVM_TESTNAME=$(TC)"
那么,使用時就可以通過命令行控制選項開關:
make sim TC=basic_testmake sim TC=basic_test POST=1make sim TC=basic_test DUMP=1make sim TC=basic_test POST=1 DUMP=1
makefile的大殺器:目錄遞歸
另一個重要功能是目錄遞歸,目錄遞歸有一個典型的應用:make clean。在頂層目錄里make clean時,將會自動調用子目錄的make clean。這個怎么實現呢?看下面的例子:
示例九:
cat ./Makefileclean: rm -f *~ make -C a clean make -C b cleancat ./a/Makefileclean: rm -f *~cat ./b/Makefileclean: rm -f *~ make -C c cleancat ./b/c/Makefileclean: rm -f *~
我們看到一個make -C subdir clean,就是說可以通過-C來把目標clean傳遞給子目錄,相當于在Makefile里調用了另一個Makefile。這樣在頂到make clean時,將自動遞歸到所有的子目錄。
Makefile的引用與復用
最后還有一點,我們也會經常遇到,把共用的Makefile腳本寫到common.mk,然后再include common.mk,這樣可以讓Makefile看起來更簡潔。
示例十
# ../common/common.mkbasic: @ echo "call basic"# Makefiledep := $(shell depth)all: basic @ echo "call all"include $(dep)/common/common.mk
如果被include的文件使用相對路徑的話,必須相對敲make命令的目錄。當然也可以像這個示例一樣,先獲取項目根目錄,然后再用變量來引用路徑。這樣比較易于移植。
與IC Flow的聯系
到這里,學了這么多,你已經可以寫一些復雜的Makefile了。但重在應用,在IC設計里,我們常常用Makefile串起多個工具,實現完整的流程。下面是一個啟發型的例子。
示例十一:
.PHONY: help clean rtl lint sim syn lec pr pt lvshelp: @echo "make help"clean: rm -rf *~ *.log *.fsdb csrc simv* ... make -C xxx cleanrtl: python3 ...lint: sg_shell/nLint ...sim: vcs/irun ...syn: dc_shell -64bit -topographical -f run_syn.tcl | tee log/syn.loglec: fm_shell/lec ...pt: pt_shell ...pr: innovus/icc ...lvs: calibre ...
習題:
根據自己公司的情況,把示例十一補充完整。
-
Linux
+關注
關注
87文章
11230瀏覽量
208937 -
Makefile
+關注
關注
1文章
125瀏覽量
19163
發布評論請先 登錄
相關推薦
評論