**make**是一个在软件开发中所使用的工具程式（Utility software），經由讀取"makefile"的文件以自動化建構軟體。它是一種转化文件形式的工具，转换的目标称为"target"；与此同时，它也检查文件的依赖关系，如果需要的话，它会调用一些外部软件来完成任务。它的依赖关系检查系统非常简单，主要根据依赖文件的修改时间进行判断。大多数情况下，它被用来编译源代码，生成结果代码，然后把结果代码连接起来生成可执行文件或者库文件。它使用叫做"makefile"的文件来确定一个target文件的依赖关系，然后把生成这个target的相关命令传给shell去执行。

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

起源
--

目前虽有众多依赖关系检查工具，但是make是应用最广泛的一个。这要归功于它被包含在Unix系统中。斯圖亞特·費爾德曼（）在1977年在贝尔实验室（）里制作了这个软件。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如何运作。

```
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

```

当我们输入：

```
make
或者
make editor

```

当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。
于是，可有几种不同的输出：

* 第一次运行：

```
gcc -c main.c
gcc -c text.c
gcc -o editor main.o text.o

```

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

```
gcc -c main.c
gcc -o editor main.o text.o

```

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

```
gcc -c text.c
gcc -o editor main.o text.o

```

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

```
gcc -c main.c
gcc -c text.c
gcc -o editor main.o text.o

```

当我们输入：

```
make install

```

make会检查install的依赖editor是否是最新，如果是，则执行其下的命令"mv editor /usr/local"。由于这个过程并没有产生名为"install"的文件，所以，install是一个假目标。

  

### 巨集

"巨集"指的是用一个字符串代替另一个字符串的功能。在makefile中可以使用"="号来定义巨集，使用"$（巨集名）"来使用巨集；还可以用"+="追加巨集的内容。习惯上，巨集名使用大写。承接上面的例子：

```
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)

```

参见
--

* Apache Ant
* CMake

参考资料
----

1. 1 2  Thompson, T. J.. Bell System Technical Journal. November 1980, **59** (9): 1811–1825. doi:10.1002/j.1538-7305.1980.tb03063.x. In the general maintenance of DWB, we have used the Source Code Control System and make utility provided by the PWB/UNIX\* interactive operating system.
2. ↑ . tuhs.org. 1 September 2013  [18 March 2018]. （原始内容存档于2013-09-01）.
3. ↑  Feldman, S. I.. Software: Practice and Experience. April 1979, **9** (4): 255–265  [11 May 2016]. doi:10.1002/spe.4380090402. （原始内容存档于2020-09-14）.
4. ↑  Matthew Doar.. O'Reilly Media. 2005: 94. ISBN 978-0-596-00796-6.

外部链接
----

* GNU Make官方网站 （页面存档备份，存于）
* GNU make中文手册
* 跟我一起写Makefile （页面存档备份，存于）




|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
Unix命令行程序和shell内建命令 |
| --- |
|  |
| 文件系統 | 
* cat
* cd
* chmod
* chown
* chgrp
* cksum
* cmp
* cp
* dd
* du
* df
* file
* fsck
* fuser
* ln
* ls
* mkdir
* mount
* mv
* pax（英语：）
* pwd
* rm
* rmdir
* size
* split
* stat
* tee
* touch
* type（英语：）
* umask（英语：）

 |
|  |
| 程序 | 
* at
* bg
* chroot
* cron
* fg
* kill
* killall（英语：）
* nice
* pgrep
* pkill（英语：）
* ps
* pstree（英语：）
* time
* top

 |
|  |
| 用户环境 | 
* clear
* env
* exit
* history（英语：）
* id
* logname
* mesg（英语：）
* passwd
* su
* sudo
* uptime
* talk（英语：）
* tput（英语：）
* uname
* w
* wall（英语：）
* who
* whoami
* write（英语：）

 |
|  |
| 文本编辑 | 
* awk
* banner（英语：）
* basename
* comm（英语：）
* csplit（英语：）
* cut
* diff
* dirname
* ed
* ex
* fmt（英语：）
* fold（英语：）
* head（英语：）
* iconv
* join（英语：）
* less
* more
* nl（英语：）
* paste（英语：）
* sed
* sort（英语：）
* spell（英语：）
* strings（英语：）
* tail
* tr
* uniq（英语：）
* vi
* wc
* xargs

 |
|  |
| 壳层内建 | 
* alias
* echo
* printf格式字符串
* test（英语：）
* unset
* wait

 |
|  |
| 网络 | 
* dig
* host
* ifconfig
* inetd（英语：）
* netcat
* netstat
* nslookup
* ping
* rdate（英语：）
* rlogin（英语：）
* route
* ssh
* traceroute

 |
|  |
| 查找 | 
* find
* grep
* locate
* whatis（英语：）
* whereis

 |
|  |
| 文档 | 
* apropos（英语：）
* help（英语：）
* man

 |
|  |
| 软件开发 | 
* ar
* ctags
* lex
* make
* nm
* strip
* yacc

 |
|  |
| 杂项 | 
* bc
* cal
* dc
* expr
* lp（英语：）
* lpr
* sleep
* true和false
* yes

 |
|  |
| Unix实用程序列表 |

 |