make命令使用 & makefile編寫詳解


  • 為什么要使用make

先來想像一個案例,假設我的可執行文件里面包含了四個源代碼文件,分別是 main.c haha.c sin_value.c cos_value.c 這四個文件,這四個文件的目的是:

main.c :主要的目的是讓使用者輸入角度數據與調用其他三支副程序;

haha.c :輸出一堆有的沒有的訊息而已;

sin_value.c :計算使用者輸入的角度(360 sin 數值;

cos_value.c :計算使用者輸入的角度(360 cos 數值。

這四個文件你可以到 http://linux.vbird.org/linux_basic/0520source/main.tgz 來下載。由於這四個文件里面包含了相關性,並且還用到數學函數在里面,所以如果你想要讓這個程序可以跑, 那么就需要這樣編譯

# 1. 先進行目標文件的編譯,最終會有四個 *.o 的文件名出現:
[root@study ~]# gcc -c main.c
[root@study ~]# gcc -c haha.c
[root@study ~]# gcc -c sin_value.c
[root@study ~]# gcc -c cos_value.c
# 2. 再進行鏈接成為可執行文件,並加入 libm 的數學函數,以產生 main 可執行文件:
[root@study ~]# gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 3. 本程序的執行結果,必須輸入姓名、360 度角的角度值來計算:
[root@study ~]# ./main
Please input your name: VBird <==這里先輸入名字
Please enter the degree angle (ex> 90): 30 <==輸入以 360 度角為主的角度
Hi, Dear VBird, nice to meet you. <==這三行為輸出的結果喔!
The Sin is: 0.50
The Cos is: 0.87

編譯的過程需要進行好多動作啊!而且如果要重新編譯,則上述的流程得要重新來一遍,光是找出這些指令就夠煩人的了! 如果可以的話,能不能一個步驟就給他完成上面所有的動作呢?那就利用 make 這個工具吧! 先試看看在這個目錄下創建一個名為 makefile 的文件,內容如下:

# 1. 先編輯 makefile 這個規則檔,內容只要作出 main 這個可執行文件
[root@study ~]# vim makefile
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 注意:第二行的 gcc 之前是 <tab> 按鍵產生的空格喔!
# 2. 嘗試使用 makefile 制訂的規則進行編譯的行為:
[root@study ~]# rm -f main *.o <==先將之前的目標文件去除
[root@study ~]# make
cc -c -o main.o main.c
cc -c -o haha.o haha.c
cc -c -o sin_value.o sin_value.c
cc -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 此時 make 會去讀取 makefile 的內容,並根據內容直接去給他編譯相關的文件啰!
# 3. 在不刪除任何文件的情況下,重新執行一次編譯的動作:
[root@study ~]# make
make: `main' is up to date.
# 看到了吧!是否很方便呢!只會進行更新 (update) 的動作而已。

如此一來,將可大大的節省很多編譯的時間,要知道,某些程序在進行編譯的行為時,會消耗很多的 CPU

資源呢!所以說, make 有這些好處:

    • 簡化編譯時所需要下達的指令;
    • 若在編譯完成之后,修改了某個源代碼文件,則 make 僅會針對被修改了的文件進行編譯,其他的 object file 不會被更動;
    • 最后可以依照相依性來更新 update 可執行文件。

 

  • makefile語法

基本的 makefile 規則是這樣的:標的(di四聲)

標的(target): 目標文件1 目標文件2
<tab> gcc -o 欲創建的可執行文件 目標文件1 目標文件2

那個標的 target 就是我們想要創建的信息,而目標文件就是具有相關性的 object files ,那創建可執行文件的語法就是以 <tab> 按鍵開頭的那一行!特別給他留意喔,“命令列必須要以 tab 按鍵作為開頭”才行!他的規則基本上是這樣:

    • makefile 當中的 # 代表注解;
    • <tab> 需要在命令行 (例如 gcc 這個編譯器指令) 的第一個字符;
    • 標的 target 與相依文件(就是目標文件)之間需以“:”隔開。

同樣的,我們以剛剛上一個小節的范例進一步說明,如果我想要有兩個以上的執行動作時, 例如下達一個指令就直接清除掉所有的目標文件與可執行文件,該如何制作呢?

# 1. 先編輯 makefile 來創建新的規則,此規則的標的名稱為 clean :
[root@study ~]# vi makefile
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
clean:
rm -f main main.o haha.o sin_value.o cos_value.o
# 2. 以新的標的 (clean) 測試看看執行 make 的結果:
[root@study ~]# make clean <==就是這里!通過 make 以 clean 為標的
rm -rf main main.o haha.o sin_value.o cos_value.o

如此一來,我們的 makefile 里面就具有至少兩個標的,分別是 main clean ,如果我們想要創建 main 的話,輸入“make main”,如果想要清除有的沒的,輸入“make clean”即可啊!而如果想要先清除目標文件再編譯 main 這個程序的話,就可以這樣輸入:“make clean main”,如下所示:

[root@study ~]# make clean main
rm -rf main main.o haha.o sin_value.o cos_value.o
cc -c -o main.o main.c
cc -c -o haha.o haha.c
cc -c -o sin_value.o sin_value.c
cc -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm

這樣就很清楚了吧!但是,你是否會覺得,咦! makefile 里面怎么重復的數據這么多啊!沒錯!所以我們可以再借由 shell script 那時學到的“變量”來更簡化 makefile 喔:

[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
main: ${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}

bash shell script 的語法有點不太相同,變量的基本語法為:

  1. 變量與變量內容以“=”隔開,同時兩邊可以具有空格;

  2. 變量左邊不可以有 <tab> ,例如上面范例的第一行 LIBS 左邊不可以是 <tab>;

  3. 變量與變量內容在“=”兩邊不能具有“:”;

  4. 在習慣上,變量最好是以“大寫字母”為主;

  5. 運用變量時,以 ${變量} $(變量) 使用;

  6. 在該 shell 的環境變量是可以被套用的,例如提到的 CFLAGS 這個變量!

  7. 在指令列模式也可以給予變量。

由於 gcc 在進行編譯的行為時,會主動的去讀取 CFLAGS 這個環境變量,所以,你可以直接在 shell 定義出這個環境變量,也可以在makefile 文件里面去定義,更可以在指令列當中給予這個咚咚呢!例如:

[root@study ~]# CFLAGS="-Wall" make clean main
# 這個動作在上 make 進行編譯時,會去取用 CFLAGS 的變量內容!
也可以這樣:
[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}

咦!我可以利用指令列進行環境變量的輸入,也可以在文件內直接指定環境變量,那萬一這個 CFLAGS 的內容在指令列與 makefile 里面並不相同時,以那個方式輸入的為主?呵呵!問了個好問題啊! 環境變量取用的規則是這樣的:

  1. make 指令列后面加上的環境變量為優先;

  2. makefile 里面指定的環境變量第二;

  3. shell 原本具有的環境變量第三。

此外,還有一些特殊的變量需要了解的喔:

    •  $@:代表目前的標的(target)

所以我也可以將 makefile 改成:

[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
gcc -o $@ ${OBJS} ${LIBS} <==那個 $@ 就是 main !
clean:
rm -f main ${OBJS}

 

  

 

 

 

 

 

Over......

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM