Makfile筆記

1.Makfile初識

1.1Makefile規則

target ... : prerequisites ...
    command
    ...
    ...
注:  
target:目標
prerequisites:依賴文件
command:makefile 需要執行的命令

Makfile規則:
    在執行Makfile時,Makfile會判斷target文件是否存在,
    若不存在,則執行下面的command命令,
    若存在,則判斷prerequisites的時間戳是否比target的時間戳要新,
    若是,則也執行下面的command命令。

1.2引用其他Makefile文件

使用方式:
include <filename>
例:
include foo.make $(value) 

1.3Makefile變量

1.
使用方式:
obj= a.o b.o c.o \
    d.o e.o
target : prerequisites
    command $(obj)
2.CFLAGS,CXXFLAGS 
    CFLAGS 表示用於 C 編譯器的選項,CXXFLAGS表示用於 C++ 編譯器的選項。
    CFLAGS指定頭文件(.h文件)的路徑、編譯條件宏,如:CFLAGS=-I/usr/include -I/path/include -D_YUQIANG。
    上面兩個變量用於gcc的參數中:$(CC) $(CFLAGS)
3.LDFLAGS:
    gcc 等編譯器會用到的一些優化參數,也可以在裏面指定庫文件的位置。用法:
    LDFLAGS=-L/usr/lib -L/path/to/your/lib。
4.LIBS:告訴鏈接器要鏈接哪些庫文件,如LIBS = -lpthread -liconv

1.4Makefile工作流程

1.在敲入make之後,make會在當前目錄下尋找Makefile類型文件
2.讀入被include包含的makefile文件
3.替換變量
4.推到並分析所有規則
5.位所有的目標創建依賴關係鏈
6.找到文件中的第一個target作爲最終的目標文件
7.找到target後按照規則執行,若target的依賴文件也存在依賴文件,則同樣按照規則遞歸執行,直到生成最終的目標文件後make執行完成

2.書寫規則

2.1規則語法

方式1:
targets : prereuuisites
    command
    ...
方式2:
targets : prereuuisites ; command
    command
    ...
注意:
1,若command爲獨立行,則需以<TAB>開頭
2.換行符:'\'
3.command默認使用/bash/sh來執行

2.2通配符

'*':代表『 0 個到無窮多個』任意字符
'?':代表『一定有一個』任意字符
'~':代表用戶的主目錄,~feison/data代表用戶feison主目錄下的data目錄
注:若需要使用這些特定字符,在該字符前加轉義字符'\'

2.3文件搜索路徑

1.VPATH變量
VPATH:makefile中設定默認搜索文件路徑的變量
例:VPATH= src:../headers
注:設置多個路徑用冒號分隔
2.vpath關鍵字
vpath <pattern> <directories> :爲符合模式<pattern>的文件指定搜索目錄<directories>
vpath <pattern> :清除符合模式<pattern>的文件的搜索目錄
vpath :清除所有已設置好的文件搜索目錄
例:vpath %h ../headers

2.4僞目標

僞目標聲明方式:
隱式聲明:
phonytargets:
    commands
顯式聲明:
.PHONY:phonytargets
phonytargets:
    commands
例:生成多個可執行文件
all:prog1 prog2 prog3
.PHONY: all

prog1:prog1.o
    commands1
prog2:prog2.o
    commands2
prog3:prog3.o
    commands3

2.5靜態模式

規則:
<targets>:<target-pattern>:<prereq-pattern>
    <commands>
    ...
注:
targets:目標集,多個目標文件
target-pattern:目標集模式
prereq-pattern:依賴模式
例:
foo.o bar.o abc.m : %.o : %.c
    $(CC) -c $(CFLAGS) $< -o $@
上述的.o文件的依賴文件爲.c文件,當不滿足makefile原則時,執行下面的命令

3.書寫命令

3.1顯示命令

1.@command和command比較
    @command 該命令不會被make顯示
    command 該命令會被make顯示
例:
    @echo this is a test
    make輸出:
    this is a test

    echo this is a test
    make輸出:
    echo this is a test
    this is a test
2.make -n 只顯示命令,但不執行命令
3.make -s 全面禁止命令的顯示

3.2嵌套執行make

make嵌套,亦是make包含,以利於模塊編譯和分段編譯
例:
./Makefile:(總控Makefile)
subsystem:
    cd subdir && $(MAKE)
<==>
sybsystem:
    $(MAKE) -C subdir
1.makefile中的變量傳遞
默認情況下,上級的Makefile中的變量可以傳遞到下級makefile中,但不會覆蓋下級makefile中的變量,除非制定了-e參數。
export <variable ...> 聲明要傳遞到下級makefile的變量
unport <variable ...> 聲明不能傳遞到下級makefile的變量
注:
SHELL和MAKEFLAGS兩個變量始終會被傳遞到下級makefile中
2.make -w
當make進入和離開下級目錄時,輸出相應的目錄變化信息

3.3定義命令塊

規則:
define cmdblocks-name
cmd1
cmd2
...
endef
例:
target : prereqs
    $(cmdblocks-name)

4.變量

4.1變量聲明

1.常規變量
variable = value
$(variable)==>value
${variable}==>value
2.變量中的變量
variable :=value
1中的聲明方式會出現無限的變量展開中,如下
A=$(B)
B=$(A)
:=的聲明方式規定前面的變量不能使用後面的變量,若使用的變量前面未被定義,則其值爲空
例:
x:=foo
y:=$(x) bar $(m)
x:=later
==>
y:=foo bar
x:=later
3.定義一個其值爲空格的變量
nullstring:=
space:=$(nullstring) #end of the line
注:nullstring爲Empty變量,space表示一個空格,Empty變量表示一個變量的值開始了,#表示變量的定義終止
4.操作符?=
variable ?=value
表示若variable之前被定義過,則該語句無效,若沒有被定義過,其值爲value

4.2變量使用

1.多重變量
x=y
y=z
a:=$($(x))
==>
a:=z

2.變量值的替換
$(var:a=b)
${var:a=b}
表示把變量var中所有以a字符串結尾的a替換爲b字符串
例:
foo := a.o b.o c.o
bar :=$(foo:.o=.c)

foo := a.o b.o c.o
bar :=$(foo:%.o=%.c)

3.追加變量
variable +=value
例:
a := b
a +=c
==>
a := b
a :=$(a) b

4.其他
例:
first_second = Hello
a = first
b = second
c =$($(a)_$(b))
==>
c = Hello

4.3override標識符

通過make的命令行參數設置的變量,通常在makefile中對這些變量賦值是無效的,但可以通過override標識符重新設置這些變量的值。
1.
override <variable>; =<value>
2.
override <variable>; :=<value>
3.
override <variable>; +=<value>
4.
override define foo
bar
endef

4.4多行變量

聲明方式:
define two-lines
echo foo
echo $(bar)
endef
注:參見3.3定義命令塊

4.5環境變量

見3.2嵌套執行make

4.6目標變量

目標變量表示爲某個特定的目標設定的變量,該變量的值只適用於特殊目標
聲明:
<target ...>:<variable-assignment>
<target ...>:override <variable-assignment>
注:
<variable-assignment>表示常規賦值表達式
第二個聲明適用於make命令帶入的變量或環境變量
例:
m = flag
target:m= flag_target
target:
    @echo $(m)
則$(m)的值爲flage_target

4.7模式變量

聲明:
<pattern ...>:<variable-assignment>
<pattern ...>:override <variable-assignment>
使用方式同目標變量
例:
%.o : CFLAGS = -g
prog: prog1.o prog2.o
    $(CC) $(CFLAGS ) prog1.o prog2.o
prog1.o:prog1.c
    $(CC) $(CFLAGS ) prog1.c
prog2.o:prog2.c
    $(CC) $(CFLAGS ) prog2.c
以上只有prog1.o和prog2.o下的命令中的CFLAGS的值爲-O,其餘爲系統變量的值

4.8自動化變量

在模式規則中(將在<隱含規則>一節中講解),規則的目標和依賴文件名代表了一類文件名。命令是對所有這一類文件重建過程的描述,顯然,在命令中不能指定特定的文件名,否則模式規則將沒有了意義。那麼在模式規則的命令行中該如何表示文件,將成我們這一小節的討論重點。make中使用了“自動環變量”來實現這個目的,自動化變量的取值是根據具體的規則決定的,就是說對不同的規則其所代表的文件名不同。
前邊我們也看到了很多例子中使用到了自動化變量。下面對所有的自動化變量進行說明:
$@
代表規則中的目標文件名。如果目標是一個文檔(Linux中,一般稱.a文件爲文檔),那麼它代表這個文檔的文件名。在多目標的模式規則中,它代表的是哪個觸發規則被執行的目標文件名。
$%
規則的目標文件是一個靜態庫文件時,代表靜態庫的一個成員名。例如,規則的目標是“foo.a(bar.o)”,那麼,“$%”的值就爲“bar.o”,“$@”的值爲“foo.a”。如果目標不是函數庫文件,其值爲空。
$<
規則的第一個依賴文件名。如果是隱含規則,則它代表通過目標指定的第一個依賴文件。
$?
所有比目標文件更新的依賴文件列表,空格分割。如果目標是靜態庫文件名,代表的是庫成員(.o文件)的更新情況。
$^
規則的所有依賴文件列表,使用空格分隔。如果目標是靜態庫文件名,它所代表的只能是所有庫成員(.o文件)名。一個文件可重複的出現在目標的依賴中,變量“$^”只記錄它的一次引用情況。就是說變量“$^”會去掉重複的依賴文件。
$+
類似“$^”,但是它保留了依賴文件中重複出現的文件。主要用在程序鏈接時,庫的交叉引用場合。
$*
在模式規則和靜態模式規則中,代表“莖”。“莖”是目標模式中“%”所代表的部分(當文件名中存在目錄時,“莖”也包含目錄(斜槓之前)部分)。例如:文件“dir/a.foo.b”,當目標的模式爲“a.%.b”時,“$*”的值爲“dir/a.foo”。“莖”對於構造相關文件名非常有用。
自動化變量“$*”需要兩點說明:
Ø        對於一個明確指定的規則來說不存在“莖”,這種情況下“$*”所代表的值發生變化。此時,如果目標文件名帶有一個可識別的後綴,那麼“$*”表示文件中除後綴以外的部分。例如:“foo.c”則“$*”的值爲:“foo”,因爲.c是一個可識別的文件後綴名。GUN make對明確規則的這種奇怪的處理行爲是爲了和其它版本的make兼容。通常,在除靜態規則和模式規則以外,明確指定目標文件的規則中避免使用這個變量。
Ø        當明確指定文件名的規則中目標文件名包含不可識別的後綴時,此變量爲空。
自動化變量“$?”在顯式規則中也是非常有用的,規則中可以使用它來指定只對更新的依賴文件進行操作。例如,函數庫文件“libN.a”,它由一些.o文件組成。如下的規則實現了根據變化的.o文件更新庫文件:

lib: foo.o bar.o lose.o win.o
    ar r lib $?

上述列出的自動量變量中。其中有四個在規則中代表一個文件名($@$<$%$*)。而其它三個的在規則中代表一個文件名的列表。GUN make中,還可以通過這七個自動化變量來獲取一個完整文件名中的目錄部分或者具體文件名,需要在這些變量中加入“D”或者“F”字符。這樣就形成了一系列變種的自動環變量。這些變量在以前版本的make中使用,在當前版本的make中,可以使用“dir”或者“notdir”函數來實現同樣的功能。
$(@D)
代表目標文件的目錄部分(去掉目錄部分的最後一個斜槓)。如果“$@”是“dir/foo.o”,那麼“$(@D)”的值爲“dir”。如果“$@”不存在斜槓,其值就是“.”(當前目錄)。注意它和函數“dir”的區別!
$(@F)
目標文件的完整文件名中除目錄以外的部分(實際文件名)。如果“$@”爲“dir/foo.o”,那麼“$(@F)”只就是“foo.o”。“$(@F)”等價於函數“$(notdir $@)”。
$(*D)
$(*F)
分別代表目標“莖”中的目錄部分和文件名部分。
$(%D)
$(%F)
當以如“archive(member)”形式靜態庫爲目標時,分別表示庫文件成員“member”名中的目錄部分和文件名部分。它僅對這種形式的規則目標有效。
$(<D)
$(<F)
分別表示規則中第一個依賴文件的目錄部分和文件名部分。
$(^D)
$(^F)
分別表示所有依賴文件的目錄部分和文件部分(不存在同一文件)。
$(+D)
$(+F)
分別表示所有依賴文件的目錄部分和文件部分(可存在重複文件)。
$(?D)
$(?F)
分別表示被更新的依賴文件的目錄部分和文件部分。

5.邏輯判斷語句

5.1使用語法

1.ifeq/else/endif
    <1>
    ifeq (<arg1>,<arg2>)
    <text-ifeq>
    else
    <text-else>
    endif

    <2>
    ifeq (<arg1>,<arg2>)
    <text-ifeq>
    endif

2.ifneq/else/endif
    <1>
    ifneq (<arg1>,<arg2>)
    <text-ifneq>
    else
    <text-else>
    endif

    <2>
    ifneq (<arg1>,<arg2>)
        <text-ifneq>
    endif

3.ifdef/else/endif
    <1>
    ifdef <variable-name>
    <text-ifdef>
    else
    <text-else>
    endif

    <2>
    ifdef <variable-name>
    <text-ifdef>
    endif

4.if <condition>, <then-part>, <else-part>
    相當於C語言中:
    if(condition)
        then-part;
    else
        else-part;

6.常用函數

6.1函數調用語法

語法:
$(<function> <arguments>)
${<function> <arguments>}

6.2字符串處理函數

1.subst
字符串替換函數
$(subst <from>,<to>,<text>)
例:
$(subst ee,EE,feet on the street)
==>fEEt on the strEEt

2.patsubst
模式字符串替換函數
$(patsubst <pattern>,<replacement>,<text>)

3.strip
去空格函數,去掉字符串開頭和結尾的空格
$(strip <string>)

4.findstring
查找字符串函數
$(findstring <findstr>,<string>)

5.filter
過濾函數
$(filter <pattern...>,<text>)

6.filter-out
反過濾函數
$(filter-out <pattern...>,<text>)

7.sort
排序函數
$(sort <list>)

8.word
取單詞函數
$(word <n>,<text>)

9.wordlist
取單詞串函數,得到從<s_num>到<e_num>的單詞串
$(wordlist <s_num>,<e_num>,<text>)

10.words
單詞數統計函數
$(words <string>)

11.firstword
取首單詞函數
$(firstword <string>)

6.3文件名操作函數

1.dir
取目錄函數
$(dir <path_files_name>)

2.notdir
取文件名函數
$(nodir <path_files_name>)

3.suffix
取後綴函數
$(suffix <names>)

4.basename
取前綴函數
$(basename <names>)

5.addsuffix
添加後綴函數
$(addsuffix <suffix>,<names>)

6.addprefix
添加前綴函數
$(addprefix  <prefix>,<names>)

7.join
連接函數
$(join <list1>,<list2>)

6.4makefile調試函數

1.error
產生一個致命錯誤
$(error <text>)

2.warning
生成一個警告信息
$(warning <text>)

3.info
生成一個普通信息
$(info <text>)

6.5其他函數

1.foreach
循環函數
$(foreach <var>,<list>,<text>)

2.if
條件判斷函數
$(if <condition>,<then-part>)
$(if <condition>,<then-part>,<else-part>)

3.call
調用函數的函數
$(call <func>,<parm1>,<parm2>,<parm3>,...)
注:
func:自定義函數
parm1:func中的參數1($(1))
parm2: func中的參數2($(2))
func中的所有參數變量均用,$(1),$(2)...表示
例:
reverse = $(2) $(1)
foo=$(call reverse ,a,b)
==>
foo=b a

4.origin
變量源函數,輸出變量來源
源列表:
<1>undefined:未定義變量
<2>default:默認定義
<3>environment:環境變量
<4>file:makefile中定義的變量
<5>command line:命令行定義的變量
<6>override:override重新定義的變量
<7>automatic:自動化變量
$(origin <variable>)

5.shell
調用外部shell命令函數
$(shell commands)
例:
fileslist:=$(shell echo *.c)

7.Makefile調試功能

7.1makefile調試

常用的幾種調試方法:
https://www.cnblogs.com/AP0904225/p/5936465.html

7.2makefile 源碼調試

一般方式是通過makefile向源碼增加宏定義
main.c:
#ifdef DEBUG
.....
Makefile:
.PHONY: all clean

LINUX_ROOT=$(LINUX_SRC)

obj-m := sil9024.o

all:
    @make -C $(LINUX_ROOT) M=$(PWD) modules "CFLAGS += -DDEBUG"
    @cp sil9024.ko ../ko/  -vfr

clean:
    @make -C $(LINUX_ROOT) M=$(PWD) clean

8.隱含規則

這裏寫代碼片

9.寫在後面

非常感謝皓哥的《跟我一起寫Makefile》,之前看過一點,不過沒有機會全部瞭解,這次基本全部瞭解過,這是我的一點讀書筆記,主要參考的就是皓哥的這本書(姑且算書吧^-^),目的爲分析安卓源碼中的makefile打基礎,所以研究不是很深入,以後有時間再深入瞭解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章