Make

Make是一個在軟體開發中所使用的構建工具，用於自動化建構軟體。它通過一個名為 Makefile 的文本文件來描述原始碼文件之間的依賴關係和構建規則。Make 會根據這些規則和依賴關係，判斷哪些文件需要重新編譯，並執行相應的編譯命令，以確保最終生成可執行文件或其他目標文件（這些目標被稱為「target」）。大多數情況下，它被用來編譯原始碼，生成結果代碼，然後把結果代碼連接起來生成可執行文件或者庫文件。

許多現代軟體的開發環境中（如Microsoft Visual Studio），集成開發環境已經取代make，但是在Unix環境中，仍然有許多工程師採用make來協助軟體開發。

## 起源

目前雖有眾多依賴關係檢查工具，但是make是應用最廣泛的一個。這要歸功於它被包含在Unix系統中。斯圖亞特·費爾德曼（Stuart Feldman）在1977年在貝爾實驗室（Bell Labs）里製作了這個軟體。2003年，斯圖亞特·費爾德曼因發明了這樣一個重要的工具而接受了美國電腦協會（ACM）頒發的軟體系統獎。

在make誕生之前，編譯工作主要依賴於作業系統裡面的類似於「make」、「install」功能的shell腳本。它可以批量執行生成目標的命令，並且可以完成依賴關係的檢查。這是向現代編譯環境發展的重要一步。

## 不同版本

make程序已被使用者多次重/改寫，其中包括幾次用相同的文件格式和算法原理重新編寫，並且依照不同需要添加了一些不常見的改良。

### GNU make

GNU make仿照make的標準功能（透過clean-room工程）重新改寫，並加入作者覺得值得加入的新功能，常和GNU編譯系統一起被使用，是大多數GNU Linux安裝的一部分。

### BSD make

BSD make是從Adam de Boor的製作的版本上發展成。它編譯目標的時候有並行計算的能力。它在FreeBSD，NetBSD和OpenBSD中不同程度的修改下存活了下來。

### Microsoft nmake

廣泛應用於微軟的Windows，微軟的nmake是 Visual Studio 隨附的命令行工具，不要與來自AT&T和貝爾實驗室的Unix系統nmake混淆。

## 優點和缺點

就像其他和make有著悠久歷史的軟體一樣，make有著很多的擁護者和反對者。它的很多問題因現代大型的軟體項目的出現而暴露出來。但是很多人爭論說它在常見的情況下可以很好的工作，而且使用非常的簡單，功能強大，表達清楚。無論如何，make仍然被用來編譯很多完整的作業系統，而且現在替代品們在基本的操作上與它沒有太大差別。

隨著現代的集成開發環境（IDE）的誕生，特別是非Unix的平台上，很多程式設計師不再手動管理依靠關係檢查，甚至不用去管哪些文件是這個項目的一部分，而是把這些任務交給了他們的開發環境去做。類似的，很多現代的程式語言有自己特別的高效的依賴關係的設置方法。

## Makefile

### 規則

makefile的格式是：

```
   # 用“#”号表明注释。
   target（要生成的文件）: dependencies（被依赖的文件）
   	# 命令前面用的是“tab”而非空格。误用空格是初学者容易犯的错误！
   TAB命令1
   TAB命令2
   TAB命令3
         .
   	  .
   	  .
   TAB命令n
   # 可以使用“\”表示续行。注意，“\”之后不能有空格！
```

- target, dependencies和命令構成了一個makefile里的一個「規則」，規則指示make何時以及如何重新生成target或執行target下的命令
- target通常是我們要生成的文件的名字，擺放的順序不重要，但第一個target是默認的target。當make不帶參數時，自動執行第一個target。target也可以是要求make完成的動作，執行這種target後並不能得到和target同名的文件，因此，也稱為偽target(phony target)。
- dependencies是生成target所需的文件名列表。依賴可以為空，常用的「clean」target就常常沒有依賴，只有命令。若依賴不為空，則make會先檢查依賴的「規則」。依賴規定了何時重新執行target下命令。若任何依賴比target更新 （由於執行了依賴的「規則」的命令或使用者修改了依賴），make則會重新執行target下的命令。
- 命令可以是任何一個shell能運行的命令。

### 示例

舉例來說明makefile的結構和make如何運作。

```make
editor: main.o text.o
	gcc -o editor main.o text.o
main.o: main.c def.h
	gcc -c main.c
text.o: text.c com.h
	gcc -c text.c
install:editor
	mv editor /usr/local
```

當我們輸入：

```
<nowiki>
make
或者
make editor
</nowiki>
```

當editor這個target文件不存在，或者main.o、text.o這兩個依賴文件被修改，都會導致make調用其下的命令「gcc -o editor main.o text.o」；接下來，由於引用到main.o和text.o，make會檢查main.o的依賴main.c、def.h有無更新，如果有，則執行其下的命令「gcc -c main.c」；同樣的道理，也適用於text.o。

於是，可有幾種不同的輸出：

```
<nowiki>
gcc -c main.c
gcc -c text.c
gcc -o editor main.o text.o
</nowiki>
```

- main.c或/和def.h有修改：

```
<nowiki>
gcc -c main.c
gcc -o editor main.o text.o
</nowiki>
```

- text.c或/和com.h有修改：

```
<nowiki>
gcc -c text.c
gcc -o editor main.o text.o
</nowiki>
```

- main.c和text.c均有修改：

```
<nowiki>
gcc -c main.c
gcc -c text.c
gcc -o editor main.o text.o
</nowiki>
```

當我們輸入：

```
<nowiki>
make install
</nowiki>
```

make會檢查install的依賴editor是否是最新，如果是，則執行其下的命令「mv editor /usr/local」。由於這個過程並沒有產生名為「install」的文件，所以，install是一個假目標。

### 巨集

「巨集」指的是用一個字串代替另一個字串的功能。在makefile中可以使用「=」號來定義巨集，使用「$（巨集名）」來使用巨集；還可以用「+=」追加巨集的內容。習慣上，巨集名使用大寫。承接上面的例子：

```make
OBJECTS = main.o text.o
INSTALL_PATH = /usr/local
editor: $(OBJECTS)
	gcc -o editor $(OBJECTS)
main.o: main.c
	gcc -c main.c
text.o: text.c
	gcc -c text.c
install:editor
	mv editor $(INSTALL_PATH)
```

## 基本資料

- 編程范型：巨集, 宣告式編程
- 設計者：斯圖亞特·費爾德曼
- 發行日期：1976年
- 實作語言：C 語言
- 作業系統：類 Unix 系統
- 檔案格式：Makefile