Makefile基本規則和原理

chenwr2018發表於2019-03-03

閱讀《跟我一起寫makefile》,摘錄文章個人認為有助於理解的語句,並記錄自己驗證實踐的過程,方便自己後續工作中複習。

一、基本規則

target ... : prerequisites ... command

  • target 是一個目標檔案(makefile支援多目標),可以是 Object File,也可以是執行檔案,還可以是一個標籤(Label)。
  • prerequisites 生成 target 所需要的檔案或是目標。
  • command 為 make 需要執行的命令。(任意的 Shell 命令)

這是一個檔案的依賴關係,也就是說,target 這一個或多個的目標檔案依賴於prerequisites 中的檔案,其生成規則定義在 command 中。說白一點就是說,prerequisites中如果有一個以上的檔案比 target 檔案要新的話,command 所定義的命令就會被執行。這就是 Makefile 的規則。也就是 Makefile 中最核心的內容。

二、最基本的例項

顯式規則,依賴關係寫的比較清楚。

run: main.o hello.o test.o
    gcc -o run main.o hello.o test.o
main.o: main.c
    gcc -c main.c
hello.o: hello.c
    gcc -c hello.c
test.o: test.c
    gcc -c test.c
clean:
    rm run *.o
複製程式碼

執行結果:

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make run
gcc -c main.c
gcc -c hello.c
gcc -c test.c
gcc -o run main.o hello.o test.o
複製程式碼

run所需要的依賴檔案不存在時,執行下一語句。待依賴檔案生成時,繼續執行run對應的命令。

如果依賴的test.o檔案沒有生成的規則,makefile會自動產生規則去生成test.o檔案。這個特性就是隱晦規則,主要靠make自動推導。只要 make 看到一個[.o]檔案,它就會自動的把[.c]檔案加在依賴關係中,如自動把test.c加入到依賴關係中,並且cc -c -o test.o test.c也會被推匯出來。

刪除該語句測試
test.o: test.c
    gcc -c test.c
複製程式碼

執行結果:

gcc -c main.c
gcc -c hello.c
cc    -c -o test.o test.c
gcc -o run main.o hello.o test.o
複製程式碼

如果沒有test.c檔案則無法生成,直接終止執行。

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make run
gcc -c main.c
gcc -c hello.c
make: *** No rule to make target `test.o', needed by `run'.  Stop.
複製程式碼

make 並不管命令是怎麼工作的,他只管執行所定義的命令。 make 會比較 targets 檔案和 prerequisites 檔案的修改日期,如果 prerequisites 檔案的日期要比 targets 檔案的日期要新,或者 target 不存在的話,那麼,make 就會執行後續定義的命令。我發覺書上這句話有點問題。 測試把hello.c檔案刪除後,即無法生成hello.o這個target,執行make run,結果如下

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make run
gcc -c main.c
make: *** No rule to make target `hello.c', needed by `hello.o'.  Stop.
複製程式碼

後續定義的語句並不會去執行,直接終止。

test.o: test.c
    gcc -c test.c
複製程式碼

原來是我理解錯誤了,書中後面提到: 在找尋的過程中,如果出現錯誤,比如最後被依賴的檔案找不到,那麼make 就會直接退出,並報錯,而對於所定義的命令的錯誤,或是編譯不成功,make 根本不理。make 只管檔案的依賴性,即,如果在我找了依賴關係之後,冒號後面的檔案還是不在,那麼對不起,我就不工作啦。 這個target不存在,是指上一次編譯生成的run,已經不存在需要執行對應的command來產生。並且大前提是整個makefile的依賴關係正確和編譯命令所需的檔案是存在的情況下。

三、基本原理

  1. make 會在當前目錄下找名字叫“Makefile”或“makefile”的檔案。
  2. 如果找到,它會找檔案中的第一個目標檔案(target),例項中第一個目標target為run
  3. 如果 run 檔案不存在,或是run 所依賴的後面的 .o 檔案的檔案修改時間要比 run這個檔案新,那麼,他就會執行後面所定義的命令來生成 run這個檔案。(根據這個特性,我每次修改相應的檔案時候,有依賴關係的檔案都會重新編譯和連結。其實完全可以不用make clean,畢竟大型原始碼重新編譯一次是很耗費時間的。)
  4. 如果run所依賴的.o 檔案也存在,那麼 make 會在當前檔案中找目標為.o 檔案的依賴關係,也按照第3點的判斷依據來更新生成.o檔案。
  5. 如果run依賴關係中比如test.o的生成規則沒在makefile檔案中體現,make會自動產生規則並生成test.o檔案,前提是test.c存在當前目錄下,否則直接終止執行。
  6. 最終根據對應的依賴關係生成run這個可執行檔案。

相關文章