Makefile常用调试方法
?
?
轉(zhuǎn)載自 陳皓《跟我一起寫 Makefile》《GNU Make項目管理》
?
GNU make 提供了若干可以協(xié)助調(diào)試的內(nèi)置函數(shù)以及命令行選項。
1、warning函數(shù)
$(warning string)函數(shù)可以放在makefile 中的任何地方,執(zhí)行到該函數(shù)時,會將string輸出,方便定位make執(zhí)行到哪個位置。warning函數(shù)可以放在makefile 中的任何地方:開始的位置、工作目標(biāo)或必要條件列表中以及命令腳本中。這讓你能夠在最方便查看變量的地方輸出變量的值。例如:
| $(warning A top-level warning) ? FOO := $(warning Right-hand side of a simple variable)bar BAZ = $(warning Right-hand side of a recursive variable)boo ? $(warning A target)target: $(warning In a prerequisite list)makefile $(BAZ) $(warning In a command script) ls $(BAZ): |
這會產(chǎn)生如下的輸出:
| $ make makefile:1: A top-level warning makefile:2: Right-hand side of a simple variable makefile:5: A target makefile:5: In a prerequisite list makefile:5: Right-hand side of a recursive variable makefile:8: Right-hand side of a recursive variable makefile:6: In a command script ls makefile |
注意,warning函數(shù)的求值方式是按照make標(biāo)準(zhǔn)的立即和延后求值算法。雖然對BAZ的賦值動作中包含了一個warning函數(shù),但是直到BAZ在必要條件列表中被求值后,這個信息才會被輸出來。
?
2.命令行選項
有時候,我們不想讓我們的makefile中的規(guī)則執(zhí)行起來,我們只想檢查一下我們的命令,或是執(zhí)行的序列。于是我們可以使用make命令的下述參數(shù):
“-n” “--just-print” “--dry-run” “--recon” 不執(zhí)行參數(shù),這些參數(shù)只是打印命令,不管目標(biāo)是否更新,把規(guī)則和連帶規(guī)則下的命令打印出來,但不執(zhí)行,這些參數(shù)對于我們調(diào)試makefile很有用處。
“-t” “--touch” 這個參數(shù)的意思就是把目標(biāo)文件的時間更新,但不更改目標(biāo)文件。也就是說,make假裝編譯目標(biāo),但不是真正的編譯目標(biāo),只是把目標(biāo)變成已編譯過的狀態(tài)。
“-q” “--question” 這個參數(shù)的行為是找目標(biāo)的意思,也就是說,如果目標(biāo)存在,那么其什么也不會輸出,當(dāng)然也不會執(zhí)行編譯,如果目標(biāo)不存在,其會打印出一條出錯信息。
“-W <file>;” “--what-if=<file>;” “--assume-new=<file>;” “--new-file=<file>;” 這個參數(shù)需要指定一個文件。一般是是源文件(或依賴文件),Make會根據(jù)規(guī)則推導(dǎo)來運行依賴于這個文件的命令,一般來說,可以和“-n”參數(shù)一同使用,來查看這個依賴文件所發(fā)生的規(guī)則命令。
三個最適合用來調(diào)試的命令行選項:
--just-print(-n)
--print-database(-p)
--warn-undefined-variables
2.1 --just-print
在一個新的makefile 工作目標(biāo)上,我所做的第一個測試就是以--just-print(-n)選項來調(diào)用make。這會使得make讀進(jìn)makefile并且輸出它更新工作目標(biāo)時將會執(zhí)行的命令,但是不會真的執(zhí)行它們。GNU make有一個方便的功能,就是允許你為將被輸出的命令標(biāo)上安靜模式修飾符(@)。
這個選項被假設(shè)可以抑制所有命令的執(zhí)行動作,然而這只在特定的狀況下為真。實際上,你必須小心以對。盡管make不會運行命令腳本,但是在立即的語境之中,它會對shell函數(shù)
調(diào)用進(jìn)行求值動作。例如:
?
正如我們之前所見,_MKDIRS 簡單變量的目的是觸發(fā)必要目錄的創(chuàng)建動作。如果這個Makefile 是以--just-print 選項的方式運行的,那么當(dāng)make 讀進(jìn)Makefile 時,shell命令將會一如往常般被執(zhí)行。然后,make 將會輸出(但不會執(zhí)行)更新$(objects)文件列表所需要進(jìn)行的每個編譯命令。
2.2 --print-data-base
--print-data-base(-p)是另一個你常會用到的選項。它會運行Makefile,顯示GNU版權(quán)信息以及make 所運行的命令,然后輸出它的內(nèi)部數(shù)據(jù)庫。數(shù)據(jù)庫里的數(shù)據(jù)將會依種類劃分成以下幾個組:variables、directories、implicit rules、pattern-specific variables、files(explicit rules)以及vpath earch path。如下所示:
| # GNU Make 3.80 # Copyright (C) 2002 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. 正常的命令將會在此處執(zhí)行 ? # Make data base, printed on Thu Apr 29 20:58:13 2004 # Variables ... # Directories ... # Implicit Rules ... # Pattern-specific variable values ... # Files ... # VPATH Search Paths |
讓我們更詳細(xì)地查看以上這幾個區(qū)段。
變量區(qū)段(variable)將會列出每個變量以及具描述性的注釋:
自動變量不會被顯示出來,但是通過它們可以方便變量的獲得,像$(<D)。注釋所指出的是origin 函數(shù)所返回的變量類型(參見“較不重要的雜項函數(shù)”一節(jié))。如果變量被定義在一個文件中,則會在注釋中指出其文件名以及該定義所在的行號。簡單變量和遞歸變量的差別在于賦值運算符。簡單變量的值將會被顯示成右邊部分被求值的形式。
下一個區(qū)段標(biāo)示為Directories,它對make 開發(fā)人員比對make 用戶有用。它列出了將會被make 檢查的目錄,包括可能會存在的SCCS 和RCS 子目錄,但它們通常不存在。對每個目錄來說,make 會顯示實現(xiàn)細(xì)節(jié),比如設(shè)備編號、inode 以及文件名模式匹配的統(tǒng)計數(shù)據(jù)。
接著是Implicit Rules 區(qū)段。這個區(qū)段包含了make 數(shù)據(jù)庫中所有的內(nèi)置的和用戶自定義的模式規(guī)則。此外,對于那些定義在文件中的規(guī)則,它們的注釋將會指出文件名以及行號:
| %.c %.h: %.y # commands to execute (from `../mp3_player/makefile', line 73): $(YACC.y) --defines $< $(MV) y.tab.c $*.c $(MV) y.tab.h $*.h ? %: %.c # commands to execute (built-in): $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@ ? %.o: %.c # commands to execute (built-in): $(COMPILE.c) $(OUTPUT_OPTION) $< |
查看這個區(qū)段,是讓你能夠熟悉make 內(nèi)置規(guī)則的變化和結(jié)構(gòu)的最佳方法。當(dāng)然,并非所有的內(nèi)置規(guī)則都會被實現(xiàn)成模式規(guī)則。如果你沒有找到你想要的規(guī)則,可以查看Files區(qū)段,舊式后綴規(guī)則就列在該處。
下一個區(qū)段被標(biāo)示為Pattern-specific variables,此處所列出的是定義在makefile 里的模式專屬變量。所謂模式專屬變量,就是變量定義的有效范圍被限定在相關(guān)的模式規(guī)則執(zhí)行的時候。例如,模式變量YYLEXFLAG 被定義成:
| %.c %.h: YYLEXFLAG := -d %.c %.h: %.y $(YACC.y) --defines $< $(MV) y.tab.c $*.c $(MV) y.tab.h $*.h |
將會被顯示成:
| # Pattern-specific variable values %.c : # makefile (from `Makefile', line 1) # YYLEXFLAG := -d # variable set hash-table stats: # Load=1/16=6%, Rehash=0, Collisions=0/1=0% %.h : # makefile (from `Makefile', line 1) # YYLEXFLAG := -d # variable set hash-table stats: # Load=1/16=6%, Rehash=0, Collisions=0/1=0% # 2 pattern-specific variable values |
接著是Files 區(qū)段,此處所列出的都是與特定文件有關(guān)的自定義和后綴規(guī)則:
| # Not a target: .p.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in): $(COMPILE.p) $(OUTPUT_OPTION) $< ? lib/ui/libui.a: lib/ui/ui.o # Implicit rule search has not been done. # Last modified 2004-04-01 22:04:09.515625 # File has been updated. # Successfully updated. # commands to execute (from `../mp3_player/lib/ui/module.mk', line 3): ar rv $@ $^ ? lib/codec/codec.o: ../mp3_player/lib/codec/codec.c ../mp3_player/lib/codec/codec.c ../mp3_player/include/codec/codec.h # Implicit rule search has been done. # Implicit/static pattern stem: `lib/codec/codec' # Last modified 2004-04-01 22:04:08.40625 # File has been updated. # Successfully updated. # commands to execute (built-in): $(COMPILE.c) $(OUTPUT_OPTION) $< |
中間文件與后綴規(guī)則會被標(biāo)示為Not a target,其余是工作目標(biāo)。每個文件將會包含注釋,用以指出make 是如何處理此規(guī)則的。被找到的文件在被顯示的時候?qū)ㄟ^標(biāo)準(zhǔn)的vpath 搜索來找出其路徑。
最后一個區(qū)段被標(biāo)示為VPATH Search Paths,列出了VPATH 的值以及所有的vpath模式。
對于大規(guī)模使用eval 以及用戶自定義函數(shù)來建立復(fù)雜的變量和規(guī)則的makefile 來說,查看它們的輸出結(jié)果通常是確認(rèn)宏是否已被擴(kuò)展成預(yù)期值的唯一方法。
2.3 --warn-undefined-variables
這個選項會使得make 在未定義的變量被擴(kuò)展時顯示警告信息。因為未定義的變量會被擴(kuò)展成空字符串,這常見于變量名稱打錯而且很長一段時間未被發(fā)現(xiàn)到。這個選項有個問題,這也是為什么我很少使用這個選項的原因,那就是許多內(nèi)置規(guī)則都會包含未定義的變量以作為用戶自定義值的掛鉤。所以使用這個選項來運行make必然會產(chǎn)生許多不是錯誤的警告信息,而且對用戶的makefile 沒有什么用處。例如:
| $ make --warn-undefined-variables -n makefile:35: warning: undefined variable MAKECMDGOALS makefile:45: warning: undefined variable CFLAGS makefile:45: warning: undefined variable TARGET_ARCH ... makefile:35: warning: undefined variable MAKECMDGOALS make: warning: undefined variable CFLAGS make: warning: undefined variable TARGET_ARCH make: warning: undefined variable CFLAGS make: warning: undefined variable TARGET_ARCH ... make: warning: undefined variable LDFLAGS make: warning: undefined variable TARGET_ARCH make: warning: undefined variable LOADLIBES make: warning: undefined variable LDLIBS |
不過,此命令在需要捕獲此類錯誤的某些場合上可能非常有用。
3.--debug 選項
當(dāng)你需要知道make 如何分析你的依存圖時,可以使用--debug 選項。除了運行調(diào)試器,這個選項是讓你獲得最詳細(xì)信息的另一個方法。你有五個調(diào)試選項以及一個修飾符可用,分別是:basic、verbose、implicit、jobs、all 以及makefile。
如果調(diào)試選項被指定成--debug,就是在進(jìn)行basic 調(diào)試;如果調(diào)試選項被指定成-d,就是在進(jìn)行all調(diào)試;如果要使用選項的其他組合,則可以使用--debug=option1,option2 這個以逗號為分隔符的列表,此處的選項可以是下面任何一個單詞(實際上,make 只會查看第一個字母):
3.1 basic
這是所提供的信息最不詳細(xì)的基本調(diào)試功能。啟用時,make會輸出被發(fā)現(xiàn)尚未更新的工作目標(biāo)并更新動作的狀態(tài)。它的輸出會像下面這樣:
| File all does not exist. File app/player/play_mp3 does not exist. File app/player/play_mp3.o does not exist. Must remake target app/player/play_mp3.o. gcc ... ../mp3_player/app/player/play_mp3.c Successfully remade target file app/player/play_mp3.o. |
3.2 verbose
這個選項會設(shè)定basic 選項,以及提供關(guān)于“哪些文件被分析、哪些必要條件不需要重建等”的額外信息:
| File all does not exist. Considering target file app/player/play_mp3. File app/player/play_mp3 does not exist. Considering target file app/player/play_mp3.o. File app/player/play_mp3.o does not exist. Pruning file ../mp3_player/app/player/play_mp3.c. Pruning file ../mp3_player/app/player/play_mp3.c. Pruning file ../mp3_player/include/player/play_mp3.h. Finished prerequisites of target file app/player/play_mp3.o. Must remake target app/player/play_mp3.o. gcc ... ../mp3_player/app/player/play_mp3.c Successfully remade target file app/player/play_mp3.o. Pruning file app/player/play_mp3.o. |
3.3 implicit
這個選項會設(shè)定basic 選項,以及提供關(guān)于“為每個工作目標(biāo)搜索隱含規(guī)則”的額外信息:
| File all does not exist. File app/player/play_mp3 does not exist. Looking for an implicit rule for app/player/play_mp3. Trying pattern rule with stem play_mp3. Trying implicit prerequisite app/player/play_mp3.o. Found an implicit rule for app/player/play_mp3. File app/player/play_mp3.o does not exist. Looking for an implicit rule for app/player/play_mp3.o. Trying pattern rule with stem play_mp3. Trying implicit prerequisite app/player/play_mp3.c. Found prerequisite app/player/play_mp3.c as VPATH ../mp3_player/app/ player/play_mp3.c Found an implicit rule for app/player/play_mp3.o. Must remake target app/player/play_mp3.o. gcc ... ../mp3_player/app/player/play_mp3.c Successfully remade target file app/player/play_mp3.o. |
3.4 jobs
這個選項會輸出被make 調(diào)用的子進(jìn)程的細(xì)節(jié),它不會啟用basic 選項的功能
| Got a SIGCHLD; 1 unreaped children. gcc ... ../mp3_player/app/player/play_mp3.c Putting child 0x10033800 (app/player/play_mp3.o) PID 576 on the chain. Live child 0x10033800 (app/player/play_mp3.o) PID 576 Got a SIGCHLD; 1 unreaped children. Reaping winning child 0x10033800 PID 576 Removing child 0x10033800 PID 576 from chain. |
3.5 all
這會啟用前面的所有選項,當(dāng)你使用-d 選項時,默認(rèn)會啟用此功能。
3.6 makefile
它不會啟用調(diào)試信息,直到Makefile 被更新—— 這包括更新任何的引入文件。如果使用此修飾符,make 會在重編譯makefile 以及引入文件的時候,輸出被選擇的信息。這個選項會啟用basic 選項,all 選項也會啟用此選項。
?
?
如何調(diào)試Makefile變量
轉(zhuǎn)載自:http://coolshell.cn/articles/3790.html
?
六、七年前寫過一篇《跟我一起寫Makefile》,直到今天,還有一些朋友問我一些Makefile的問題,老實說,我有一段時間沒有用Makefile了,生疏了。回顧,這幾年來大家問題我的問題,其實很多時候是makefile的調(diào)試問題。所以,就像我在之前的那篇關(guān)于GDB的技巧的文章中做的一樣,在這里向大家介紹一個小小的調(diào)試變量的技巧。相信一定對你有用。
對于Makefile中的各種變量,可能是我們比較頭痛的事了。我們要查看他們并不是很方便,需要修改makefile加入echo命令。這有時候很不方便。其實我們可以制作下面一個專門用來輸出變量的makefile(假設(shè)名字叫:vars.mk)
vars.mk
| ?%: ??????? @echo '$*=$($*)' ? d-%: ??????? @echo '$*=$($*)' ??????? @echo '? origin = $(origin $*)' ??????? @echo '?? value = $(value? $*)' ??????? @echo '? flavor = $(flavor $*)' |
?
這樣一來,我們可以使用make命令的-f參數(shù)來查看makefile中的相關(guān)變量(包括make的內(nèi)建變量,比如:COMPILE.c或MAKE_VERSION之類的)。注意:第二個以“d-”為前綴的目標(biāo)可以用來打印關(guān)于這個變量更為詳細(xì)的東西(后面有詳細(xì)說明)
假設(shè)我們的makefile是這個樣子(test.mk)
test.mk
| OBJDIR := objdir OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o) ? foo = $(bar)bar = $(ugh)ugh = Huh? ? CFLAGS = $(include_dirs) -O include_dirs = -Ifoo -Ibar CFLAGS := $(CFLAGS) -Wall ? MYOBJ := a.o b.o c.o MYSRC := $(MYOBJ:.o=.c) |
?
那么,我們可以這樣進(jìn)行調(diào)試:
演示
| [hchen@RHELSVR5]$ make -f test.mk -f var.mk OBJS OBJS=objdir/foo.o objdir/bar.o objdir/baz.o ? [hchen@RHELSVR5]$ make -f test.mk -f var.mk d-foo foo=Huh? ? origin = file ? value = $(bar) ? flavor = recursive ? [hchen@RHELSVR5]$ make -f test.mk -f var.mk d-CFLAGS CFLAGS=-Ifoo -Ibar -O -O ? origin = file ? value = -Ifoo -Ibar -O -O ? flavor = simple ? [hchen@RHELSVR5]$? make -f test.mk -f var.mk d-COMPILE.c COMPILE.c=cc -Ifoo -Ibar -O -Wall?? -c ? origin = default ? flavor = recursive ?? value = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c ? |
?
我們可以看到:
- make的第一個-f后是要測試的makefile,第二個是我們的debug makefile。
- 后面直接跟變量名,如果在變量名前加”d-“,則輸出更為詳細(xì)的東西。
說一說”d-” 前綴(其意為details),其中調(diào)用了下面三個參數(shù)。
- $(origin):告訴你這個變量是來自哪兒,file表示文件,environment表示環(huán)境變量,還有environment override,command line,override,automatic等。
- $(value):打出這個變量沒有被展開的樣子。比如上述示例中的 foo 變量。
- $(flavor):有兩個值,simple表示是一般展開的變量,recursive表示遞歸展開的變量。
?
?
?
make調(diào)試工具:remake
?
http://bashdb.sourceforge.net/remake/
?
?
?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/LoTGu/p/5936465.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的Makefile常用调试方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring 整合mongodb报NoS
- 下一篇: 如何升级cordova插件