這一節我們詳細看看makefile中關於變數的語法規則。先看乙個簡單的例子:
foo = $(bar)我們執行bar = huh?
all:
@echo $(foo)
make
將會打出huh?
。當make
讀到foo = $(bar)
時,確定foo
的值是$(bar)
,但並不立即展開$(bar)
,然後讀到bar = huh?
,確定bar
的值是huh?
,然後在執行規則all:
的命令列表時才需要展開$(foo)
,得到$(bar)
,再展開$(bar)
,得到huh?
。因此,雖然bar
的定義寫在foo
之後,$(foo)
展開還是能夠取到$(bar)
的值。
這種特性有好處也有壞處。好處是我們可以把變數的值推遲到後面定義,例如:
main.o: main.c編譯命令可以展開成$(cc) $(cflags) $(cppflags) -c $<
cc = gcc
cflags = -o -g
cppflags = -iinclude
gcc -o -g -iinclude -c main.c
。通常把cflags
定義成一些編譯選項,例如-o
、-g
等,而把cppflags
定義成一些預處理選項,例如-d
、-i
等。用=
號定義變數的延遲展開特性也有壞處,就是有可能寫出無窮遞迴的定義,例如cflags = $(cflags) -o
,或者:
a = $(b)當然,b = $(a)
make
有能力檢測出這樣的錯誤而不會陷入死迴圈。有時候我們希望make
在遇到變數定義時立即展開,可以用:=
運算子,例如:
x := foo當y := $(x) bar
all:
@echo "-$(y)-"
make
讀到y := $(x) bar
定義時,立即把$(x)
展開,使變數y
的取值是foo bar
,如果把這兩行顛倒過來:
y := $(x) bar那麼當x := foo
make
讀到y := $(x) bar
時,x
還沒有定義,展開為空值,所以y
的取值是␣bar
,注意bar
前面有個空格。乙個變數的定義從=
後面的第乙個非空白字元開始(從$(x)
的$
開始),包括後面的所有字元,直到注釋或換行之前結束。如果要定義乙個變數的值是乙個空格,可以這樣:
nullstring :=space := $(nullstring) # end of the line
nullstring
的值為空,space
的值是乙個空格,後面寫個注釋是為了增加可讀性,如果不寫注釋就換行,則很難看出$(nullstring)
後面有個空格。
還有乙個比較有用的賦值運算子是?=
,例如foo ?= $(bar)
的意思是:如果foo
沒有定義過,那麼?=
相當於=
,定義foo
的值是$(bar)
,但不立即展開;如果先前已經定義了foo
,則什麼也不做,不會給foo
重新賦值。
+=
運算子可以給變數追加值,例如:
objects = main.oobjects += $(foo)
foo = foo.o bar.o
object
是用=
定義的,+=
仍然保持=
的特性,objects
的值是main.o $(foo)
(注意$(foo)
前面自動添乙個空格),但不立即展開,等到後面需要展開$(objects)
時會展開成main.o foo.o bar.o
。
再比如:
objects := main.oobjects += $(foo)
foo = foo.o bar.o
object
是用:=
定義的,+=
保持:=
的特性,objects
的值是main.o $(foo)
,立即展開得到main.o
(這時foo
還沒定義),注意main.o
後面的空格仍保留。
如果變數還沒有定義過就直接用+=
賦值,那麼+=
相當於=
。
上一節我們用到了特殊變數$@
和$<
,這兩個變數的特點是不需要給它們賦值,在不同的上下文中它們自動取不同的值。常用的特殊變數有:
例如前面寫過的這條規則:
main: main.o stack.o maze.o可以改寫成:gcc main.o stack.o maze.o -o main
main: main.o stack.o maze.o這樣即使以後又往條件裡新增了新的目標檔案,編譯命令也不需要修改,減少了出錯的可能。gcc $^ -o $@
$?
變數也很有用,有時候希望只對更新過的條件進行操作,例如有乙個庫檔案libsome.a
依賴於幾個目標檔案:
libsome.a: foo.o bar.o lose.o win.o這樣,只有更新過的目標檔案才需要重新打包到ar r libsome.a $?
ranlib libsome.a
libsome.a
中,沒更新過的目標檔案原本已經在libsome.a
中了,不必重新打包。
在上一節我們看到make
的隱含規則資料庫中用到了很多變數,有些變數沒有定義(例如cflags
),有些變數定義了預設值(例如cc
),我們寫makefile時可以重新定義這些變數的值,也可以在預設值的基礎上追加。以下列舉一些常用的變數,請讀者體會其中的規律。
ar
靜態庫打包命令的名字,預設值是ar
。
arflags
靜態庫打包命令的選項,預設值是rv
。
as
彙編器的名字,預設值是as
。
asflags
彙編器的選項,沒有定義。
ccc編譯器的名字,預設值是cc
。
cflags
c編譯器的選項,沒有定義。
cxxc++編譯器的名字,預設值是g++
。
cxxflags
c++編譯器的選項,沒有定義。
cppc預處理器的名字,預設值是$(cc) -e
。
cppflags
c預處理器的選項,沒有定義。
ld鏈結器的名字,預設值是ld
。
ldflags
鏈結器的選項,沒有定義。
target_arch
和目標平台相關的命令列選項,沒有定義。
output_option
輸出的命令列選項,預設值是-o $@
。
link.o
把.o
檔案鏈結在一起的命令列,預設值是$(cc) $(ldflags) $(target_arch)
。
link.c
把.c
檔案鏈結在一起的命令列,預設值是$(cc) $(cflags) $(cppflags) $(ldflags) $(target_arch)
。
link.cc
把.cc
檔案(c++原始檔)鏈結在一起的命令列,預設值是$(cxx) $(cxxflags) $(cppflags) $(ldflags) $(target_arch)
。
compile.c
編譯.c
檔案的命令列,預設值是$(cc) $(cflags) $(cppflags) $(target_arch) -c
。
compile.cc
編譯.cc
檔案的命令列,預設值是$(cxx) $(cxxflags) $(cppflags) $(target_arch) -c
。
rm刪除命令的名字,預設值是rm -f
。
Makefile 常用變數
make的隱含規則資料庫中用到了很多變數,有些變數沒有定義 例如cflags 有些變數定義了預設值 例如cc 寫makefile時可以重新定義這些變數的值,也可以在預設值的基礎上追加。以下是一些常用的變數。ar 靜態庫打包命令的名字,預設值是ar。arflags 靜態庫打包命令的選項,預設值是rv。...
makefile自動變數
下面是所有的自動化變數及其說明 表示規則中的目標檔案集。在模式規則中,如果有多個目標,那麼,就是匹配於 目標中模式定義的集合。僅當目標是函式庫檔案中,表示規則中的目標成員名。例如,如果乙個目標是 foo.a bar.o 那麼,就是 bar.o 就是 foo.a 如果目標不是函式庫檔案 unix 下是...
Makefile之變數小解
變數對每乙個程式設計師再熟悉不過,每乙個程式語言都有自己的變數,makefile也不例外,下面就讓我們來看一下makefile怎麼定義和使用變數的吧!這裡我們先寫乙個例子 標頭檔案 apute.h include include include 第乙個c檔案foo.c,根據位址列印傳遞的字串 inc...