學會使用makefile 3

2021-07-09 10:23:59 字數 2867 閱讀 5571

前面寫的makefile的相關只是都沒有使用到變數,依照變數,makefile可以使用的非常多變。

foo = $(bar)

bar = huh?

all:

@echo $(foo)

上面這個例子執行 make 將會打出 huh?當 make 讀到 foo = $(bar) 時,確定 foo 的值是 $(bar) ,但並不立即展開 $(bar) ,然後讀到 bar = huh? ,確定 bar 的值是 huh?

通過上面這個特點,我們可以講變數的值推遲到後面去定義:

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 等。

如果希望makefile在遇到賦值的時候立刻展開,可以使用:=來代替= ,下面這個例子

root@wc:~/codes/learn# cat makefile 

x := foo

y := $(x) bar!

all:

@echo "$(y)"

root@wc:~/codes/learn# make all

foo bar!

root@wc:~/codes/learn#

如果x 和 y的位置交換,那麼賦值的時候x會被展開成為乙個空值

還有一種有用的賦值運算子是?=:例如 foo ?= $(bar) 的意思是:如果 foo 沒有定義過,那麼 ?= 相當於 = ,定義 foo 的值是 $(bar) ,但不立即展開;如果先前已經定義了 foo ,則什麼也不做,不會給 foo 重新賦值。

另一種是+=,其可以給變數追加值,+=依舊保持著=或者:=的特性,主要看這個變數原先是怎麼定義的。如果變數還沒有定義過就直接用 += 賦值,那麼 += 相當於 = 。

類似$@這樣的特殊變數還有:

$@ ,表示規則中的目標。

$< ,表示規則中的第乙個條件。

$? ,表示規則中所有比目標新的條件,組成乙個列表,以空格分隔。

$^ ,表示規則中的所有條件,組成乙個列表,以空格分隔。

按照上面,下面的兩條語句實際上就是等價的了:

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 中了,不必重新打包。

第一節中可以看到預設規則中有很多變數,類似cc,cflags,cc預設值為cc,而cflags的預設值為空,類似的變數還有很多:

ar  靜態庫打包命令的名字,預設值是 ar 。

arflags 靜態庫打包命令的選項,預設值是 rv 。

as 彙編器的名字,預設值是 as 。

asflags 彙編器的選項,沒有定義。

cc c編譯器的名字,預設值是 cc 。

cflags c編譯器的選項,沒有定義。

cxx c++編譯器的名字,預設值是 g++ 。

cxxflags c++編譯器的選項,沒有定義。

cpp c預處理器的名字,預設值是 $(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 。

學會使用SafeArray

學會使用safearray也是很重要的,因為在ado程式設計中經常要用。它的主要目的是用於automation中的陣列型引數的傳遞。因為在網路環境中,陣列是不能直接傳遞的,而必須將其包裝成safearray。實質上safearray就是將通常的陣列增加乙個描述符,說明其維數 長度 邊界 元素型別等資...

學會使用Git

作為一名人民的好幹部,如果希望被惦記,可以學我們的鄭書記,將自己和藹可親的光輝形象搬上檯曆 作為一名有夢想有追求而又不知道如何出名的人,你可以參考對岸的 超想被包養 社團。而作為乙個核心愛好者,要想成為一名核心開發者,為核心貢獻自己的 我們必須要能夠與其他眾多的核心開發者協同工作,這就意味著應該能夠...

學會使用SafeArray

學會使用safearray也是很重要的,因為在ado程式設計中經常要用。它的主要目的是用於automation中的陣列型引數的傳遞。因為在網路環境中,陣列是不能直接傳遞的,而必須將其包裝成safearray。實質上safearray就是將通常的陣列增加乙個描述符,說明其維數 長度 邊界 元素型別等資...