1. 程式人生 > >make--變量與函數的綜合示例 自動生成依賴關系

make--變量與函數的綜合示例 自動生成依賴關系

14. 自動生成 處理 con 替換 總結 連續 產生 rebuild

一.變量與函數的示例

示例的要求
1.自動生成target文件夾存放可執行文件
2.自動生成objs文件夾存放編譯生成的目標文件
3.支持調試版本的編譯選項
4.考慮代碼的擴展性
完成該示例所需的
1.$(wildcardpattern)獲取當前工作目錄中滿足pattern的文件或目錄列表
2.$(addprefix,_name)給名字列表name的每一個名字增加前綴_prefix
關鍵技巧
1.自動獲取當前目錄下的源文件列表(函數調用)

SRC : = $(wildcard *.c)

2.根據源文件列表生成目標目標文件列表(變量的值替換)

OBJS := $(SRCS:.c=.o)

3.對每一個目標文件列表加上路徑前綴(函數調用)

OBJS := $(addprefix path/,$(OBJS))

規則中的模式替換(目錄結構)
技術分享圖片
編譯規則的依賴
技術分享圖片
編譯的示例代碼及運行結果
技術分享圖片技術分享圖片技術分享圖片

CC := gcc
MKDIR := mkdir
RM := rm -fr

DIR_OBJS := objs
DIR_TARGET := target

DIRS := $(DIR_OBJS) $(DIR_TARGET)

TARGET := $(DIR_TARGET)/hello-makefile.out
# main.c const.c func.c
SRCS := $(wildcard *.c)
# main.o const.o func.o
OBJS := $(SRCS:.c=.o)
# objs/main.o objs/const.o objs/func.o
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))

.PHONY : rebuild clean all

$(TARGET) : $(DIRS) $(OBJS)
    $(CC) -o $@ $(OBJS)
    @echo "Target File ==> $@"

$(DIRS) :
    $(MKDIR) $@

$(DIR_OBJS)/%.o : %.c
    ifeq ($(DEBUG),true)
        $(CC) -o $@ -g -c $^ 
    else   
        $(CC) -o $@ -c $^
    endif

rebuild : clean all

all : $(TARGET)

clean :
    $(RM) $(DIRS)

運行結果
技術分享圖片
小結:
1.目錄可以成為目標的依賴,在規則中創建目錄
2.預定義函數是makefile不可或缺的部分
3.規則這的模式匹配可以直接針對目錄中的文件
4.可以使用命令行變量編譯特殊的目標版本

二.自動生成依賴關系

一.編譯行為帶來的缺陷
1.預處理器將頭文件中的代碼直接插入源文件
2.編譯器只能通過預處理後的源文件產生目標文件‘
所以,規則中以源文件為依賴,命令可能無法執行
示例
技術分享圖片技術分享圖片
在第一張圖可以看出main.c與func.c是依賴於func.h的,此時將func.h中的打印信息改了之後運行的結果如下圖所示
技術分享圖片技術分享圖片
技術分享圖片
由運行的結果可以看到把打印的信息改變了,但是make之後的結果並沒有改變,這是因為並沒有把func.h算子啊依賴上去,所以在它的打印信息改變之後,結果還是一樣的 ,需要進行以下修改才能實現修改打印信息,運行結果也改變(如圖所示)

技術分享圖片
由上面的解決方法可以得出
1.頭文件作為依賴條出現於每個目標對應的規則中
2.當頭文件改動,任何源文件都將被重新編譯
3.當項目中頭文件數量巨大時,makefile將很難維護

二.改進的方法
1.通過命令自動生成對頭文件的依賴
2.將生成的依賴自動包含進makefile中
3.當頭文件改動後,自動確認需要重新編譯的文件
所需條件
1.Linux命令sed
2.編譯器依賴生成選項gcc -MM(gcc -M)
A.Linux中的sed命令
1.sed是一個流編輯器,用於流文本的修改(增/刪/查/改)
2.sed可用於流文本的中的字符串替換
3.sed的字符串替換方式為 :sed ‘s:src:des:g‘
技術分享圖片
B.sed的正則表達式支持
1.在sed中可以用正在表達式匹配替換目標
2.並且可以使用匹配的目標生成替換結果
技術分享圖片
C.gcc關鍵編譯選項(生成依賴關系)
1.獲取目標的完整依賴關系(gcc -M test.c)
2.獲取目標的部分依賴關系(gcc -MM test.c)
D.makefile中的include關鍵字
1.類似C語言中的include
2.將其它文件的內容原封不動的搬入當前文件

技術分享圖片
make對include關鍵字的處理方式
a.在當前目錄搜索或指定目錄搜索目標文件
1.搜索成功:將文件搬入當前makefile中
2.搜索失敗:產生警告
a.以文件名作為目標查找並執行對應規則
b.當前文件名對應的規則不存在時,最終產生錯誤
代碼示例及運行結果
技術分享圖片
makefile中命令的執行機制
1.規則中的每個命令默認是在一個新的進程中執行
2.可以通過連續符(;)將多個命令組成一個命令
3.組合的命令依次在同一個進程中被執行
4.set -e指定發生錯誤後立即退出執行

示例:
技術分享圖片
技術分享圖片技術分享圖片
該代碼主要的目的是想在當前文件夾下新建test文件夾,然後進入test文件夾,創建subtest文件夾,但是make之後的結果如圖所示,可以看到subtest與test文件夾在同一級目錄,不是我們要的結果
經過修改之後的代碼及運行結果
技術分享圖片技術分享圖片技術分享圖片

三.綜合示例

思路:通過gcc -MM 和sed得到.dep依賴文件,通過inclue指令包含所有的.dep依賴文件
技術分享圖片技術分享圖片技術分享圖片

運行的結果:
技術分享圖片
該示例可能會出現的問題是如何在makefile在組織.dep文件到指定目錄
解決的思路:
當include發現.dep文件不存在:
1.通過規則和命令創建deps文件
2.將所有.dep文件創建到deps文件夾
3..dep文件記錄目標文件的依賴關系
代碼實現
技術分享圖片技術分享圖片
總結:
a.使用減號(-)不但關閉了include發出的警告,同時關閉了錯誤,當錯誤發生時make將忽略這些錯誤
b.當目標文件不存在(以文件名查找規則,並執行)
c.當目標文件不存在,且查找到的規則在創建了目標文件(將創建成功的目標文件包含進當前makefile)
d.當目標文件存在(將目標文件包含進當前makefile,以目標文件名查找是否有相應的規則)
e.當目標文件存在,且目標名對應的規則被執行(規則中的命令更新了目標文件,make重新包含目標文件,替換之前包含的內容),目標文件未被更新(無操作)

make--變量與函數的綜合示例 自動生成依賴關系