鍍金池/ 教程/ C/ 練習(xí)2:用Make來(lái)代替Python
練習(xí)9:數(shù)組和字符串
練習(xí)6:變量類(lèi)型
練習(xí)3:格式化輸出
練習(xí)4:Valgrind 介紹
練習(xí)28:Makefile 進(jìn)階
練習(xí)14:編寫(xiě)并使用函數(shù)
練習(xí)21:高級(jí)數(shù)據(jù)類(lèi)型和控制結(jié)構(gòu)
練習(xí)20:Zed的強(qiáng)大的調(diào)試宏
練習(xí)18:函數(shù)指針
練習(xí)0:準(zhǔn)備
練習(xí)15:指針,可怕的指針
練習(xí)27:創(chuàng)造性和防御性編程
練習(xí)22:棧、作用域和全局
練習(xí)10:字符串?dāng)?shù)組和循環(huán)
練習(xí)8:大小和數(shù)組
練習(xí)16:結(jié)構(gòu)體和指向它們的指針
練習(xí)7:更多變量和一些算術(shù)
練習(xí)23:認(rèn)識(shí)達(dá)夫設(shè)備
練習(xí)12:If,Else If,Else
練習(xí)2:用Make來(lái)代替Python
練習(xí)1:?jiǎn)⒂镁幾g器
練習(xí)11:While循環(huán)和布爾表達(dá)式
練習(xí)5:一個(gè)C程序的結(jié)構(gòu)
練習(xí)24:輸入輸出和文件
練習(xí)25:變參函數(shù)
練習(xí)13:Switch語(yǔ)句
練習(xí)19:一個(gè)簡(jiǎn)單的對(duì)象系統(tǒng)
練習(xí)26:編寫(xiě)第一個(gè)真正的程序
導(dǎo)言:C的笛卡爾之夢(mèng)
練習(xí)17:堆和棧的內(nèi)存分配

練習(xí)2:用Make來(lái)代替Python

在Python中,你僅僅需要輸入python,就可以運(yùn)行你想要運(yùn)行的代碼。Python的解釋器會(huì)運(yùn)行它們,并且在運(yùn)行中導(dǎo)入它所需的庫(kù)和其它東西。C是完全不同的東西,你需要事先編譯你的源文件,并且手動(dòng)將它們整合為一個(gè)可以自己運(yùn)行的二進(jìn)制文件。手動(dòng)來(lái)做這些事情很痛苦,在上一個(gè)練習(xí)中只需要運(yùn)行make就能完成。

這個(gè)練習(xí)是GNU make 的速成課,由于你在學(xué)C語(yǔ)言,所以你就必須掌握它。Make 將貫穿剩下的課程,等效于Python(命令)。它會(huì)構(gòu)建源碼,執(zhí)行測(cè)試,設(shè)置一些選項(xiàng)以及為你做所有Python通常會(huì)做的事情。

有所不同的是,我會(huì)向你展示一些更智能化的Makefile魔法,你不需要指出你的C程序的每一個(gè)愚蠢的細(xì)節(jié)來(lái)構(gòu)建它。我不會(huì)在練習(xí)中那樣做,但是你需要先用一段時(shí)間的“低級(jí) make”,我才能向你演示“大師級(jí)的make”。

使用 Make

使用make的第一階段就是用它已知的方式來(lái)構(gòu)建程序。Make預(yù)置了一些知識(shí),來(lái)從其它文件構(gòu)建多種文件。上一個(gè)練習(xí)中,你已經(jīng)使用像下面的命令來(lái)這樣做了:

$ make ex1
# or this one too
$ CFLAGS="-Wall" make ex1

第一個(gè)命令中你告訴make,“我想創(chuàng)建名為ex1的文件”。于是Make執(zhí)行下面的動(dòng)作:

  • 文件ex1存在嗎?
  • 沒(méi)有。好的,有沒(méi)有其他文件以ex1開(kāi)頭?
  • 有,叫做ex1.c。我知道如何構(gòu)建.c文件嗎?
  • 是的,我會(huì)運(yùn)行命令cc ex1.c -o ex1來(lái)構(gòu)建它。
  • 我將使用ccex1.c文件來(lái)為你構(gòu)建ex1。

上面列出的第二條命令是一種向make命令傳遞“修改器”的途徑。如果你不熟悉Unix shell如何工作,你可以創(chuàng)建這些“環(huán)境變量”,它們會(huì)在程序運(yùn)行時(shí)生效。有時(shí)你會(huì)用一條類(lèi)似于export CFLAGS="-Wall"的命令來(lái)執(zhí)行相同的事情,取決于你所用的shell。然而你可以僅僅把它們放到你想執(zhí)行的命令前面,于是環(huán)境變量只會(huì)在程序運(yùn)行時(shí)有效。

在這個(gè)例子中我執(zhí)行了CFLAGS="-Wall" make ex1,所以它會(huì)給make通常使用的cc命令添加-Wall選項(xiàng)。這行命令告訴cc編譯器要報(bào)告所有的警告(然而實(shí)際上不可能報(bào)告所有警告)。

實(shí)際上你可以深入探索使用make的上述方法,但是先讓我們來(lái)看看Makefile,以便讓你對(duì)make了解得更多一點(diǎn)。首先,創(chuàng)建文件并寫(xiě)入以下內(nèi)容:

CFLAGS=-Wall -g

clean:
    rm -f ex1

將文件在你的當(dāng)前文件夾上保存為Makefile。Make會(huì)自動(dòng)假設(shè)當(dāng)前文件夾中有一個(gè)叫做Makefile的文件,并且會(huì)執(zhí)行它。此外,一定要注意:確保你只輸入了 TAB 字符,而不是空格和 TAB 的混合。

譯者注:上述代碼中第四行rm前面是一個(gè) TAB ,而不是多個(gè)等量的空格。

Makefile向你展示了make的一些新功能。首先我們?cè)谖募性O(shè)置CFLAGS,所以之后就不用再設(shè)置了。并且,我們添加了-g標(biāo)識(shí)來(lái)獲取調(diào)試信息。接著我們寫(xiě)了一個(gè)叫做clean的部分,它告訴make如何清理我們的小項(xiàng)目。

確保它和你的ex1.c文件在相同的目錄中,之后運(yùn)行以下命令:

$ make clean
$ make ex1

你會(huì)看到什么

如果代碼能正常工作,你應(yīng)該看到這些:

$ 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'
$

你可以看出來(lái)我執(zhí)行了make clean,它告訴make執(zhí)行我們的clean目標(biāo)。再去看一眼Makefile,之后你會(huì)看到在它的下面,我縮進(jìn)并且輸入了一些想要make為我運(yùn)行的shell命令。你可以在此處輸入任意多的命令,所以它是一個(gè)非常棒的自動(dòng)化工具。

如果你修改了ex1.c,添加了#include<stdio>,輸出中的關(guān)于puts的警告就會(huì)消失(這其實(shí)應(yīng)該算作一個(gè)錯(cuò)誤)。我這里有警告是因?yàn)槲也](méi)有去掉它。

同時(shí)也要注意,即使我們?cè)?code>Makefile中并沒(méi)有提到ex1make仍然會(huì)知道如何構(gòu)建它,以及使用我們指定的設(shè)置。

如何使它崩潰

上面那些已經(jīng)足夠讓你起步了,但是讓我們以一種特定的方式來(lái)破壞make文件,以便你可以看到發(fā)生了什么。找到rm -f ex1的那一行并去掉縮進(jìn)(讓它左移),之后你可以看到發(fā)生了什么。再次運(yùn)行make clean,你就會(huì)得到下面的信息:

$ make clean
Makefile:4: *** missing separator.  Stop.

永遠(yuǎn)記住要縮進(jìn),以及如果你得到了像這種奇奇怪怪的錯(cuò)誤,應(yīng)該復(fù)查你是否都使用了 TAB 字符,由于一些make的變種十分挑剔。

附加題

  • 創(chuàng)建目標(biāo)all:ex1,可以以單個(gè)命令make構(gòu)建ex1
  • 閱讀man make來(lái)了解關(guān)于如何執(zhí)行它的更多信息。
  • 閱讀man cc來(lái)了解關(guān)于-Wall-g行為的更多信息。
  • 在互聯(lián)網(wǎng)上搜索Makefile文件,看看你是否能改進(jìn)你的文件。
  • 在另一個(gè)C語(yǔ)言項(xiàng)目中找到Makefile文件,并且嘗試?yán)斫馑隽耸裁础?/li>