0. 作用
Makefile文件告訴Make怎樣編譯和連接成一個(gè)程序扔茅。
1. Makefile基本語法與執(zhí)行
示例
編譯一個(gè)單文件HelloWorld.cpp
- 編寫
Makefile
HelloWorld : HelloWorld.cpp
g++ HelloWorld.cpp -o HelloWorld
clean :
rm HelloWorld
- 編譯
make
- 清空
make clean
構(gòu)成
Makefile主要由多條規(guī)則構(gòu)成已旧,每條規(guī)則由三部分構(gòu)成:目標(biāo)(target)、依賴(prerequiries)和命令(command)召娜。
格式
按如下格式編寫Makefile
目標(biāo)(target): 依賴(prerequiries)...
命令(command)
- 目標(biāo)(target)通常是要產(chǎn)生的文件的名稱运褪,目標(biāo)的例子是可執(zhí)行文件或OBJ文件。目標(biāo)也可是一個(gè)執(zhí)行的動作名稱玖瘸,諸如‘clean’(僅僅表達(dá)動作的目標(biāo)稱為假想目標(biāo))吐句。
- 依賴是用來輸入從而產(chǎn)生目標(biāo)的文件,一個(gè)目標(biāo)經(jīng)常有幾個(gè)依賴店读。
- 命令是Make執(zhí)行的動作,一個(gè)規(guī)則可以含有幾個(gè)命令攀芯,每個(gè)命令占一行屯断。
注意:每個(gè)命令行前面必須是一個(gè)Tab字符,即命令行第一個(gè)字符是Tab侣诺。這是不小心容易出錯的地方殖演。
說明
- 默認(rèn)情況下,
make
最先執(zhí)行第一條年鸳。 - 使用
make 目標(biāo)名
的方式趴久,執(zhí)行指定的規(guī)則。
2. Makefile多文件編譯
示例
String.h
#ifndef _STRING_H_
#define _STRING_H_
#include <iostream>
using namespace std;
#include <string.h>
class String{
public:
String(const char* cstr = NULL);
String(const String& str);
String& operator=(const String& str);
~String();
char* c_str() const {
return m_data;
}
private:
char* m_data;
};
ostream& operator<<(ostream& os, const String& str);
#endif // _STRING_H_
String.cpp
#include "String.h"
String::String(const char* cstr /*= NULL*/) {
if (cstr) {
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
}
else {
m_data = new char[1];
*m_data = '\0';
}
}
String::String(const String& str) {
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
}
String& String::operator=(const String& str) {
//檢測是否自我賦值
if (this == &str)
return *this;
delete [] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this;
}
String::~String() {
delete[] m_data;
}
ostream& operator<<(ostream& os, const String& str) {
os << str.c_str();
return os;
}
StringTest.cpp
#include "String.h"
int main() {
String s1;
String s2("hello");
String s3(s1); //拷貝構(gòu)造函數(shù)
cout << s3 << endl;
s3 = s2; //拷貝賦值函數(shù)
cout << s3 << endl;
return 0;
}
makefile
StringTest:StringTest.o String.o
g++ -o StringTest StringTest.o String.o
StringTest.o:StringTest.cpp String.h
g++ -c StringTest.cpp
String.o:String.cpp String.h
g++ -c String.cpp
clean :
rm StringTest StringTest.o String.o
說明
-
make
執(zhí)行規(guī)則之前搔确,檢查依賴是否存在或者是否最新的彼棍。如果不是則執(zhí)行依賴對應(yīng)的規(guī)則,創(chuàng)建或者更新依賴膳算。
3. 使用變量簡化makefile
每次增加新的文件座硕,需要在makefile的很多地方增加依賴,容易導(dǎo)致遺漏涕蜂』遥可以使用變量可以簡化,避免這種出錯的可能机隙。
- 變量定義:
變量 = 字符串
- 變量使用:
$(變量名)
示例
makefile
OBJS = StringTest.o String.o
StringTest:$(OBJS)
g++ -o StringTest $(OBJS)
StringTest.o:StringTest.cpp String.h
g++ -c StringTest.cpp
String.o:String.cpp String.h
g++ -c String.cpp
clean :
rm StringTest $(OBJS)
在makefile文件中使用名為
objects
,OBJECTS
,objs
,OBJS
,obj
, 或OBJ
的變量代表所有OBJ
文件已是約定成俗蜘拉。
說明
- 變量是定義一個(gè)字符串,在多處替代該字符串使用有鹿。
4. 命令自動推導(dǎo)
編譯.o
文件這類非常普遍并且常用旭旭,規(guī)則也比較簡單
文件名.o:文件名.cpp 頭文件
g++ -c 文件名.cpp
make提供一種簡化寫法,可以自動推導(dǎo)出該規(guī)則
文件名.o:頭文件
這種簡化規(guī)則稱為隱含規(guī)則印颤,非簡化規(guī)則成為具體規(guī)則您机。
示例
makefile
OBJS = StringTest.o String.o
StringTest:$(OBJS)
g++ -o StringTest $(OBJS)
StringTest.o:String.h
String.o:String.h
clean :
rm StringTest $(OBJS)
- 小知識
通常,規(guī)則按照目標(biāo)進(jìn)行分組。規(guī)則也可以按照依賴分組际看。例如咸产,例子中String.o
和StringTest.o
都依賴String.h
。那么仲闽,可以這兩個(gè)合并到一個(gè)規(guī)則中脑溢。OBJS = StringTest.o String.o StringTest:$(OBJS) g++ -o StringTest $(OBJS) StringTest.o String.o:String.h clean : rm StringTest $(OBJS)
按照依賴分組規(guī)則可以減少規(guī)則數(shù)量,規(guī)則按照目標(biāo)分組更符合我們?nèi)粘K季S習(xí)慣赖欣。
5. 假想目標(biāo)
表達(dá)動作的目標(biāo)稱為假想目標(biāo)屑彻。通常規(guī)則會生成或者更新與目標(biāo)的同名文件,但是假想目標(biāo)不生成文件顶吮,只是作為幾個(gè)命令組成特殊規(guī)則的名稱社牲。例如例子中的clean
,只是執(zhí)行清理動作悴了。如果搏恤,makefile同級目錄存在與假象目標(biāo)同名的文件(例如:clean
),那么會導(dǎo)致命令不會被執(zhí)行湃交。所以需要把目標(biāo)顯示聲明為假想目標(biāo)熟空。
.PHONY 目標(biāo)
示例
makefile
OBJS = StringTest.o String.o
.PHONY: all clean
all:StringTest
StringTest:$(OBJS)
g++ -o StringTest $(OBJS)
StringTest.o:String.h
String.o:String.h
clean :
rm StringTest $(OBJS)
- 常用假想目標(biāo)
No. | 假想目標(biāo) | 功能 |
---|---|---|
1 | all |
這所有目標(biāo)的目標(biāo),一般是編譯所有的目標(biāo)息罗。 |
2 | clean |
刪除所有被make創(chuàng)建的文件迈喉。 |
3 | install |
安裝已編譯好的程序弊添,就是把目標(biāo)執(zhí)行文件拷貝到指定的目標(biāo)中去。 |
4 | print |
列出改變過的源文件澈圈。 |
5 | tar |
源程序打tar包備份 |
6 | dist |
創(chuàng)建一個(gè)壓縮文件瞬女,一般是把tar文件壓成Z文件诽偷”剑或是gz文件眠冈。 |
6. 通配符與變量
編譯.o
文件可以寫成更通用的方式蜗顽,使用我們之前已經(jīng)定義好的變量$(OBJS)
雇盖,自動推導(dǎo)出需要生成的規(guī)則这弧。
makefile
OBJS = StringTest.o String.o
.PHONY: all clean
all:StringTest
StringTest:$(OBJS)
g++ -o StringTest $^
$(OBJS):%.o:%.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
.PHONY: clean
clean :
rm StringTest $(OBJS)
說明
1. 通配符
通配符主要用于匹配文件名,makefile中使用%
作為通配符卷哩。從匹配目標(biāo)格式的目標(biāo)名中依據(jù)通配符抽取部分字符串,再按照抽取字符串分配到每一個(gè)依賴格式中產(chǎn)生依賴名尊浓。例如栋齿,使用%.o:%.cpp
。
2. 自動變量
自動變量是在規(guī)則每次執(zhí)行時(shí)都基于目標(biāo)和依賴產(chǎn)生新值的變量菇用。下面是常用的自動變量惋鸥。
No. | 自動變量 | 含義 |
---|---|---|
1 | $< |
表示第一個(gè)匹配的依賴 |
2 | $@ |
表示目標(biāo) |
3 | $^ |
所有依賴 |
4 | $? |
所有依賴中更新的文件 |
5 | $+ |
所有依賴文件不去重 |
6 | $(@D) |
目標(biāo)文件路徑 |
7 | $(@F) |
目標(biāo)文件名稱 |
3. 預(yù)定義變量
預(yù)定義變量是makefile已經(jīng)定義好的變量,用戶可以在makefile文件中改變變量的值拴鸵。
- 程序名變量
No. | 變量 | 程序 | 默認(rèn)值 |
---|---|---|---|
1 | CC |
C語言編譯程序 | cc |
2 | CXX |
C++編譯程序 | g++ |
3 | AR |
C++打包程序 | ar |
4 | CPP |
帶有標(biāo)準(zhǔn)輸出的C語言預(yù)處理程序 | $(CC) -E |
5 | RM |
刪除命令 | rm |
- 程序運(yùn)行參數(shù)的變量
No. | 變量 | 程序參數(shù) |
---|---|---|
1 | CFLAGS |
用于C編譯器的額外標(biāo)志 |
2 | CXXFLAGS |
用于C++編譯器的額外標(biāo)志 |
3 | ARFLAGS |
用于C/C++打包器的額外標(biāo)志 |
4 | LDFLAGS |
鏈接庫路徑-L
|
5 | LDLIBS |
鏈接庫-l
|
9. 其他
- 注釋
#
- 換行
\
- 回顯命令
@echo