徹底掌握Makeifle(三)

2022-09-25 06:01:27

徹底掌握Makeifle(三)

前言

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

Makefile中與檔案相關的函數

dir與notdir函數

file = ./files/a.c
fdir = $(dir $(file))
nfdir = $(notdir $(file))

main: demo.c
	echo $(fdir)
	echo $(nfdir)

dir函數主要書獲取檔案路徑當中的目錄部分,而notdir函數主要是獲取檔案路徑當中檔名的部分,執行上面的makefile結果如下所示:

suffix函數

這個函數主要是用於獲取檔案的字尾名。

file = ./files/a.c
fdir = $(dir $(file))
nfdir = $(notdir $(file))
name = $(suffix $(file))
main: demo.c
	echo $(fdir)
	echo $(nfdir)
	echo $(name)

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

basename

這個函數用於獲取檔案路徑當中除去字尾名的部分。

file = ./files/a.c
base = $(basename $(file))
main: demo.c
	echo $(base)

addsuffix

這個函數主要是給檔案加上字尾的。

file = ./files/a.c
base = $(addsuffix .c, $(file))
main: demo.c
	echo $(base)

上面的程式碼執行結果如下:

上面的結果就表示在檔案的末尾加上了對應的字尾名。

addprefix

這個函數的主要作用就是在字串的前面加上一串字元。

file = files/a.c
base = $(addprefix ./src/main/, $(file))
main: demo.c
	echo $(base)

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

迴圈函數foreach

foreach函數的主要使用規則為:

$(foreach <var>,<list>,<text>)

我們直接使用一個例子來說明這個情況:

files = a.c b.c c.c d.c
new_files = $(foreach n, $(files), $(n)pp)
main: demo.c
	echo $(new_files)

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

foreach函數會將files當中的字串先按照空格、tab鍵、回車換行符進行分割,然後將分割後的值一個一個的放入變數n當中,然後會產生一個字串$(n)pp,最終將這些字串通過空格拼接起來並且賦值給new_files,這才會有最終的結果。

上面的過程對應一個python程式碼如下所示:

call函數

call函數在makefile當中可以用於呼叫我們自定義的一個表示式,他的語法個數如下面所示:

$(call <expression>,<parm1>,<parm2>,...,<parmn>)
  • 表示定義的表示式的名字。
  • 表示第n個引數,我們在當中可以使用$(n)進行參照。

我們現在有一個需求就是將兩個字元中間加上多個橫槓,比如下面的makefile。

a=a.c
b=b.c
c=$(a)-------$(b)
main: demo.c
	echo $(c)

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

但是如果我們想要重複實現這個功能的話,我們就不需要每次都去寫這樣一個表示式,而是我們應該寫一個表示式然後進行呼叫。

a=a.c
b=b.c
c=$(1)-------$(2) # 定義表示式c $(1) 表示使用第一個引數 $(2) 表示使用第二個引數
main: demo.c
	echo $(call c, $(a), $(b)) # c 就是定義好的表示式 這裡呼叫表示式c

上面的makefile輸出結果和上面一樣:

在makefile當中使用shell函數

我們在makefile的表示式當中可以使用shell的函數。

比如現在我們有一個檔案叫做test.txt,檔案的內容如下所示:

a.c b.c c.c d.c

我們的makefile內容如下:

content=$(shell cat test.txt) # 將shell命令的輸出內容賦給content

main: demo.c
	echo $(content) # 輸出content

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

origin函數

origin這個函數主要是返回變數的定義方式,使用格式如下:

$(origin <variable>) # 其中 variable 是變數名字 這裡不需要使用 $ 符號去參照

這個函數的輸出結果又下面這些值:

undefined

如果 <variable> 從來沒有定義過,origin函數返回這個值 undefined

default

如果 <variable> 是一個預設的定義,比如「CC」這個變數。

GNU make預設變數:

  • AR-->歸檔維護程式的名稱,預設值為ar
  • ARFLAGS-->歸檔維護程式的選項
  • AS-->組合程式的名稱,預設值為as
  • ASFLAGS-->組合程式的選項
  • CC-->C編譯器的名稱,預設為gcc
  • CPP-->C預編譯器的名稱
  • CCFLAGS-->C編譯器的選項
  • CPPFLAGS-->C預編譯的選項
  • CXX-->C++編譯器的名稱,預設為g++
  • CXXFLAGS-->C++編譯器的選項
  • FC-->FORTRAN編譯器的名稱,預設為f77
  • FFLAGS-->FORTRAN編譯器的選項
environment

variable是一個環境變數。

file

如果 <variable> 這個變數被定義在Makefile中。

command line

如果 <variable> 這個變數是被命令列定義的。

override

如果 <variable> 是被override指示符重新定義的,關於override的使用,請檢視本文彩蛋部分。

現在我們舉一個例子,去看看上面這些值對應的例子:

override var = aaaa
file=file
main: demo.c
	echo $(origin file) # makefile 內部定義的
	echo $(origin data) # 命令列定義的
	@echo $(origin var) # override 重寫
	@echo $(origin JAVA_HOME) # JAVA_HOME 是一個環境變數
	@echo $(origin CXX) # 預設定義的變數

我們現在使用make命令測試一下上面的makefile輸出結果:

error函數

在makefile當中我們可以使用error函數讓makefie停止執行。當我們有需求:讓在某種條件下讓makefile停止編譯

data=data

ifeq ($(data), data)
$(error "data == data")
endif

main: main.c
	gcc main.c

現在我們執行makefile,輸出結果如下:

還有一個函數warning使用方法和上面一樣用於產生警告。

彩蛋

@符號

有時候在makefile當中我們不想輸出某些命令(如果不進行設定makefile會輸出每一條我們執行過的命令),比如下面的makefile。

main: demo.c
	echo hello world

上面的makefile輸出結果為:

現在我們不想輸出echo hello world這條命令,我們可以使用@進行修飾,在makefile當中如果一條命令使用@進行了修飾,那麼這條命令就不會輸出。

main: demo.c
	@echo hello world

上面的makefile輸出結果如下:

override使用

在使用make命令的時候可以進行變數的設定,這個變數我們可以在makefile檔案當中使用:

main: demo.c
	@echo $(var)  # 使用變數 var

我們現在輸入make命令並且指定引數然後檢視結果:

可以看到我們指定的變數在makefile當中可以使用了。

但是如果在我們的makefile當中也有一個變數叫做var那麼makefile當中的var就會被覆蓋。比如像下面這個例子一樣:

如果我們想讓我們自己的變數起作用的話我們可以使用override:

總結

在本篇文章當中主要給大家介紹了Makefile當中一些常用的函數的使用,整體比較簡單,大家可以對照著makefile和結果自己實現一遍。


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

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