一個工程中的源文件不計其數,按照不同的功能分類在若干的目錄里面,makefile定義了一系列的規則,來制定那些文件需要先編譯,那些文件后編譯,那些文件重新編譯。makefile最大的好處就是自動化編譯。一旦寫好,只需要一個make命令,整個過程都自動編譯。極大提高開發的效率。我們先來看個簡單的例子:
如果一個工程里面有1個頭文件calc.h和2個C文件main.c,calc.c
main.c的內容如下:
#include "stdio.h"
#include "calc.h"
int main()
{
int n,k;
int c;
n=3;
k=4;
c=calculate(n,k);
printf("the value is %d\n",c);
}
calc.c的內容如下:
#include "calc.h"
int calculate(int n,int k)
{
return n*k;
}
calc.h的內容如下:
#ifdef CALC_H
#define CALC_H
int calculate(int n,int k);
#endif
為了完成對工程文件案的編譯,並生成執行文件main,按照如下的方式編譯文件
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# gcc main.c calc.c -o main
但是如果我對main.c做了修改。就需要把所有源文件都重新編譯一遍,即使其他文件沒有任何變化。也要跟着重新編譯。一個大的軟件項目上千個源文件組成,編譯一次耗時很長。一個源文件修改導致全部重新編譯肯定不合理。我們可以這樣優化下:
gcc -c main.c
gcc -c calc.c
gcc main.o calc.o -o main
如果編譯之后有對main.c做了修改,重新編譯之需要兩步:
gcc -c main.c
gcc main.o calc.o -o main
這樣比之前的要省事一些了,但還是有問題,在calc.c和main.c都包含了calc.h。如果我對calc.h做了改動。所有包含calc.h的文件都得改動。而且還得到處去找那些包含了calc.h。還是很麻煩。比如在calc.h中增加了一個宏定義。並且在man.c和calc.c中都有用到這個變量。那么一旦calc.h修改了宏定義變量的值。calc.c和main.c都必須重新編譯。
#define max_value 40
那么我們需要一種什么樣的編譯方式才能最省事呢:
1 如果這個工程沒有被編譯過,那么我們的所有C文件都要編譯並被鏈接
2 如果這個工程的某幾個C文件被修改,那么我們只編譯被修改的C文件,並連接目標程序
3 如果這個工程的頭文件被修改了,那么我們需要編譯引用了這幾個頭文件的C文件並鏈接目標程序。
能達到上述目的的就是makefile文件了。在工程的文件路徑下新建一個Makefile文件。其中內容如下:
main:main.o calc.o
gcc -o main main.o calc.o
main.o:main.c calc.h
gcc -c main.c
calc.o:calc.c calc.h
gcc -c calc.c
clean:
rm *.o
rm main
執行make命令
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c main.c
gcc -c calc.c
gcc -o main main.o calc.o
來看下Makefile的規則:
1 第一條規則的目標為main。而為了得到main,必須先得到main.o calc.o這2個文件。所以make會進一步查找這2個條件為目標的規則。
2 第二條規則和第三套規則的目標三main.o和calc.o。main.o依賴於main.c和calc.h。為了得到main.o必行執行gcc -c main. Calc.o依賴於calc.c和calc.h。為了得到calc.o必須執行gcc -c calc.c
3 最后的clean操作清除執行過程中產生的臨時文件。當用make命令執行的時候,clean下的命令不會執行,要以make clean方式單獨執行。執行后,所有*.o和main都被刪除。
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# ls -al
total 40
drwxr-xr-x 2 root root 4096 Nov 10 09:15 .
drwxr-xr-x 3 root root 4096 Nov 8 10:35 ..
-rw-r--r-- 1 root root 118 Nov 10 08:55 calc.c
-rw-r--r-- 1 root root 94 Nov 10 08:54 calc.h
-rw-r--r-- 1 root root 1056 Nov 10 09:15 calc.o
-rwxr-xr-x 1 root root 7396 Nov 10 09:15 main
-rw-r--r-- 1 root root 182 Nov 10 08:56 main.c
-rw-r--r-- 1 root root 1196 Nov 10 09:15 main.o
-rw-r--r-- 1 root root 142 Nov 10 09:15 Makefile
執行make clean
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make clean
rm *.o
rm main
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# ls -al
total 24
drwxr-xr-x 2 root root 4096 Nov 10 09:29 .
drwxr-xr-x 3 root root 4096 Nov 8 10:35 ..
-rw-r--r-- 1 root root 118 Nov 10 08:55 calc.c
-rw-r--r-- 1 root root 94 Nov 10 08:54 calc.h
-rw-r--r-- 1 root root 182 Nov 10 08:56 main.c
-rw-r--r-- 1 root root 142 Nov 10 09:15 Makefile
下面我們來修改calc.h中的內容,#define max_value 50
看下編譯內容。由於calc.c和main.c都包含了calc.h因此calc.c和main.c都會編譯
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c main.c
gcc -c calc.c
gcc -o main main.o calc.o
如果只修改calc.c中的內容。calc.c修改如下
int calculate(int n,int k)
{
printf("the value is %d",max_value);
return n*k+n*k;
}
可以看到只編譯了calc.c。main.c沒有編譯
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c calc.c
gcc -o main main.o calc.o
當沒有任何文件修改的時候:會提示main is up to date
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
make: 'main' is up to date.
那么make是如何工作的呢:
1 make會在當前目錄下查找名為makefile或者Makefile的文件
2 如果找到,它會找文件中的第一個目標文件,在上面的例子中,它會找到main這個文件
3 如果main不存在,或者main所依賴的后面的.o文件的修改時間比main晚,那么就會執行后面所定義的命令來生成main這個文件
4 如果main所依賴的.o文件存在,那么make會在當前文件中查找目標為.o文件的依賴性,如果找到,則再根據那個規則生成.o文件
5 當C文件和H文件存在時,make會生成.o文件。然后再用.o文件生成make的終結任務也就是執行文件main
也就是說,main會一層一層的尋找文件的依賴關系,直到編譯出一個目標文件。如果在查找過程中依賴的文件找不到那么就會直接退出或報錯。
繼續來看下之前的makefile文件。在第一條規則的時候。.o文件被重復了兩次。如果工程需要加入一個新的.o文件,那么就需要在2個地方加。如果makefile很復雜。那么就可有可能忘掉一個需要加入的地方。而導致編譯失敗。所以為了makefile的易維護,在makefile中可以使用變量。可以理解為C語言中的宏定義
main:main.o calc.o
gcc -o main main.o calc.o
文件修改如下:
objects=main.o calc.o
main:$(objects)
gcc -o main $(objects)
