# 練習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了解得更多一點。首先,創建文件并寫入以下內容:
```Makefile
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” 已死