1. 程式人生 > >從0開始寫一個通用的Makefile檔案

從0開始寫一個通用的Makefile檔案

  1.      什麼是Makefile檔案 

         一個工程中的原始檔不計其數,其按型別、功能、模組分別放在若干個目錄中,makefile定義了一系列的規則來指定,哪些檔案需要先編譯,哪些檔案需要後編譯,哪些檔案需要重新編譯,甚至於進行更復雜的功能操作,因為 makefile就像一個Shell指令碼一樣,其中也可以執行作業系統的命令

  2. Makefile三要素
        目標 條件 命令  
     

    3.現在讓我們來編寫第一個Makefile檔案

我的電腦裡面有如下幾個檔案

                                                

其程式碼如下

//add.c
#include"cal.h"
int add(int a,int b)
{
    return a+b;
}
//sub.c
#include"cal.h"
int sub(int a,int b)
{
    return a-b;
}
//mul.c
#include"cal.h"
int mul(int a,int b)
{
    return a*b;
}
//div.c
#include"cal.h"
int div(int a,int b)
{
    return a/b;
}
//cal.h
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
int div(int a,int b);
//mcal.h
#include"cal.h"
#include"stdio.h"
int main()
{
  int a=0;
  int b=0;
  scanf("a=%d,b=%d",&a,&b);
  printf("\n%d+%d = %d\n",a,b,add(a,b));
  printf("%d-%d = %d\n",a,b,sub(a,b));
  printf("%d*%d = %d\n",a,b,mul(a,b));
  printf("%d/%d = %d\n",a,b,div(a,b));
}

如果沒有Makefile檔案我們要編譯就需要這麼些 gcc add.c sub.c mul.c div.c mcal.c -o app

我們可以讓Makefile替我們做這件事 ,在我們的專案目錄裡touch Makefile 注意Makefile第一個字母要大寫

#目標       依賴
all:add.c sub.c mul.c div.c maal.c
#命令                                                                        
    gcc add.c sub.c mul.c div.c mcal.c -o app

all是個偽目標,是所有目標的目標,其功能是編譯所有的目標。all 是目標要頂格寫,all後面跟條件(依賴)  gcc ****是命令

實際上我們gcc首先要生存.o的目標檔案(中間檔案)然後再連結成可執行程式 因此我們將Makefile改成這樣

all:add.o sub.o mul.o div.o mcal.o
	gcc add.o sub.o mul.o div.o mcal.o -o app

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

sub.o:sub.c
	gcc -c sub.c

mul.o:mul.c
	gcc -c mul.c

div.o:div.c
	gcc -c div.c

mcal.o:mcal.c
	gcc -c mcal.c

然後在shell中敲入make我們再看目錄中的檔案 如下

目錄中多了*.o檔案,由於gcc *.o依賴於 .o檔案 而.o檔案又依賴於.c檔案 Makefile會去分析並處理這些依賴,先去生成.o檔案 然後再gcc .o檔案。在上面的Makefile中我們發現add.o sub.o mul.o div.o mcal.o 這一行出現了兩次,像在c中一樣,我們也可以在Makefile中設定變數去代表這個值,並且我們發現

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

和後面的sub....等只是名字不同而已,就像c++中寫模版函式一樣,我們也可以在Makefile中寫一個通用的目標因此我們可以將Makefile改寫成如下

obj = add.o sub.o mul.o div.o mcal.o
app:$(obj)
	gcc $(obj) -o app

%.o:%.c
	gcc -c $< -o [email protected]

我們將add.o sub.o mul.o div.o mcal.o賦值給obj,然後通過$(obj)去取出obj的值, %是一個萬用字元,在Makefile中[email protected]表示目標,$^表示所有依賴所有 $<表示依賴中的第一個。因此之前的四個目標可以簡寫成一個目標我們儲存然後make發現一樣可以生成.o檔案和app執行檔案,並且目錄下所有的.c檔案都會生成.o檔案,因此無關緊要的程式碼不要放在工作目錄下,我們發現

obj = add.o sub.o mul.o div.o mcal.o這一行還是出現了具體的檔名稱,要想實現一個通用的Makefile我們就不能出現具體的檔名,因此我們可以通過使用函式wildcard 該函式的作用是查詢當前目錄下所有的符合指定規則的檔案 我們原本的目錄下只有.c檔案,我們可以這麼寫src = $(wildcard  *.c),定義一個變數來接收這些檔名,細心的你一定發前面我們需要的是.o檔案,這裡找到的是.c檔案,因此這裡我們需要用到Makefile的字串替換函式pathsubstr來把帶.c字串名改成帶.o字串名 我們可以這麼寫obj=$(patsubst %.c,%.o ,$(src)) 這樣obj就跟前面的obj = add.o sub.o mul.o div.o mcal.o一樣了,因此改過後的Makefile檔案如下

src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
target = app
$(target):$(obj)
	gcc $(obj) -o $(target)

%.o:%.c
	gcc -c $< -o [email protected]

此時我們發現我們的Makefile跟目錄下的檔案沒有一點關係了,基本可以用於所有的專案,還有最後一步 為Makefile新增相應的配置

#前處理器表示一般指定標頭檔案所在檔案
CPPFLAGS =
#編譯時候的引數 一般是-g -wall等
CFLAGS =
#指定共享庫位置
LDFLAGS=
#指定編譯器是啥
CC= gcc
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
target = app
$(target):$(obj)
	$(CC) $^ $(LDFLAGS) -o [email protected]

%.o:%.c
	$(CC) -c $< $(CFLAGS) $(CPPFLAGS)-o [email protected]
#.PHONY
#make clean即使當前目錄有clean檔案,執行make clean時依然會執行clean目標
.PHONY:clean
clean:
# 前面的-表示錯誤依然繼續執行加@表示執行時螢幕上不顯示此語句
	@-rm -rf *.o
	@-rm -rf $(target)

重新執行make前可以通過make clean刪除生成的中間檔案和目標檔案。至此一個簡單的通用Makefile寫完了,原創,如有錯誤之處還望指出

   要想更具體的學習Makefile可以下載我上傳到文件https://download.csdn.net/download/woshichaoren1/10838702