日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Makefile 7——自动生成依赖关系 三颗星

發布時間:2023/12/18 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Makefile 7——自动生成依赖关系 三颗星 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

后面會介紹gcc獲得源文件依賴的方法,gcc這個功能就是為make而存在的。我們采用gcc的-MM選項結合sed命令。使用sed進行替換的目的是為了在目標名前加上“objs/”前綴。gcc的-E選項,預處理。在生成依賴關系時,其實并不需要gcc編譯源文件,只要預處理就可以獲得依賴關系了。通過-E選項,可以避免生成依賴關系時gcc發出警告,以及提高依賴關系的生成效率。

現在,已經找到自動生成依賴關系的方法了,那么如何將其整合到我們complicated項目的Makefile中呢?自動生成的依賴信息不能直接出現在Makefile中,因為不能動態地改變Makefile中的內容,此時我們需要通過創建依賴關系文件的方式。假設依賴關系的文件以“.dep”結尾,因此我們新創建一個deps文件,用來存放依賴關系文件信息。

Makefile如下:

1 .PHONY: all clean 2 3 MKDIR = mkdir 4 RM = rm 5 RMFLAGS = -rf 6 7 CC=gcc 8 9 DIR_OBJS=objs 10 DIR_EXES=exes 11 DIR_DEPS=deps 12 13 DIRS =$(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS) 14 EXE=complicated 15 EXE:=$(addprefix $(DIR_EXES)/,$(EXE)) 16 SRCS=$(wildcard *.c) 17 OBJS=$(SRCS:.c=.o) 18 OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS)) 19 DEPS=$(SRCS:.c=.dep) 20 DEPS:=$(addprefix $(DIR_DEPS)/,$(DEPS)) 21 22 all:$(DIRS) $(DEPS) $(EXE) 23 $(DIRS): 24 $(MKDIR) $@ 25 $(EXE):$(OBJS) 26 $(CC) -o $@ $^ 27 $(DIR_OBJS)/%.o:%.c 28 $(CC) -o $@ -c $^ 29 $(DIR_DEPS)/%.dep:%.c 30 @echo "Creating $@ ..." 31 @set -e;\ 32 $(RM) $(RMFLAGS) $@.tmp;\ 33 $(CC) -E -MM $^ >$@.tmp;\ 34 sed 's,\(.*\)\.o[:]*,objs/\1.o:,g' <$@.tmp >$@;\ 35 $(RM) $(RMFLAGS) $@.tmp 36 clean: 37 $(RM) $(RMFLAGS) $(DIRS)

(這個Makefile廢了不少力氣才想明白。。。)

和之前的complicated項目的Makefile相比:

1,增加了deps文件夾

2,刪除了目標文件創建規則中的foo.h依賴,并將規則中的$<變回了$^

3,增加了了DEPS變量用于存放文件

4,為all目標增加了$(DEPS)

5,增加了一個用于創建依賴關系問價你的規則。在這個規則中,使用了gcc的-E和-MM選項來獲取依賴關系。在生成最終的依賴關系文件之前,使用了一個由$@.tmp表示的臨時文件,且在依賴文件生成以后將其刪除。set -e的作用是告訴shell,在生成依賴關系文件的過程中如果出現任何錯誤就直接退出。shell異常退出的最終表現就是make會告訴我們出錯了,從而停止后續的make工作。如果不設置這一行,當構建依賴出錯時,make還會繼續后面的工作并最終出錯,這并不是我們希望看到的。讀者可以測試故意在源文件或者頭文件中植入錯誤并去掉set -e選項觀察make的行為和加上set -e有上面不同。

這里還有幾個知識點需要補充。

1.對于規則中的每一條命令,make都是在一個新的shell上運行它的。

2.如果希望多個命令在同一個shell中運行,可以用“;”將這些命令連起來。

3.當命令很長時,可以用“\”將一個命令書寫成多行。

為了更好的理解第一點,我們做一個實驗。現假設需要創建一個test目錄,然后在這個test目錄下再創建一個subtest子目錄。編寫Makefile如下:

?

1 .PHONY:all 2 all: 3 @mkdir test 4 @cd test 5 @mkdir subtest

?

可以看到test和subtest是同級目錄并非父子目錄,然后用上面提到的知識點更改Makefile:

1 .PHONY:all 2 all: 3 @mkdir test;\ 4 cd test;\ 5 mkdir subtest

?

這樣就可以達到目的了。不過你可能會想,為什么這里后面的cd和最后一個mkdir不需要在前面加上@呢?那么我們加上試試呢?

?

如果使用了分號“ ;”,表示命令在同一個shell中運行,而且使用“ \”鏈接一條命令,既然是一條命令,自然不能夠識別后面的@cd或者@mkdir,因為最開始的mkdir使用@,讓終端不顯示執行的指令,后面的cd和mkdir是在前面操作的情況下進行的?,此時,直接使用命令即可。

還有一個需要注意的地方:

如同

EXE=complicated EXE:=$(addprefix $(DIR_EXES)/,$(EXE)) 這樣的Makefile,為什么第二個賦值我們是用:=而不是直接=呢?這也是需要注意的小細節,這個在之前的隨筆中已經說過,要是用=,會導致無限遞歸,為什么呢?因為EXE在復制號左邊,而右邊又有$(EXE)(EXE的引用),這樣會無限調用,make報錯。不信你可以試試。 最后,來到最難的一個東西: sed 's,\(.*\)\.o[:]*,objs/\1.o:,g' <$@.tmp >$@; 這個語句才是最難的,也是最費力的。 首先要簡單說明一下linux中sed的用法: 1.簡介 sed是非交互式的編輯器。它不會修改文件,除非使用shell重定向來保存結果(這里這個復雜命令就用了重定向來更改)。默認情況下,所有的輸出行都被打印到屏幕上。 sed編輯器逐行處理文件(或輸入),并將結果發送到屏幕。具體過程如下:首先sed把當前正在處理的行保存在一個臨時緩存區中(也稱為模式空間),然后處理臨時緩沖區中的行,完成后把該行發送到屏幕上。sed每處理完一行就將其從臨時緩沖區刪除,然后將下一行讀入,進行處理和顯示。處理完輸入文件的最后一行后,sed便結束運行。sed把每一行都存在臨時緩沖區中,對這個副本進行編輯,所以不會修改原文件。 2.定址 定址用于決定對哪些行進行編輯。地址的形式可以是數字、正則表達式、或二者的結合。如果沒有指定地址,sed將處理輸入文件的所有行

3.命令與選項

sed命令告訴sed如何處理由地址指定的各輸入行,如果沒有指定地址則處理所有的輸入行。

此處sed引用此博客, 參考鏈接:http://www.cnblogs.com/edwardlost/archive/2010/09/17/1829145.html

3.1 sed命令

?命令?功能
?a\

?在當前行后添加一行或多行。多行時除最后一行外,每行末尾需用“\”續行

?c\?用此符號后的新文本替換當前行中的文本。多行時除最后一行外,每行末尾需用"\"續行
?i\?在當前行之前插入文本。多行時除最后一行外,每行末尾需用"\"續行
?d?刪除行
?h?把模式空間里的內容復制到暫存緩沖區
?H?把模式空間里的內容追加到暫存緩沖區
?g?把暫存緩沖區里的內容復制到模式空間,覆蓋原有的內容
?G?把暫存緩沖區的內容追加到模式空間里,追加在原有內容的后面
?l?列出非打印字符
?p?打印行
?n?讀入下一輸入行,并從下一條命令而不是第一條命令開始對其的處理
?q?結束或退出sed
?r?從文件中讀取輸入行
?!?對所選行以外的所有行應用命令
?s?用一個字符串替換另一個
?g?在行內進行全局替換
??
?w?將所選的行寫入文件
?x?交換暫存緩沖區與模式空間的內容
?y?將字符替換為另一字符(不能對正則表達式使用y命令)

?

3.2 sed選項

?選項?功能
?-e?進行多項編輯,即對輸入行應用多條sed命令時使用
?-n?取消默認的輸出
?-f?指定sed腳本的文件名
? ? ? ? 4.退出狀態 sed不向grep一樣,不管是否找到指定的模式,它的退出狀態都是0。只有當命令存在語法錯誤時,sed的退出狀態才不是0。 ? ? ? 5.正則表達式元字符 ?與grep一樣,sed也支持特殊元字符,來進行模式查找、替換。不同的是,sed使用的正則表達式是括在斜杠線"/"之間的模式。 如果要把正則表達式分隔符"/"改為另一個字符,比如o,只要在這個字符前加一個反斜線,在字符后跟上正則表達式,再跟上這個字符即可。例如:sed -n '\o^Myop' datafile ?

?

?元字符?功能?示例
?^?行首定位符?/^my/? 匹配所有以my開頭的行
?$?行尾定位符?/my$/? 匹配所有以my結尾的行
?.?匹配除換行符以外的單個字符?/m..y/? 匹配包含字母m,后跟兩個任意字符,再跟字母y的行
?*?匹配零個或多個前導字符?/my*/? 匹配包含字母m,后跟零個或多個y字母的行
?[]?匹配指定字符組內的任一字符?/[Mm]y/? 匹配包含My或my的行
?[^]?匹配不在指定字符組內的任一字符?/[^Mm]y/? 匹配包含y,但y之前的那個字符不是M或m的行
?\(..\)?保存已匹配的字符?1,20s/\(you\)self/\1r/? 標記元字符之間的模式,并將其保存為標簽1,之后可以使用\1來引用它。最多可以定義9個標簽,從左邊開始編號,最左邊的是第一個。此例中,對第1到第20行進行處理,you被保存為標簽1,如果發現youself,則替換為your。
?&?保存查找串以便在替換串中引用?s/my/**&**/??符號&代表查找串。my將被替換為**my**
?\<?詞首定位符?/\<my/? 匹配包含以my開頭的單詞的行
?\>?詞尾定位符?/my\>/? 匹配包含以my結尾的單詞的行
?x\{m\}?連續m個x?/9\{5\}/ 匹配包含連續5個9的行
?x\{m,\}?至少m個x?/9\{5,\}/? 匹配包含至少連續5個9的行
?x\{m,n\}?至少m個,但不超過n個x?/9\{5,7\}/? 匹配包含連續5到7個9的行
? 1.并不是只有 / 可作為模式分割符,很多符合如 , ; 都可以,尤其是模式中有 / 時使用其他分割符更方便,這里這個復雜例子使用逗號,做模式分隔符; sed 's,\(.*\)\.o[:]*,objs/\1.o:,g' <$@.tmp >$@;
現在來分解這個復雜表達式,首先,sed s表示我們想用一個字符串替換另一個字符串,這也是我們使用sed的原因,它的s命令就
可以達到這個效果。
's,\(.*\)\.o[:]*,objs/\1.o:,g'第一次分解,此時需要知道,單引號是一對的,即s前面的'和g后面的'是一個整體單引號,
這也是sed命令的基礎,至于單引號和雙引號有什么區別,可百度谷歌或者必應。(但是我之前測試的單引號和雙引號并不是我搜索所顯示的那樣,后面再試試吧)
繼續分解,s,中s是替換字符串的意思,這個在上面的表格中可以查詢到,逗號,表示模式分隔符,在這種有/出現的字符串中,我們選擇了逗號,作為分隔符號。
所以下一次分解應該倒下一個逗號處,
\(.*\)\.o[:]*,
這里首先看 .* 它表示匹配任意字符,\( \)是一個整體,也是通過上面的表格得到的,然后轉義字符\和.o在一起,把.的作用(匹配除換行符的單個字符)變成普通的.(就是一個字符.),那么這一句話就是
操作字符串所有有.o的且在.0后面(可以有空格)匹配:的零個或多個字符串。
objs/\1.o:,g
這里要解釋的是\1.o 這里用了轉義字符\加上1,這表示什么呢?尤其是這個1,表示的就是前面\( \)內的字符串,這是組
的概念,如何知道是第幾組呢?前面的第一個\(\)的就是第一組,用轉義字符\1表示,依次類推。g在sed中表示行內全局替換
這樣,我們做一個假設例子來說明。
abc.o : 用這個代表
\(.*\)\.o[:]*
后objs/\1.o:,g之后呢,abc.o :變成了 objs/abc.o: 這里相當于給前面的通用匹配加上了objs/前綴,并且把:和.o之前的空格去掉了
最后這個<$@.tmp >$@;這不屬于sed的內容了,屬于linux和Makefile的東西,$@.tmp重定向輸入給前面的sed替換操作,
$@代表目標在Makefile中,$@.tmp是前面的Makefile生成的,<重定向,看方向是輸入,
就是把$@.tmp重定向輸入給sed,經過sed替換之后,再輸出重定向 > 到$@,這個是目標。
這樣再回過頭去看之前那個Makefile就可以看懂了。
?

轉載于:https://www.cnblogs.com/yangguang-it/p/6818664.html

總結

以上是生活随笔為你收集整理的Makefile 7——自动生成依赖关系 三颗星的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。