Makefile,從最最基礎的說起...

最近在用烏邦圖的c++寫一個小項目,才寫了幾個程序文件。

寫程序總免不了修改,特別是在剛開始的時候,需要這樣試試,那樣試試,找找感覺,也是爲以後的編程找一個比較好的思路。

但凡程序裏有一個小小的改動,就要把項目全部編譯一遍,細算起來,居然也浪費不少的時間。

一開始覺得項目小,沒有必要弄個Makefile,沒想到沒有它還真不行。

最初的想法是到網上找一個Makefile模板,改改用比較省事。結果找到了一個,打開看了個一頭霧水。竟然啥也不懂!

沒辦法,再找找大神們發的帖子,一點點學起來。總算發現Makefile雖然博大精深,但核心的東西還是很好理解的,對小項目來說,用起來還真不難。

寫Makefile的初衷,無非就是想省點時間,只編譯改動過的程序文件,沒改的就不用再編譯了,恰恰Makefile就是幹這個活的。

比如,在Makefile文件裏寫上:

main.o: main.cpp main.hpp
    gcc -c $^

大部分內容都是一目瞭然,可能$^看起來有些頭暈,不要着急,下面細細說來。

學習c++的一定會知道,從源程序文件到可執行程序,一般說要分兩步,第一步是編譯,從源文件生成目標文件,在這個例子裏,是從main.cpp編譯成main.o。第二步是連接,把目標文件和用到的一些庫組裝成一個可執行的程序。上面的Makefile裏只寫了第一步,編譯。

main.o是目標,它是從程序文件main.cpp和頭文件main.hpp編譯後產生的,main.cpp和main.hpp叫做main.o的依賴。

第二行是編譯命令,執行這個命令後,main.cpp和main.hpp就變成了main.o。

那麼$^到底是什麼呢?其實它就是第一行冒號後面的內容,在這個例子裏就是main.cpp main.hpp,執行命令的時候,是這樣的:

gcc -c main.cpp main.hpp

寫好Makefile後,用make命令執行。

執行make命令的時候,它就會在當前目錄下找Makefile或者makefile文件,如果找到了,就比較目標文件和依賴文件的日期,如果目標文件比較新,就不執行命令,如果依賴文件日期比較新,就執行命令。通過這個操作,達到只編譯新改動文件的目的。

還是說上面這個例子,如果main.cpp和main.hpp中有一個時間比main.o新,就執行gcc -c main.cpp main.hpp命令。

假如main.cpp和main.hpp剛寫完,還沒有main.o文件呢?當然是看作main.cpp和main.hpp比main.o新,肯要執行命令了!

總結一下Makefile的最基本格式:

目標:依賴
<tab> 命令

如果依賴文件的日期比目標文件的日期新,就執行命令,否則不執行。注意,命令一定是用tab縮進的,不能是空格,這是make的硬規定,沒有爲什麼。

好吧,到現在我的項目裏纔有4個程序文件,寫出的Makefile如下:

main: main.o read.o write.o data.o
    gcc -o $@ $^ -lstdc++

main.o: main.cpp main.hpp
    gcc -c $^

read.o: read.cpp read.hpp
    gcc -c $^

write.o: write.cpp write.hpp
    gcc -c $^

data.o: data.cpp data.hpp
    gcc -c $^

每個命令前面的縮進,需要按一下鍵盤左面的Tab鍵,如果你的編輯器把tab自動轉爲空格,需要把這個轉換功能關掉。

第二行裏又多了一個$@,不用解釋你可能就猜到了,它表示冒號前面的內容。翻譯一下就是:

gcc -o main main.o read.o write.o data.o -lstdc++

這個文件在說,我需要一個名稱是main的可執行文件,是用幾個.o文件和庫文件連接後生成的,在生成之前呢,要把每個.o文件和它的依賴文件做一下比較,看看是否需要重新編譯。

假如成功編譯之後,只改動了data.hpp中的內容,在執行make命令時,就只編譯data.cpp,其它的幾個.cpp文件就不再編譯了。通過Makefile這種操作,節省了不必要的編譯時間。

隨着我的項目不斷擴展,這點兒知識肯定不能滿足我的需要了,我還會繼續學習,到時,再和大家一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章