1. 程式人生 > >MakeFile 文件的使用

MakeFile 文件的使用

系列 之前 文件描述 比較 長度 深入 腳本 highlight 又是

什麽是Makefile?

一個工程中的源文件不計其數,其按類型、功能、模塊分別放在若幹個目錄中,makefile定義了一系列的規則來指定,哪些文件需要先編譯,哪些文件需要後編譯,哪些文件需要重新編譯,甚至於進行更復雜的功能操作,因為 makefile就像一個Shell腳本一樣,其中也可以執行操作系統的命令.

為什麽要使用Makefile?

就像前面提到的,一個工程的源文件可能不計其數,編寫makefile,使用make命令來構建工程,會使原本復雜繁瑣的工作簡化許多,極大地提高了效率。

如何使用make命令?

Makefile 文件描述了整個工程的編譯、連接等規則,make是一個命令工具,它解釋Makefile中的指令(規則)。

一個基本的makefile主要由目標對象、依賴文件、變量和命令4部分組成。

命令行中執行makefile內容:

◆宏定義

◆ 源文件之間的相互依賴關系

◆ 可執行的命令

通常makefile文件中的一條規則的編寫形式如下:

target ... : prerequisites ...
(tab)command
...
...

解釋為:

目標:依賴文件
(制表符)執行指令 ...

下面來看一個具體的例子:

新建 三個文件: main.c add.c fun.h

fun.h

#include<sdtio.h>
#include<math.h>
int add(int a,int b);

add.c

int multi(int a,int b)
{
	return a+b;
}

main.c

#include"fun.h"
int main()
{
	int a=12,b=6;
	c=add(a,b);
	printf("%d\n",add(a,b));

	return 0;
}

  

下圖體現了文件間的依賴關系:

技術分享圖片

我們先使用gcc 命令來構建這個工程:

gcc -c main.c add.c

查看當前文件目錄:

技術分享圖片

文件夾中多了main.o 和 add.o這兩個文件,接著在執行下面的命令:

gcc main.o add.o -o math -l m//用main.o add.o 進一步生成目標 ,最後兩個參數 -l m 為連接數學函數庫

技術分享圖片

我們發現生成目標文件math需要兩步,也就是要先生成main.o 和 add.o 這兩個中間文件,這兩個文件稱為目標文件的直接依賴文件,那麽main.c和add.c分別又是main.o和add.o的直接依賴文件。

makefile正事依據這樣一層一層的的依賴關系和連接 依賴文件 和 目標文件 的命令 所構成的。

下面來看一個最基本的makefile文件:

以下makefile文件顯示了各個目標與依賴文件直接的關系,以及生成它們的命令

add:main.o add.o                              		//目標文件add的依賴文件為main.o、add.o
	gcc -o add main.o add.o -l m			//將目標文件連接為可執行文件,並連接數學函數庫
	
main.o:main.c 						//main.o的依賴文件為main.c 
	gcc -c main.c					//將源文件main.c編譯成目標文件main.o

add.o:add.c 
	gcc -c test.c

clean:							//清理中間文件
	rm main.o add.o add 

 

編寫makefile文件中要註意的幾點:

1、clean沒有被第一個目標add直接或間接依賴,那麽它後面的命令就不會被自動執行可以在make 命令後面跟clean目標作為參數來執行其後所定義的命令,

即執行"make clean"命令,用於清除make過程中生成的目標,以便重新編譯


2、在定義好依賴關系後,後續的那一行定義了如何生成目標文件的操作系統命令,一定要以一個Tab鍵作為開頭。


3、記住,make並不管命令是怎麽工作的,他只管執行所定義的命令。make會比較目標文件和依賴文件的修改日期,即時間戳
如果依賴文件的日期要比目標文件的日期要新,或者目標不存在的話,那麽,make就會執行後續定義的命令

先執行rm main.o add.o math 清除之前生成的中間文件和目標文件

然後用ls命令查看以下當前目錄所包含的文件:

技術分享圖片

執行make命令,再用ls查看當前目錄下的文件:

技術分享圖片

我們發現,make命令已經生成了add目標文件,還有依賴文件main.o, add.o

執行結果:

技術分享圖片

執行make命令時,可以通過參數為makefile文件的宏變量CC賦值,通過宏變量CC指定不同的編譯器來編譯源文件

CC=
add:main.o add.o
	$(CC) -o add main.o add.o
main.o:main.c
	$(CC) -c main.c
add.o:add.c
	$(CC) -c add.c

clean:
	rm main.o add.o add

 

下面,對makefile做一點小小的改動:

OBJS=main.o add.o						#使用了變量OBJS
CC=gcc
CFLAGS=-Wall -O -g

add:$(OBJS)
	$(CC)  $(OBJS)  -o  add
main.o:main.c
	$(CC)  $(CFLAGS)  -c main.c 
add.o:add.c
	$(CC)  $(CFLAGS)  -c  add.c

clean:
	rm *.o   add

  

這裏使用到了變量,用CC代替了gcc, CFLAGS是makefile中預定義的變量,我們為將它初始化為-Wall -O -g (開啟警告信息、編譯鏈接過程中執行優化處理、增加調試信息),這三個參數都是gcc參數的常用的值,關於gcc參數常用值,這裏不做具體介紹。

Makefile中允許使用簡單的宏指代源文件及其相關編譯信息,在Linux中也稱宏為變量。在引用宏時只需在變量前加$符號,
但值得註意的是,如果變量名的長度超過一個字符,在引用時就必須加圓括號()。
有效的宏引用
$(CFLAGS)
$Z
$(Z)

makefile中常見的預定義變量及其部分默認值

技術分享圖片

我們先使用make clean 清除之前生成的目標文件,再執行make命令,得到的結果是一樣的.

技術分享圖片

下面再對makefile進行升級:

#Makefile
CC=gcc
CFLAGS=-Wall -O -g
OBJS=main.o add.o
add:$(OBJS)
	$(CC)  $^ -o $(OBJS)
main.o:main.c
	$(CC)   $(CFLAGS)   -c  $<  -o  $@
add.o:add.c
	$(CC)   $(CFLAGS)  -c  $<  -o  $@

clean:
	rm   -f   *.o 

  

這裏使用了makefile 的自動變量,下表是makefile中常見的自動變量:

makefile中常見的自動變量

技術分享圖片

自動變量通常可以代表編譯語句中出現的目標文件和依賴文件等,自動變量的使用進一步簡化makefile的編寫,自動變量的書寫比較難記,但是在熟練了之後會非常方便。

下面是一個使用二進制作為目標文件的makefile模板:

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g  -I../include               //-I[頭文件目錄路徑]  :用來找到不再當前目錄下的頭文件
BIN=main add					//這一行添加依賴文件的名稱
all:$(BIN)
%.o:%.c
	$(CC) $(CFLAGS)	-c $< -o $@
clean:
	rm -f *.o $(BIN)

終極版makefile

技術分享圖片

關於maefile的寫法,其形式可能有很多種,makefile還支持帶有條件語句的條件編譯、函數、以及一些隱含規則等,這裏不做深入介紹,只有多加練習、實踐,才能真正掌握make這個強大的工具。

MakeFile 文件的使用