【Makefile】5-Makefile變數的基礎

李柱明發表於2020-11-28


前言

  • 本筆記主要記錄Makefile一些概念要點。

概念

Chapter 5:變數的基礎

  • 變數可以使用在 目標依賴目標命令 或是 Makefile的其它部分中

  • 變數的名字可以包含 字元、數字和下劃線(可以以數字開頭)

    • 但是不應該包含有 : # = 空格 回車 等特殊字元。
    • 變數名具有大小寫敏感特性。(推薦大小寫搭配使用)
  • 變數賦值時,會自動刪除等號 = 兩邊的空格,但是,變數值後面的空格會保留,直至遇到 結束符或註釋符 **

5.1 變數的基礎 *

  • 使用變數時需要在變數前面新增 $ 符號,表示去該變數的值。
    • 推薦在取值時給變數新增上 (){}
    • 如果需要使用真實的 $ ,就用 $$ 即可。
  • 取變數值其實就是相當於 C/C++ 中的巨集展開一樣,其實還是字串替換。
  • 注:推薦看例子。*
    • 賦值時要注意後面的空格和註釋符 #
      • 註釋符 # 可以表示終止一個變數的定義。
      • 例子:
        • /foo/bar 後面還跟了幾個 空格,如果使用到 $(dir)/file ,那 路徑就錯誤了。
dir := /foo/bar      # directory to put the frobs indir := /foo/bar # directory to put the frobs in

空格的定義 **

  • 先定義一個空變數 empty
  • 然後用 $ 符號取出 + 空格 + 註釋符 #
    • 因為 註釋符 # 可以結束一個變數的賦值。
    • 不用註釋符 # 也可以,只是怕空格的數量不對才用 註釋符 # 表示一下而已。
empty:=
a = $(empty) #

一些賦值

 變數定義語法:

形式 說明
A = xxx 延時變數
B ?= xxx 延時變數,只有第一次定義時賦值才成功,若曾被定義過,則此賦值無效。
C := xxx 立即變數
D += yyy 如果D在前面是延時變數,那麼現在它還是延時變數
如果D在前面是立即變數,那麼它現在還是立即變數

一些特殊的符號

符號 說明
$@ 表示規則中的目標檔案集
$% 當目標為函式庫的時候,則表示規則中的目標成員名。反之為空。如一個目標為"foo.a(bar.o)",那麼,"$%"就是"bar.o",以空格分隔開。
$< 依賴檔案集合中的第一個檔案,如果依賴檔案以"%"形式出現,則表示符合模式的一系列檔案集合
$? 所有比目標新的依賴集合,以空格分隔開。
$^ 所有依賴檔案集合,以空格分隔開。如果依賴有相同,則取其一。
$+ 和 "$^"類同,但是不會把相同的刪除掉。
$* 這個變數表示目標模式中 "%"及其之前的部分,如果目標是 test/a.test.c,目標模式為 a.%.c, 那麼 "$* " 就是 test/a.test。

5.2 變數中的變數 *

  • = 號右側可以是值,也可以是變數*
  • 如果 = 右側是 變數,那麼該 變數 可以定義在檔案的任何一處(就是 延時變數 =)。(但是不推薦使用該方法

  • 為了避免上面第二點的操作,一般使用 即時變數 := 來賦值,例子:
    • y 的值是 foo bar
x := foo
y := $(x) bar
x := later
* y 的值是 **bar**
y := $(x) bar
x := food

5.3 變數高階用法

  • 變數值替換
  • 把變數的值再變成變數

變數值替換

  • 替換變數中的共有的部分
    • 格式
      • $(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)

把變數的值再當成變數

  • 直接上例子:
ifdef do_sort
func := sort
else
func := strip
endif
bar := a d b g q c
foo := $($(func) $(bar))
  • 用在操作符左邊:
dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c)
define $(dir)_print
lpr $($(dir)_sources)
endef

5.5 override 指示符

  • 通常在執行 make 時,如果通過命令列定義了一個變數,那麼它將替代在 Makefile 中出現的同名變數的定義。
  • 如果不希望命令列指定的變數值替代在 Makefile 中的變數定義,那麼我們需要在 Makefile 中使用指示符 override 來對這個變數進行宣告,如:
override <variable>; = <value>;
# 或
override <variable>; := <value>;
# 或
override <variable>; += <more text>;
# 或
override define foo
bar
endef

5.6 多行變數

  • 相當於 C 中的函式
  • 關鍵字 define。(使用該該關鍵字可以有 換行
  • 例子
define two-lines
echo foo
echo $(bar)
endef

5.7 環境變數

  • make 執行時的系統環境變數可以在 make 開始執行時被載入到 Makefile 檔案中,但是如果 Makefile中已定義了這個變數,或是這個變數由 make 命令列帶入,那麼系統的環境變數的值將被覆蓋。(如果make 指定了“-e”引數,那麼,系統環境變數將覆蓋 Makefi le 中定義的變數)

5.8 目標變數

  • 為某個目標設定區域性變數,這種變數被稱為Target-specifi c Variable
  • 範圍只在這條規則以及連帶規則中
  • 語法
    • ; 可以是前面講過的各種賦值表示式,如 = := += 或是 ?=
<target ...> : <variable-assignment>;
<target ...> : overide <variable-assignment>
  • 例子
    • 在這個示例中,不管全域性的 $(CFLAGS) 的值是什麼,在 prog 目標,以及其所引發的所有規則中(prog.o foo.o bar.o 的規則),$(CFLAGS) 的值都是 -g
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
    $(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o : prog.c
    $(CC) $(CFLAGS) prog.c
foo.o : foo.c
    $(CC) $(CFLAGS) foo.c
bar.o : bar.c
    $(CC) $(CFLAGS) bar.c

5.9 模式變數

  • 就是把上面 目標變數 中的具體目標改為一種模式(一條語句(表達一種模式))。
  • 語法
<pattern ...>; : <variable-assignment>;
<pattern ...>; : override <variable-assignment>;
  • 例子:就是把 prog 改為 %.o%.o 就是一種模式,所有 .o 結尾的都符合該模式。
%.o : CFLAGS = -O

參考

  • 《GUN Makefile》
  • 《跟我一起寫Makefile》

相關文章