Linux Makefile 中的陷阱【转】
轉(zhuǎn)自:https://blog.csdn.net/QQ1452008/article/details/52247944
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。 https://blog.csdn.net/QQ1452008/article/details/52247944前言
每個編寫過Makefile的程序員都可能遇見過Makefile中內(nèi)含的陷阱,本博文旨在展現(xiàn)陷阱,提醒自己,也供大家一起學(xué)習(xí)。
本博文會隨所遇見的Makefile陷阱有關(guān)的問題而進行后續(xù)的更新。
陷阱一:在定義變量的語句后面空格之后使用了‘#’注釋符
結(jié)果:導(dǎo)致變量的值并不是你所賦值的,而是把值與注釋符之間的空格一起賦值給了變量,使得執(zhí)行違背自己的意愿,而不容易察覺。
實例說明如下(Makefile版本:GNU MAKE 3.81):
TmpDir = /Source #此處隨意定義了一個目錄,#為了驗證此陷阱,特意在賦值語句后空幾格并進行注釋,ifeq ($(TmpDir), /Source) Result = They are equal else Result = They are not equal endif all: @echo $(TmpDir)||||||| @echo $(Result)?
make之后其結(jié)果為 : /Source ||||||| (注意:/Source與|之間的空格,其實是屬于TmpDir變量的) They are not equal若把 ifeq ($(TmpDir), /Source) 改為 ifeq ($(TmpDir), /Source ) 說明:/Source后面的空格需要跟定義TmpDir與注釋符之間的空格數(shù)相等如此一來,再次make,結(jié)果為:They are equal擴展一:其實驗證的過程中也引申出了另一個陷阱,ifeq()語句中的陷阱,見陷阱二
擴展二 : 變量賦值語句存在這個陷阱,那宏定義語句呢?及類似于如下語句
?
其實經(jīng)過實測表明,這樣并不會影響宏定義“TMP”在源文件中的值, 以及“INCFLAGS ”所在的路徑值。
心得: 通過以上求證,注釋符會影響到Makefile文件內(nèi)部定義使用的變量的值,而不會影響到諸如 -D , -I 后面的值。所以建議Makefile中注釋都不要寫在語句后面,而是語句的前一行,來避免類似的問題出現(xiàn)。
陷阱二:ifeq語句的括號里面,不要隨意使用空格
結(jié)果:makefile會吧參數(shù)后面的空格也當(dāng)作參數(shù)的一部分來進行比較,導(dǎo)致結(jié)果違背自己的意愿。
實例說明如下(Makefile版本:GNU MAKE 3.81):
TmpDir = /Source#下方的/Source后面空了幾格 ifeq ($(TmpDir), /Source ) Result = They are equal else Result = They are not equal endif all: @echo $(Result) make之后其結(jié)果為 : They are not equal若把 ifeq ($(TmpDir), /Source ) 改為 ifeq ($(TmpDir), /Source) 如此一來,再次make,結(jié)果為:They are equal經(jīng)過實測表明,$(TmpDir)后面空幾格沒有影響,唯獨/Source后面空格就會有影響了
心得 : 在Makefile中,最好保證參數(shù)的一致性,是否空格等,不像C語言等語言編程一樣,那么寬松。
陷阱三:在mingw環(huán)境下使用路徑時的陷阱
詳情:在正確使用并能生成.d依賴文件,理論上使得修改任一 .h 或者 .c 文件都能自動進行編譯的情況下,其結(jié)果偏偏就是在修改了.h文件而不能編譯與之相關(guān)的.c文件,即沒有檢查到有文件更新,從而沒有進行編譯。待仔細查看Makefile的內(nèi)容,也不能輕易看出端倪。其實這背后存在一個不易察覺的陷阱。
例子大概如下:
TARGET = Temp # abspath 函數(shù):獲取其參數(shù)中的文件或者目錄的絕對路徑 APP_BASE = $(abspath ../..) DEV_BLD_DIR = $(APP_BASE)/$(TARGET)/Build TEMP = $(APPSRC:.c=.o) APPOBJS_TMP = $(TEMP:.S=.o) # addprefix 函數(shù):把 APPOBJS_TMP 中的文件一一添加前綴 $(DEV_BLD_DIR)/ APPOBJS := $(addprefix $(DEV_BLD_DIR)/,$(APPOBJS_TMP)) APPDEPS_TMP = $(APPOBJS_TMP:.o=.d) APPDEPS := $(addprefix $(DEV_BLD_DIR)/,$(APPDEPS_TMP)) all: Tmp.bin -include $(APPDEPS) ...... #省略了若干內(nèi)容 ...... # subst 函數(shù):把$@中的 Source 替換成 Build # 該編譯的命令,在編譯源文件的同時,也生成了.d 依賴文件 $(DEV_BLD_DIR)/%.o: %.c $(info Compiling $< ...) $(CC) -c -o $(subst Source,Build,$@) $(CFLAGS) $(INCFLAGS) $< -MD -MF $(DEV_BLD_DIR)/$*.d -MP?
請點擊進入 .d依賴文件 相關(guān)內(nèi)容介紹
其實從結(jié)果上便能大致推測是.d依賴文件部分出現(xiàn)了問題,因為改寫任一文件都要能重新編譯,本身就是.d依賴文件所要賦予的功能。
陷阱:目標(biāo)路徑的問題,即同一文件目標(biāo)的引用時要保持路徑一致。mingw環(huán)境下,windows路徑(e.g. c:\agc.o) 和 mingw路徑(/c/agc.o)都能夠識別,對于make而言, c:\abc.o 和 /c/abc.o 是兩個不同的目標(biāo)。若要是不知道這一知識要點,很難發(fā)現(xiàn) .d 文件開頭 c:\ 和 /c/ 的區(qū)別。(個人疑點:同一環(huán)境,不同工程,有些生成的.d依賴文件中.o目標(biāo)路徑和make中引用的路徑是一樣的,目前也不知是什么原因,總之這個陷阱還是存在的。)
實例陷阱說明:
#以下行將導(dǎo)入所有的.d依賴文件的內(nèi)容,即以 /c/...開頭的內(nèi)容 -include $(APPDEPS) #而以下目標(biāo)依賴關(guān)系中,指明目標(biāo)的路徑則是以 c:\...開頭的路徑 $(DEV_BLD_DIR)/%.o: %.c #其結(jié)果就是導(dǎo)致了因路徑表示的不同,而認為不是同一目標(biāo)的情況出現(xiàn) #使得make不能找到.o目標(biāo)文件依賴的所有依賴源文件,其中包括.h頭文件 #自然而然,也就不能因為.h文件的更新,而重新編譯對應(yīng)的.c文件來生成.o文件?
解決方法:
既然知道了陷阱所在,就可以利用如下命令來解決該問題:
?
心得:以后出現(xiàn)類似該情況,即表面上 makefile 中沒有什么問題,但在使用了依賴文件,并修改.h 文件后,不重新編譯的情況,這個時候要考慮路徑問題。不同路徑的表示方法,所表示的目標(biāo)文件在make中會認為不是同一文件。
--------------------- 本文來自 Jerry_yl_ 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/QQ1452008/article/details/52247944?utm_source=copy?
轉(zhuǎn)載于:https://www.cnblogs.com/sky-heaven/p/9735196.html
總結(jié)
以上是生活随笔為你收集整理的Linux Makefile 中的陷阱【转】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: React开发(253):react项目
- 下一篇: Linux 下, npm i 老是被ki