Makefile是什么?
gcc hello.c -o hello
gcc aa.c bb.c cc.c dd.c ...
make工具和Makefile
make和Makefile是什么關(guān)系?
make工具:找出修改過的文件,根據(jù)依賴關(guān)系,找出受影響的相關(guān)文件,最后按照規(guī)則單獨編譯這些文件。
Makefile文件:記錄依賴關(guān)系和編譯規(guī)則。
必須要學(xué)精Makefile嗎?
怎么學(xué)習(xí)Makefile?
Makefile的本質(zhì):無論多么復(fù)雜的語法,都是為了更好地解決項目文件之間的依賴關(guān)系。
?
?
Makefile三要素
Makefile三要素是什么?
目標、依賴、命令
怎么描述三要素的關(guān)系?
目標:依賴的文件或者是其他目標? ( 記得加TAB字符)
<tab>命令1?
<tab>命令2
<tab>...
實驗演示
.PHONY:可以指定偽目標
gec@ubuntu:~/makefile/part_1$ sudo vi Makefile
gec@ubuntu:~/makefile/part_1$ sudo make
echo "targetb"
targetb
echo "targetc"
targetc
echo "targeta"
targeta
gec@ubuntu:~/makefile/part_1$ cat Makefile
#Makefile格式
#目標:依賴的文件或其它目標
#Tab 命令1
#Tab 命令2
#第一個目標,是最終目標及make的默認目標
#目標a,依賴于目標targetc和targetb
#目標要執(zhí)行的shell命令 ls -lh,列出目錄下的內(nèi)容
targeta: targetb targetc
echo "targeta"
#目標b,無依賴
#目標要執(zhí)行的shell命令,使用touch創(chuàng)建test.txt文件
targetb:
echo "targetb"
#目標c,無依賴
#目標要執(zhí)行的shell命令,pwd顯示當(dāng)前路徑
targetc:
echo "targetc"
#目標d,無依賴
#由于abc目標都不依賴于目標d,所以直接make時目標d不會被執(zhí)行
#可以使用make targetd命令執(zhí)行
# targetd:
# rm -f test.txt
gec@ubuntu:~/makefile/part_1$
上圖中包含的原理說明如下:
make命令:
在終端上執(zhí)行make命令時,make會在當(dāng)前目錄下搜索名為“Makefile”或“makefile”的文件,然后 根據(jù)該文件的規(guī)則解析執(zhí)行。如果要指定其它文件作為輸入規(guī)則,可以通過“-f”參數(shù)指定輸 入文件,如“make -f 文件名”。
此處make命令讀取我們的Makefile文件后,發(fā)現(xiàn)targeta是Makefile的第一個目標,它會被當(dāng)成默認目標執(zhí)行。
又由于targeta依賴于targetc和targetb目標,所以在執(zhí)行targeta自身的命令之前,會先去完成targetc和targetb。
targetc的命令為pwd,顯示了當(dāng)前的路徑。
targetb的命令為touch test.txt ,創(chuàng)建了test.txt文件。
最后執(zhí)行targeta自身的命令ls -lh ,列出當(dāng)前目錄的內(nèi)容,可看到多了一個test.txt文件。
.PHONY
是一個在 Makefile 中使用的特殊目標標簽(偽目標),用于指示某個目標不對應(yīng)實際的文件。
通常,Makefile 中的目標都對應(yīng)著需要生成的文件,而這些目標稱為“真實目標”。但有時候,我們需要定義一些在執(zhí)行 make 命令時需要執(zhí)行的操作,而這些操作不產(chǎn)生對應(yīng)的文件。這時就可以使用 .PHONY
來定義這樣的目標。
.PHONY
的作用是告訴 make 工具,無論是否存在與之同名的文件,它所標記的目標都應(yīng)該被認定為需要執(zhí)行的操作。這樣,在執(zhí)行該目標時,make 將會按照你在 Makefile 中定義的命令來執(zhí)行相應(yīng)的操作,而不會檢查是否有與之同名的文件存在。
使用 .PHONY
的一個常見場景是在 Makefile 中定義一些常用的操作,比如 clean
來清理臨時文件,或者 all
來構(gòu)建所有的目標。
示例:
.PHONY: clean clean: rm -f *.o
在上述示例中,.PHONY: clean
表示 clean
目標是一個偽目標,不對應(yīng)任何文件。當(dāng)執(zhí)行 make clean
命令時,將會執(zhí)行 rm -f *.o
命令,刪除所有 .o
結(jié)尾的臨時文件。
總結(jié)來說,.PHONY
是用來定義偽目標的,它告訴 make 工具,該目標不對應(yīng)任何文件,而是需要執(zhí)行一些特定的操作
?
?
在Makefile的實際應(yīng)用中,通常會把編譯和最終的鏈接過程分開
?也就是說,我們的hello_main目標文件本質(zhì)上并不是依賴hello_main.c和hello_func.c文件,而是依 賴于hello_main.o和hello_func.o,把這兩個文件鏈接起來就能得到我們最終想要的hello_main目 標文件。另外,由于make有一條默認規(guī)則,當(dāng)找不到xxx. o文件時,會查找目錄下的同名xxx.c文件進行編譯。根據(jù)這樣 的規(guī)則,我們可把Makefile改修改如下。
#Makefile格式
#目標文件:依賴的文件
#Tab 命令1
#Tab 命令2
hello_main: hello_main.o hello_func.o
gcc -o hello_main hello_main.o hello_func.o
#以下是make的默認規(guī)則,下面兩行可以不寫
#hello_main.o: hello_main.c
# gcc -c hello_main.c
#以下是make的默認規(guī)則,下面兩行可以不寫
#hello_func.o: hello_func.c
# gcc -c hello_func.c
以上代碼的第5~6行把依賴文件由C文件改成了.o文件,gcc編譯命令也做 了相應(yīng)的修改。第8~13行分別是hello_main.o文件和hello_func.o文件的依賴和 編譯命令,不過由于C編譯成同名的.o文件是make的默認規(guī)則,所以這部分內(nèi)容通常不會寫上去。
Makefile的變量、模式匹配
變量
系統(tǒng)變量
自定義變量
=,延遲賦值
:=, 立即賦值
?=,空賦值(像const)
只有當(dāng)這個變量為空時賦值才有效
+=,追加賦值
當(dāng)我們用追加賦值給某個變量賦值時,不會覆蓋該變量的值,而是在該變量原來的值后面加上新賦的值
?
自動化變量
$<:第一個依賴文件
$^:全部的依賴文件
$@:目標
?
優(yōu)化
模式匹配
%:匹配任意多個非空字符
shell:*通配符
默認規(guī)則
.o文件默認使用當(dāng)前目錄下對應(yīng).c文件來進行編譯
Makefile條件分支
條件分支
如果相等 ifeq (var1,var2) ... else ... endif
ifneq (var1,var2) ... else ... endif
Makefile的常用函數(shù)
Makefie官方手冊:
GNU Make Manual - GNU Project - Free Software Foundation
patsubst:
?文本匹配成新的模式
notdir:
- $(notdir <names...>)
-
名稱:取文件函數(shù)——notdir。
-
功能:從文件名序列?
<names>
?中取出非目錄部分。非目錄部分是指最後一個反斜杠(?/
?)之后的部分。 -
返回:返回文件名序列?
<names>
?的非目錄部分。 -
示例:?
$(notdir src/foo.c hacks)
?返回值是?foo.c hacks
?。
wildcard:
示例:
(wildcard *.c)
?返回值為當(dāng)前目錄下所有.c 源文件列表。
foreach:
Makefile解決頭文件依賴
1、寫一個頭文件,并把頭文件添加到編譯器的頭文件路徑中。
gcc -I +"頭文件"
2、實時檢查頭文件的更新情況,一旦頭文件發(fā)生變化,應(yīng)該要重新編譯所有相關(guān)文件。
gcc -MM
ARCH ?= x86
ifeq ($(ARCH),x86)
CC=gcc
else
CC=arm-linux-gnueabihf-gcc
endif
TARGET=mp3
#OBJS=main.o mp3.o
BUILD_DIR=build
SRC_DIR=module1 module2
INC_DIR=include
CFLAGS=$(patsubst %,-I%,$(INC_DIR))
INCLUDES=$(foreach dir,$(INC_DIR),$(wildcard $(dir)/*.h))
SOURCES= $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))
OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCES)))
VPATH=$(SRC_DIR)
$(BUILD_DIR)/$(TARGET):$(OBJS)
$(CC) $^ -o $@
#main.o:main.c
# $(CC) -c main.c -o main.o
#mp3.o:mp3.c
# $(CC) -c mp3.c -o mp3.o
$(BUILD_DIR)/%.o:%.c $(INCLUDES) | creat_build
$(CC) -c $< -o $@ $(CFLAGS)
.PHONY:clean creat_build
clean:
rm -r $(BUILD_DIR)
creat_build:
mkdir -p $(BUILD_DIR)
文章來源:http://www.zghlxwxcb.cn/news/detail-637249.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-637249.html
到了這里,關(guān)于嵌入式Linux驅(qū)動開發(fā)系列六:Makefile的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!