Makefile入門

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í)行的動(dòng)作名稱,諸如‘clean’(僅僅表達(dá)動(dòng)作的目標(biāo)稱為假想目標(biāo))。
  • 依賴是用來輸入從而產(chǎn)生目標(biāo)的文件,一個(gè)目標(biāo)經(jīng)常有幾個(gè)依賴。
  • 命令是Make執(zhí)行的動(dòng)作,一個(gè)規(guī)則可以含有幾個(gè)命令,每個(gè)命令占一行。

注意:每個(gè)命令行前面必須是一個(gè)Tab字符,即命令行第一個(gè)字符是Tab。這是不小心容易出錯(cuò)的地方。

說明

  1. 默認(rèn)情況下,make最先執(zhí)行第一條。
  2. 使用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) {
    //檢測(cè)是否自我賦值
    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

說明

  1. make執(zhí)行規(guī)則之前,檢查依賴是否存在或者是否最新的。如果不是則執(zhí)行依賴對(duì)應(yīng)的規(guī)則,創(chuàng)建或者更新依賴。

3. 使用變量簡(jiǎn)化makefile

每次增加新的文件,需要在makefile的很多地方增加依賴,容易導(dǎo)致遺漏??梢允褂米兞靠梢院?jiǎn)化,避免這種出錯(cuò)的可能。

  • 變量定義:變量 = 字符串
  • 變量使用:$(變量名)

示例

  • 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文件已是約定成俗。

說明

  1. 變量是定義一個(gè)字符串,在多處替代該字符串使用。

4. 命令自動(dòng)推導(dǎo)

編譯.o文件這類非常普遍并且常用,規(guī)則也比較簡(jiǎn)單

文件名.o:文件名.cpp 頭文件
  g++ -c 文件名.cpp

make提供一種簡(jiǎn)化寫法,可以自動(dòng)推導(dǎo)出該規(guī)則

文件名.o:頭文件

這種簡(jiǎn)化規(guī)則稱為隱含規(guī)則,非簡(jiǎn)化規(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)
  • 小知識(shí)
    通常,規(guī)則按照目標(biāo)進(jìn)行分組。規(guī)則也可以按照依賴分組。例如,例子中String.oStringTest.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á)動(dòng)作的目標(biāo)稱為假想目標(biāo)。通常規(guī)則會(huì)生成或者更新與目標(biāo)的同名文件,但是假想目標(biāo)不生成文件,只是作為幾個(gè)命令組成特殊規(guī)則的名稱。例如例子中的clean,只是執(zhí)行清理動(dòng)作。如果,makefile同級(jí)目錄存在與假象目標(biāo)同名的文件(例如:clean),那么會(huì)導(dǎo)致命令不會(huì)被執(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文件?;蚴莋z文件。

6. 通配符與變量

編譯.o文件可以寫成更通用的方式,使用我們之前已經(jīng)定義好的變量$(OBJS),自動(dòng)推導(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. 自動(dòng)變量

自動(dòng)變量是在規(guī)則每次執(zhí)行時(shí)都基于目標(biāo)和依賴產(chǎn)生新值的變量。下面是常用的自動(dòng)變量。

No. 自動(dòng)變量 含義
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

10. 總結(jié)

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一.makefile格式 1.makefile 文件一般命名 為makefile 即可,放在目錄下面,直接調(diào)出 t...
    浩林Leon閱讀 8,090評(píng)論 0 2
  • 來自陳浩的一片老文,但絕對(duì)營(yíng)養(yǎng)。 示例工程:3 個(gè)頭文件*.h,和 8 個(gè) C 文件*.c。 初 編譯過程,源文件...
    周筱魯閱讀 4,779評(píng)論 0 17
  • 通常一個(gè)大型程序由多個(gè)模塊文件構(gòu)成的,按照其功能劃分,模塊文件會(huì)分布在不同的目錄中,模塊文件之間有包含有頭文件,調(diào)...
    wayyyy閱讀 1,420評(píng)論 0 0
  • makefile關(guān)系到整個(gè)工程的編譯規(guī)則,一個(gè)工程中的源文件不計(jì)其數(shù),按其類型、功能、模塊分別放在若干的目錄當(dāng)中,...
    Joe_HUST閱讀 1,977評(píng)論 0 3
  • 洛陽王利華 堅(jiān)持分享第220(2017.12.18)天: 今天給學(xué)生們做了一個(gè)“猜猜看”的游戲。猜之前每...
    驕陽567閱讀 305評(píng)論 0 0

友情鏈接更多精彩內(nèi)容