什麼是makefile ?
在一個項目中,會有大量的 .c 文件,.h文件.讓我們手動的編譯不僅麻煩,而且效率低.
makefile定義了一系列的規則來指定哪些文件需要先編譯,哪些文件需要後編譯,哪些文件需要重新編譯.
然後使用 make 工具,用來解釋makefile 中的規則.
現在有 3 個文件,分別是 main.c ,hello.h ,hello.c
main.c
#include<stdio.h>
#include"hello.h"
int main()
{
hello();
return 0;
}
hello.h
void hello(void);
hello.c
#include"hello.h"
#include<stdio.h>
void hello(void)
{
printf("hello world\n");
}
最直接的編譯方式: gcc main.c hello.c
使用 makefile 時,要在 makeflie(Makefile) 文件中編寫.
makefile 的 編寫由易到難.
makefile 的基本單元是規則.
一個規則的格式如下:
目標文件列表 分隔符 依賴文件列表 [; 命令]
(table)[命令]
最簡單的makefile就生成了
main: main.o hello.o
gcc main.c hello.c -o main
makefile解析:
main 爲 目標文件, : 爲分隔符,main.o 和 hello.o 爲 依賴文件
第二行 則爲一個命令
這個簡單的 makefile 解決了麻煩這個問題 ,但沒有解決 低效 的 問題.因爲每一次都要編譯 main.o,hello.o. 即使沒有改變hello.o.
main: main.o hello.o
gcc main.o hello.o -o main
main.o:main.c
gcc -c main.c
hello.o:hello.c
gcc -c hello.c
爲什麼說它能解決低效呢 ?
makefile 每次只執行一個目標文件,即 第一個 目標文件.然後檢查這個規則是否存在依賴,如果依賴存在,則執行命令,若依賴不存在則向下查找依賴.
找到依賴後 首先判斷是否要更新, 如果依賴的時間 比 目標時間 晚,則說明 依賴文件在 目標文件後修改過,需要更新,否則就跳過.所以提高了效率.
makefile 解析:
爲了生成main ,則需要main.o,hello.o ,向下查找,首先找到 main.o ,對比時間,判斷是否更新,然後查找第二個依賴並判斷,
如果所有依賴都檢查完畢,則執行 第一個規則中的命令.
但是,這又引出了一個問題,如果要修改一個makefile 的中使用的 編譯器,原來爲 gcc ,想變爲 g++,這時候,就要一個個 的修改.
爲了解決這個問題, 就引入了 變量.修改時,只要修改 變量就行了.
除此之外,makefile 中還定義了一組變量,它們的值在make 運行過程中可以動態的改變,稱爲 自動變量
例:
- $@: 表示規則中的目標文件名
- $<: 表示規則中的第一個依賴文件名
- $?: 所有比目標文件新的依賴文件列表
- $^: 表示規則中的所有依賴
還有一個 : makefile 中的匹配符 %
obj = main.o hello.o
CC = gcc
target = main
$(target): $(obj)
gcc $(obj) -o $(target)
%.o:%.c
gcc -c $< -o $@
這次的makefile 使用了 變量替換,和自動變量,還有一個 匹配符 %
解釋一下 :
%.o:%.c
在這個makefile 中 相當於
main.o : main.c
hello.o : hello.c
makefile 的解析:
前三行就是簡單的變量替換, 在makefile 中 ,用 $() 對變量的引用. 可以將 變量替換 看成 字符串 替換.
第二個規則的命令中, 每次在 第一個規則中 檢查一個依賴, 就到第二個 規則中執行.
相當於 :
檢查 main.o 依賴時 , 第二個規則 執行
main.o : main.c
gcc -c main.c -o main.o
檢查 hello.o 依賴時,第二個規則執行
hello.o : hello.c
gcc -c hello.c -o hello.o
當然也可以將 第一個規則 命令 中的 變量 用自動變量替換
obj = main.o hello.o
CC = gcc
target = main
$(target): $(obj)
gcc $^ -o $@
%.o:%.c
gcc -c $< -o $@
此時 你會發現多了 hello.o,main.o文件, 想一哈,如果 有特別多的 文件,就會生成 特別多的 .o文件,而且還可能會在不同的目錄裏,
這時,刪除他們可不是一個容易的事清.
但我們可以 用makefile 刪除
obj = main.o hello.o
CC = gcc
target = main
$(target): $(obj)
gcc $^ -o $@
%.o:%.c
gcc -c $< -o $@
clean:
rm *.o $(target)
上面提到過,makefile 只執行第一個 目標文件,其餘的是不執行的. 這時,我們只能通過自己指定 執行哪一個目標文件.
make clean
它就會執行 clean 這個規則;
除此之外,makefile 中也帶有函數.(過幾天 在補更)