Makefile基礎 變數

2021-06-19 23:31:54 字數 4903 閱讀 1712

這一節我們詳細看看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.o

objects += $(foo)

foo = foo.o bar.o

object是用=定義的,+=仍然保持=的特性,objects的值是main.o $(foo)(注意$(foo)前面自動添乙個空格),但不立即展開,等到後面需要展開$(objects)時會展開成main.o foo.o bar.o

再比如:

objects := main.o

objects += $(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...