# 练习2:用Make来代替Python
> 原文:[Exercise 2: Make Is Your Python Now](http://c.learncodethehardway.org/book/ex2.html)
> 译者:[飞龙](https://github.com/wizardforcel)
在Python中,你仅仅需要输入`python`,就可以运行你想要运行的代码。Python的解释器会运行它们,并且在运行中导入它所需的库和其它东西。C是完全不同的东西,你需要事先编译你的源文件,并且手动将它们整合为一个可以自己运行的二进制文件。手动来做这些事情很痛苦,在上一个练习中只需要运行`make`就能完成。
这个练习是GNU make 的速成课,由于你在学C语言,所以你就必须掌握它。Make 将贯穿剩下的课程,等效于Python(命令)。它会构建源码,执行测试,设置一些选项以及为你做所有Python通常会做的事情。
有所不同的是,我会向你展示一些更智能化的Makefile魔法,你不需要指出你的C程序的每一个愚蠢的细节来构建它。我不会在练习中那样做,但是你需要先用一段时间的“低级 make”,我才能向你演示“大师级的make”。
## 使用 Make
使用make的第一阶段就是用它已知的方式来构建程序。Make预置了一些知识,来从其它文件构建多种文件。上一个练习中,你已经使用像下面的命令来这样做了:
```sh
$ make ex1
# or this one too
$ CFLAGS="-Wall" make ex1
```
第一个命令中你告诉make,“我想创建名为ex1的文件”。于是Make执行下面的动作:
+ 文件`ex1`存在吗?
+ 没有。好的,有没有其他文件以`ex1`开头?
+ 有,叫做`ex1.c`。我知道如何构建`.c`文件吗?
+ 是的,我会运行命令`cc ex1.c -o ex1`来构建它。
+ 我将使用`cc`从`ex1.c`文件来为你构建`ex1`。
上面列出的第二条命令是一种向make命令传递“修改器”的途径。如果你不熟悉Unix shell如何工作,你可以创建这些“环境变量”,它们会在程序运行时生效。有时你会用一条类似于`export CFLAGS="-Wall"`的命令来执行相同的事情,取决于你所用的shell。然而你可以仅仅把它们放到你想执行的命令前面,于是环境变量只会在程序运行时有效。
在这个例子中我执行了`CFLAGS="-Wall" make ex1`,所以它会给make通常使用的`cc`命令添加`-Wall`选项。这行命令告诉`cc`编译器要报告所有的警告(然而实际上不可能报告所有警告)。
实际上你可以深入探索使用make的上述方法,但是先让我们来看看`Makefile`,以便让你对make了解得更多一点。首先,创建文件并写入以下内容:
```make
CFLAGS=-Wall -g
clean:
rm -f ex1
```
将文件在你的当前文件夹上保存为`Makefile`。Make会自动假设当前文件夹中有一个叫做`Makefile`的文件,并且会执行它。此外,一定要注意:确保你只输入了 TAB 字符,而不是空格和 TAB 的混合。
> 译者注:上述代码中第四行`rm`前面是一个 TAB ,而不是多个等量的空格。
`Makefile`向你展示了make的一些新功能。首先我们在文件中设置`CFLAGS`,所以之后就不用再设置了。并且,我们添加了`-g`标识来获取调试信息。接着我们写了一个叫做`clean`的部分,它告诉make如何清理我们的小项目。
确保它和你的`ex1.c`文件在相同的目录中,之后运行以下命令:
```sh
$ make clean
$ make ex1
```
## 你会看到什么
如果代码能正常工作,你应该看到这些:
```sh
$ make clean
rm -f ex1
$ make ex1
cc -Wall -g ex1.c -o ex1
ex1.c: In function 'main':
ex1.c:3: warning: implicit declaration of function 'puts'
$
```
你可以看出来我执行了`make clean`,它告诉make执行我们的`clean`目标。再去看一眼Makefile,之后你会看到在它的下面,我缩进并且输入了一些想要make为我运行的shell命令。你可以在此处输入任意多的命令,所以它是一个非常棒的自动化工具。
> 注
> 如果你修改了`ex1.c`,添加了`#include<stdio>`,输出中的关于`puts`的警告就会消失(这其实应该算作一个错误)。我这里有警告是因为我并没有去掉它。
同时也要注意,即使我们在`Makefile`中并没有提到`ex1`,`make`仍然会知道如何构建它,以及使用我们指定的设置。
## 如何使它崩溃
上面那些已经足够让你起步了,但是让我们以一种特定的方式来破坏make文件,以便你可以看到发生了什么。找到`rm -f ex1`的那一行并去掉缩进(让它左移),之后你可以看到发生了什么。再次运行`make clean`,你就会得到下面的信息:
```sh
$ make clean
Makefile:4: *** missing separator. Stop.
```
永远记住要缩进,以及如果你得到了像这种奇奇怪怪的错误,应该复查你是否都使用了 TAB 字符,由于一些make的变种十分挑剔。
## 附加题
+ 创建目标`all:ex1`,可以以单个命令`make`构建`ex1`。
+ 阅读`man make`来了解关于如何执行它的更多信息。
+ 阅读`man cc`来了解关于`-Wall`和`-g`行为的更多信息。
+ 在互联网上搜索Makefile文件,看看你是否能改进你的文件。
+ 在另一个C语言项目中找到`Makefile`文件,并且尝试理解它做了什么。
- 笨办法学C 中文版
- 前言
- 导言:C的笛卡尔之梦
- 练习0:准备
- 练习1:启用编译器
- 练习2:用Make来代替Python
- 练习3:格式化输出
- 练习4:Valgrind 介绍
- 练习5:一个C程序的结构
- 练习6:变量类型
- 练习7:更多变量和一些算术
- 练习8:大小和数组
- 练习9:数组和字符串
- 练习10:字符串数组和循环
- 练习11:While循环和布尔表达式
- 练习12:If,Else If,Else
- 练习13:Switch语句
- 练习14:编写并使用函数
- 练习15:指针,可怕的指针
- 练习16:结构体和指向它们的指针
- 练习17:堆和栈的内存分配
- 练习18:函数指针
- 练习19:一个简单的对象系统
- 练习20:Zed的强大的调试宏
- 练习21:高级数据类型和控制结构
- 练习22:栈、作用域和全局
- 练习23:认识达夫设备
- 练习24:输入输出和文件
- 练习25:变参函数
- 练习26:编写第一个真正的程序
- 练习27:创造性和防御性编程
- 练习28:Makefile 进阶
- 练习29:库和链接
- 练习30:自动化测试
- 练习31:代码调试
- 练习32:双向链表
- 练习33:链表算法
- 练习34:动态数组
- 练习35:排序和搜索
- 练习36:更安全的字符串
- 练习37:哈希表
- 练习38:哈希算法
- 练习39:字符串算法
- 练习40:二叉搜索树
- 练习41:将 Cachegrind 和 Callgrind 用于性能调优
- 练习42:栈和队列
- 练习43:一个简单的统计引擎
- 练习44:环形缓冲区
- 练习45:一个简单的TCP/IP客户端
- 练习46:三叉搜索树
- 练习47:一个快速的URL路由
- 后记:“解构 K&R C” 已死
- 捐赠名单