C++之Makefile語法與寫法


始、Makefile的規則

教學博客 系統性的博客2

關鍵:規則的嵌套——會先完成規則的先驗條件

   變量使用時都用${ }包圍起來,才能取到變量的實際值,否則取到的就是一個值為變量名的東西了。變量能賦值的,要不然怎么叫變量呢

  這里的變量在實際執行時,會被換成它們的實際值,變量名起簡化和占位符的作用。

 

一、變量與函數

1. 函數notdir,wildcard和patsubst

博客

這三個都是函數名,函數格式為:return = $(func arg1,arg2,..),即 $ 和 () 的結合。

例:將當前文件夾中所有以 .c為后綴的文件名替換為以 .o為后綴,並返回一個以空格為間隔的列表

SRC = $(patsubst %.c,%.o,${./})

 2. 邏輯判斷  ——參考博客

  ifeq (arg1, arg2):當arg1 == arg2 時,為true。

# 1. 連續的結構,只需要一個endif
ifeq (${mode}, TE)
    EXECUTABLE := te
else ifeq (${mode}, TR)
    EXECUTABLE := tr 
endif

# 2. 非連續的兩個結構,每個結構都需要一個endif
ifeq (${mode}, TE)
    EXECUTABLE := te
endif
ifeq (${mode}, TR)
    EXECUTABLE := tr
endif

 

  可以邏輯判斷實現條件編譯,如下,不同mode值將執行不同的規則。

ifeq (${mode}, train}
.PHONY : target ${TRAIN}
target : ${TRAIN}
else ifeq (${mode}, test}
.PHONY : target ${TEST}
target : ${TEST}
endif

 

 

二、Makefile中的自動化變量$@, $^, $< , $?, $%, $+, $* 等的含義  ——參考博客

$@   表示目標文件
$^   表示所有的依賴文件
$+   這個變量很像“$^”,也是所有依賴目標的集合。只是它不去除重復的依賴目標
$<   表示第一個依賴文件
$?   表示比目標還要新的依賴文件列表 
$%   僅當目標是函數庫文件時,表示規則中的目標成員名。例如,如果一個目標是“foo.a(bar.o)”,那么,“$%”就是“bar.o”,“$@”就是“foo.a”。如果目標不是函數庫文件(Unix下是[.a],Windows下是[.lib]),那么,其值為空

$*   這個變量表示目標模式中“%”及其之前的部分。如果目標是“dir/a.foo.b”,並且目標的模式是“a.%.b”,那么,“$*”的值就是“dir/a.foo”。這個變量對於構造有關聯的文件名是比較有較。
    如果目標中沒有模式的定義,那么“$*”也就不能被推導出,但是,如果目標文件的后綴是make所識別的,那么“$*”就是除了后綴的那一部分。例如:如果目標是“foo.c”,因為“.c”是make所能識別的后綴名,所以,“$*”的值就是“foo”。
    這個特性是GNU make的,很有可能不兼容於其它版本的make,所以,你應該盡量避免使用“$*”,除非是在隱含規則或是靜態模式中。如果目標中的后綴是make所不能識別的,那么“$*”就是空值。

 

三、規則  ——參考 博客

1. makefile中的規則的基本格式如下:

targets:dependeds
    commands

targets:要生成的文件(多個文件則以空格分開),或者是一個動作,可用稱為偽目標;若target為空(未賦值的變量),則該規則無效

dependeds:執行此規則所必須的依賴,可以是其它target,形成遞歸嵌套;所有依賴都滿足后才會執行command生成target;

command:規則所執行的命令,以tab鍵開始;規則后的所有連續的 以tab鍵開始的行 都會被視作command。tab、多個空格 二者是不等效的

eg:

...

main.o:main.cpp
    gcc -o main.o ...

test:test.o
  ...

.PHONY:clean
clean:
  rm -rf ...

  

  一次執行makefile,有一個最終目標,這個最終目標可能會帶動其它依賴目標的生成。

2. 規則的執行:

1)直接執行 make 時,先查找makefile中的第一個規則,以這個規則的目標(若有多個目標,則以第一個)為最終目標,完成這個規則的執行;  ==》如果要執行其它規則,需要指定目標,如 make test、 make clean

2)依賴項dependeds將從左往右檢查是否存在,如果需要執行其它嵌套的規則,會先執行,若不存在且無生成規則,則停止並放棄檢查后面的依賴項。

3)除了第一個規則或者指定的規則,.PHONY指定的目標也會在執行時生成。

  

3. 偽目標

  上面的clean是偽目標,所以也不會真正生成clean文件。由於它沒有依賴項,make無法判斷偽目標的依賴關系,所以要執行相關命令需要顯式地指定目標,如:make clean,這種規則每次指定時都一定會執行。

  .PHONY可以將目標顯示地聲明為偽目標。即使真的有一個文件和偽目標同名,.PHONY指定的偽目標的規則在執行時也不會生成文件。

  .PHONY也可以用於指定一個偽目標,該偽目標依賴於多個真實目標,如下: 

.PHONY:all  # .PHONY后面跟着all,all沒有具體的生成命令,但是all依賴於aa和bb,故而aa、bb會先生成
all:aa bb
aa: xxx
  ...

   偽目標每次要生成時都會生成,無論是否有更改;其它規則如果是未更改則不會重新生成。

* 遇到一個問題,以上面的.PHONY:all為例,會出現  make: Nothing to be donefor'all'. 

解決:改為以下寫法即可達到每次make都重新執行規定的目標

.PHONY:all aa bb
all:aa bb

.PHONY不影響第一規則為默認規則,若.PHONY所在規則不是第一規則,其指定的規則用make是不會默認執行的。

  下面寫法里,執行 make,則aa,bb都會生成,.PHONY行 和 偽目標all行可以調換順序,等效。

.PHONY:all aa bb
all:aa bb
aa: xxx
  ...

  下面的例子中,執行 make,只有aa會生成。

aa: xxx
  ...
.PHONY:all aa bb
all:aa bb

 

四、參數傳遞

一個例子 :這個用 -D 傳遞進去是一個宏,這個宏也可以賦值 更多

-DDEBUG   #相當於在代碼里面定義了 #define DEBUG 1
-DDEBUG=2  #相當於在代碼里面定義了 #define DEBUG 2。

另一個例子

Makefile文件:
 
ARCH := $(shell arch)
 
ifeq ($(ARCH), "x86_64")
SETTING := 1
else SETTING := 0
endif
 
CXX := g++ -std=c++11
CFLAGS := -Wall -g -O2 -D${SETTING}
ALL = main
OBJECT =  main.o
LIBS =
 
%.o:%.cpp
    $(CXX) -c $^ -o $@  $(LIBS) $(CFLAGS)
 
$(ALL):$(OBJECT)
    $(CXX) -o $@ $^ $(LIBS) $(CFLAGS)
 
.PHONY:clean
clean:
    rm -rf $(ALL) $(OBJECT)
// main.cpp
#include <iostream> using namespace std; int main(){ cout << "Hello World!" << endl; #ifdef SETTING cout<<"setting = 1"<<endl; #else cout<<"setting = 0"<<endl; #endif return 0; }

 

也可以用傳統的傳參方法,傳給main函數的argv。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM