徹底掌握Makefile(二)

2022-09-23 18:00:41

徹底掌握Makefile(二)

前言

在前面的文章徹底掌握Makefile(一)當中,我們簡要的介紹了一些常見的makefile使用方法,在本篇文章當中我們將繼續介紹一些makefile當中的常見用法。

Makefile中的條件判斷

ifeq 和 ifneq

我們在寫makefile的時候常常會有通過if語句進行判斷的需求,比如說根據不同的檔案設定不同的編譯器等等。

cc=g++

main: demo.c
	echo $(cc)

ifeq ($(cc), gcc)
	echo $(cc) = 相等的語句執行了
else
	echo $(cc) != 不相等的語句執行了
endif

上面的makeifle的執行結果如下:

在上面的makefile當中定義了一個變數cc,他的值為gcc。在上面的makefile當中ifeq表示如果後邊的表示式成立的話,也就是$(cc)的值等於gcc那麼就執行後面的語句,否則執行else後面的語句。根據上面makefile的執行結果來看,$(cc)和gcc不相等,因此和我們的期待的結果是一致的。

我們修改上面的makefile檔案如下:

cc=g++

main: demo.c
	echo $(cc)

ifneq ($(cc), gcc)
	echo $(cc) != gcc
else
	echo $(cc) = gcc
endif

執行上面的makefile檔案輸出的結果如下:

在上面的makefile當中ifneq的含義表示如果不相等,因為g++不等於gcc,因此這個滿足條件,程式執行的結果滿足條件。

關於make的輸出問題,當makefile執行到echo $(cc) != gcc的時候,首先這條命令會被make輸出,然後make會執行這條命令,而這條命令是輸出g++ != gcc,因此才會有上面的輸出。echo g++ != gcc,而執行這條命令還會輸出g++ != gcc,看到這應該能夠理解上面的makefile的輸出結果了。

前面兩個關鍵字的語法如下所示:

ifeq (<arg1>, <arg2>)
ifeq '<arg1>' '<arg2>'
ifeq "<arg1>" "<arg2>"
ifeq "<arg1>" '<arg2>'
ifeq '<arg1>' "<arg2>"

ifneq (<arg1>, <arg2>)
ifneq '<arg1>' '<arg2>'
ifneq "<arg1>" "<arg2>"
ifneq "<arg1>" '<arg2>'
ifneq '<arg1>' "<arg2>"

ifdef 和 ifndef

除了上面的兩個關鍵字之外,make還給我們提供了另外兩個關鍵字ifdefifndef

ifdefifndef用於判斷表示式是否定義過,或者是否為空:

foo = 1
main: demo.c
	echo demo
ifdef foo
	echo define foo
else
	echo not define foo
endif

上面的makefile的輸出結果如下:

在上面的makefile當中我們定義了foo,因此ifdef判斷正確,輸出define foo,現在修改上面的makefile如下所示說:

main: demo.c
	echo demo
ifdef foo
	echo define foo
else
	echo not define foo
endif

在上面的makefile當中我們沒有定義foo,因此在上面的makefile當中會輸出not define foot

我們在來看一個結果比較令人疑惑的makefile:

foo = 
main: demo.c
	echo demo
ifdef foo
	echo define foo
else
	echo not define foo
endif

在上面的makefile當中我們定義了foo,但是他沒有值,我們看一下這個makefile的輸出結果:

上面makefile的輸出表示foo沒有被定義,因此當我們定義一個空變數的時候和不定義的效果是一樣的。

bar =
foo = $(bar)
main: demo.c
	echo demo
ifdef foo
	echo define foo
else
	echo not define foo
endif

在上面的makefile當中我們定義了一個空的變數bar但是我們令foot=$(bar)我們看一下上面的makefile檔案的輸出:

可以看出是定義了foo的雖然foo的真實的值也為空,從這裡也可以看出ifdefifndef在進行判斷的時候並不會將變數直接展開,而是直接判斷成不為空。

Makfile中的函數

在makefile當中除了能夠使用條件表示式之外我們還可以使用函數,在makefile當中函數的使用規則如下:

$(<函數名> <函數引數>)
或者
將()替換為{}

函數的呼叫規則如上圖所示,函數引數用,隔開。

字串函數

subst

$(subst <from>,<to>,<text>)
  • 字串替換函數。
  • 表示文字,這個函數會將text當中是的字串替換為
s = ii am learning makefile
ss = $(subst ii, you, $(s))

main: demo.c
	echo demo
	echo $(s)
	echo $(ss)

上面的makefile執行結果如下圖所示:

從上面的結果我們可以看出,確實將字串s當中的ii替換成了you!

patsubst

$(patsubst <pattern>,<replacement>,<text>)
  • pattern 表示第一個引數,用於表示如何對 text 進行匹配。
  • replacement 表示第二個引數 表示如何對匹配的字元進行重寫。
  • patsubst在進行匹配替換的時候,會先將字串text根據空格或者tab鍵或者回車換行符進行分割,然後一一的進行替換和匹配。

這個函數也是一個字串替換函數,但是與上面的函數不同的是這是一個模式替換。我們直接根據例子來進行分析:

s = a.c b.c d.c abc.c abo.c
ss = $(patsubst %.c, %.o, $(s))

main: demo.c
	echo demo
	echo $(s)
	echo $(ss)

執行make命令上面的makefile的輸出結果如下圖所示:

從上面的結果我們可以看出,patsubst函數將所有的.c檔案的字尾都變成了.o。

  • 在上面的makefile當中首先會將$(s)當中的字串按照回車換行、空格以及tab鍵將$(s)當中的進行分割,然後一個一個進行patsubst操作,然後將得到結果合併起來。

  • 在上面的patsubst函數當中%符號是一個萬用字元,他匹配了.c前面的所有符號。

  • 在pattern當中的符號為"%.c",這個表示用%匹配了.c前面的所有的字元。

  • 在replacement當中的字串為"%.o",這個%用於表示在pattern當中匹配到的字串,比如對於abo.c來說%就代表了abo,因此被替換的字串就是abo.o。

你如果你對Python有所瞭解的話,那麼上面的替換程式碼等價的Python程式碼如下所示:

Strip

$(strip <string>)
  • 主要功能去掉字串 string 首尾的空格。

findstring

$(findstring <find>,<text>)
  • 這個函數的作用是從字串當中尋找字串,如果找到了字串就返回字串,否則返回空。

filter

$(filter <pattern...>,<text>)

這是一個過濾函數,這個函數執行時,首先會根據空格或者tab鍵或者回車換行符進行分割,然後一一的進行filter函數的操作。然後遍歷每一個被分割出來的字元,如果不滿足pattern的規則的話對應的字元就會被過濾掉。

s = a.c abo.c s.o s.y x.o x.y
ss = $(filter %.c %.o, $(s))

main: demo.c
	echo $(ss)

上面的makefile執行之後輸出的結果如下圖所示:

可以看過濾掉了不是以.c和.o結尾的檔案。

上面的過濾函數對應的Python程式碼如下所示:


filter-out

這個函數和filter的用法是一樣的只不過,作用剛好相反,filter是儲存符合條件的字串,filter-out是儲存不符合條件的字串。

s = a.c abo.c s.o s.y x.o x.y
ss = $(filter-out %.c %.o, $(s))

main: demo.c
	echo $(ss)

sort

這個函數主要是用於幫助字串排序的,同時還會取出分割之後相同的字串。

s = g a b c d e f  a a a a 
ss = $(sort $(s))

main: demo.c
	echo $(ss)

以上的makefile輸出結果如下圖所示:

從上面的輸出結果我們可以驗證sort不僅可以給字串排序還會去除相同的字串。

word

$(word <n>,<text>)

這個功能很簡單,返回當中第個字元。

s = g a b c d e f  a a a a 
ss = $(word 1, $(s)) # 取出第一個字元

main: demo.c
	echo $(ss)

wordlist

$(wordlist <start>,<end>,<text>)

這個也是從字串當中取出字元,是取出第個字元一直到第個字元。

s = g a b c d e f  a a a a 
ss = $(wordlist 1, 5, $(s))

main: demo.c
	echo $(ss)

words

統計單詞的個數。

s = 1 2 3 4 5
ss = $(words $(s))

main: demo.c
	echo $(ss)

firstword

這個函數主要是用於返回第一個字串的。

s = 1 2 3 4 5
ss = $(firstword $(s))

main: demo.c
	echo $(ss)

在本篇文章當中主要給大家介紹了Makefile當中一些常用的函數和條件語句的使用,整體比較簡單,大家可以對照著makefile和結果自己實現一遍,下期我們將在makefile當中的一些其他的函數!


以上就是本篇文章的所有內容了,我是LeHung,我們下期再見!!!更多精彩內容合集可存取專案:https://github.com/Chang-LeHung/CSCore

關注公眾號:一無是處的研究僧,瞭解更多計算機(Java、Python、計算機系統基礎、演演算法與資料結構)知識。