【C++ Makefile #1】嘗試撰寫自己的第一份 Makefile

前言

Makefile 可以是做為我們編譯一份 C++ 程式的索引,
類似一份說明書,告訴我們先處理哪一份 C++ 檔案後,再去處理哪一份檔案。

因此當撰寫到大型的 C++ 程式時,
我們都會需要 Makefile 來協助我們決定編譯 C++ 檔案的順序。

Makefile 簡介

其實 Makefile 跟 shell script 用途差不多,
我們有時候也會透過寫 shell script 來自動化執行一些 linux 指令。

而 Makefile 透過模組化的定義,更擅長處理一些大型程式的編譯。
通常是更有架構、更有組織的程式碼,我們都會使用 Makefile。

我們的第一份 Makefile

all: myfile

myfile:
    touch myfile

clean:
    rm -f myfile

說明

可以看到在這份裡面我們還沒有處理任何與 C++ 有關的東西,
沒錯,Makefile 並不是只能用來單純處理 C++ 的檔案 (只是常用,我剛開始學的時候也以為是 C++ 專用)

這份 Makefile 主要分成三個 part

  • all: myfile
    • all 會需要 myfile 這個項目
  • myfile: touch myfile
    • myfile 這個項目會去 touch myfile 這個檔案 (如果不存在就會產生)
  • clean: rm -f myfile
    • 我們去移除 myfile 這個檔案。
  • 執行指令的方式有:「make all」、「make myfile」、「make clean」,
    而通常使用上我們只會下「make all」、「make clean」,做為建檔與刪檔使用。

    註:如果我們在 terminal 只單純下 「make」 = 「make all」
    後來發現這是我的大誤會,單純下 make 會執行「makefile 的第一個 target」,只是這裡剛好是 all 而已

    補充 「make」 = 「make all」的誤會

    我之前一直以為 「make」 = 「make all」,
    總之結論是這是一個美麗的誤會,
    單純下 make 會執行「makefile 的第一個 target」,只是這裡剛好是 all 而已,
    我們進行以下的測試

    • Makefile 裡面寫下
    all2: 
        echo "touch2"
    all: 
        echo "touch3"
    clean:
        echo "clean"
    

    得到結果

    echo "touch2"
    touch2
    

    我們沒有得到全部的輸出 (包含clean),
    只有得到 touch2 的結果。

    表示他是執行 Makefile 內的第一個 target。

    常見問題:make: Nothing to be done for `all'

    在 makefile 學習的過程中,基本上應該都會踩過一次下面敘述的雷,
    我們來好好說明這是什麼意思。

    make: Nothing to be done for `all'
    

    這個要講到 makefile 的邏輯,
    makefile 只有在「兩種情況」下才會產生新檔案。

    • 目標檔案不存在
    • 「目標檔案依賴的檔案」比「目標檔案」更新

    第一點很好懂,不存在就是什麼都要從頭開始建。
    第二點講之前,我們先理解 Makefile 的語法:

    • 目標檔案:依賴的檔案(可為多個…, 依賴的檔案1 依賴的檔案2)

    換句話說,如果當「任何的檔案都沒有被更新時」,「make 這個指令就會覺得什麼事情都不需要做」。

    這就是「make: Nothing to be done for `all’」產生的原因。

    那要怎麼解決上面的問題?

    很簡單,但也最笨的方法就是,
    每一次都先「make clean,再 make」,就沒問題了。

    不過自己要先把 make clean 內容寫正確啊!! 不然是沒辦法避免這個錯誤的!

    make clean
    make # or make all
    

    Reference