1. 程式人生 > 實用技巧 >GNU Make / Makefile 學習

GNU Make / Makefile 學習

在學習GNU Make / Makefile總結了筆記,並分享出來。有問題請及時聯絡博主:Alliswell_WP,轉載請註明出處。

目錄:
一、GNU Make / Makefile 學習資料
二、makefile入門基礎
1、make簡介
2、為什麼要使用make
3、makefile簡介
4、makefile的基本結構
5、基礎示例
6、Makefile自動化變數
7、make常用的內嵌函式

一、GNU Make / Makefile 學習資料

1)阮一峰-Make命令教程——http://www.ruanyifeng.com/blog/2015/02/make.html
推薦理由:這篇寫的很簡單,不過其中提到了一點很重要:每一行"命令"是獨立的Shell。第二篇《使用Make構建網站》不需要看,是針對node.js的。

2)陳皓-跟我一起寫Makefile——https://github.com/seisman/how-to-write-makefile
推薦理由:這本讀起來很輕鬆,同時也比較全面。

3)徐海兵翻譯-GNU make手冊——http://hacker-yhj.github.io/resources/gun_make.pdf
推薦理由:官方文件通常是深入淺出的,非常推薦。就是比較羅嗦,也很厚。

二、makefile入門基礎

1、make簡介

make是一個指令工具,它解釋makefile中的指令或者說規則。makefile檔案描述了整個工程中所有檔案的**編譯順序,編譯規則**。Makefile也有自己的編寫規則,通常,我們所使用的IDE都會生成相應的makefile,然後再根據makefile來進行編譯,只是這些操作是由IDE來完成,我們只需要點選一個編譯按鈕。


2、為什麼要使用make

現可以在GitHub上看到,很多的開源專案,在編譯的時候,都是使用make來完成的,也就是說,都有其對應的makefile。他們都有個特點,那就是檔案很多。
考慮這樣一種情況,我們的專案現在有三、四十個檔案,你使用的不是IDE工具,而是命令列,那麼不同的人,在編譯你的專案的時候,都需要一個一個檔案的
gcc -o asample.c bsample.c ...... xxx.out
這樣慢慢的一個檔案,一個檔案的去找到以後再編譯嗎?

答案肯定是否定的,當你工程的檔案多了以後,時間一長,可能你自己都不能記住所有的檔案。所以,這個時候我們就可以使用make來根據makefile對整個專案進行管理。除此之外,make還有一個優點,那就是當你修改你的檔案以後,make只會編譯更新的檔案以及它相關依賴的檔案。這裡後邊進行詳細的解釋,意思就是,當你只修改了幾十個檔案中的某一個檔案時,make只會重新編譯跟你修改的檔案有關聯的檔案,而不是所有的檔案。這就大大的減短了編譯的時間。

》總結:

利用make工具可以自動完成編譯工作。這些工作包括:
如果僅僅修改了某幾個原始檔,則只重新編譯這幾個原始檔;
如果某個標頭檔案被修改,則重新編譯所有包含該標頭檔案的原始檔。
利用這種自動編譯可大大簡化開發工作,避免不必要的重新編譯。

make工具通過一個稱為Makefile的檔案來完成並自動維護編譯工作。Makefile檔案描述了整個工程的編譯、連結等規則。


3、makefile簡介

在我們執行make之前,需要有一個名為makefile或Makefile的檔案。這個檔案用來告訴make需要完成什麼樣的操作。我們可以簡單的把makefile認為是一份定義了原始檔間依賴關係、如何編譯各個原始檔並生成可執行檔案的說明書。


4、makefile的基本結構

TARGET... : PREREQUISITES...
COMMAND
...
...
TARGET:規則的目標,程式產生的檔案,如可執行檔案和目標檔案;目標也可以是要執行的動作,如clean,也稱偽目標。
PREREQUISITES:規則的依賴,是用來產生目標的輸入檔案列表,一個目標通常依賴於多個檔案。
COMMAND:規則的命令。是make執行的動作(命令是shell命令或者是可在shell下執行的程式)。

》注意:

1)這裡需要注意的是,命令前面使用的是TAB鍵,而不是空格,使用空格會出現錯誤。

2)如果DEPENDENCIES中有一個或多個檔案更新的話,COMMAND就要執行,這就是Makefile最核心的內容。

5、基礎示例

.PHONY:clean
main:main.o sub.o add.o print.o
    gcc -Wall -g main.o add.o sub.o print.o -o main
main.o:main.c 
    gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
    gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
    gcc -Wall -g -c sub.c -o sub.o
print.o:print.c print.h
    gcc -Wall -g -c print.c -o print.o
clean:
    rm -f *.o mai

我們可以看到,main是我們最終想要生成的目標檔案,它依賴main.o sub.o add.o print.o這四個.o檔案。因此要執行gcc -Wall -g main.o add.o sub.o print.o -o main命令來生成目標檔案,但是當前沒有這些.o檔案,因此就要先生成這些.o檔案。我們寫了四條xxx.o:xxx.c然後執行gcc -Wall -g -c xxx.c -o xxx.o,這些語句就會生成目標檔案的依賴項。

clean是一個偽目標檔案,因為它沒有依賴項。我們只是想通過make clean來將.o檔案刪除,但是我們通常要指定.PHONY:clean這條語句,用來顯式的指定clean是偽目標,來防止當前目錄下有一個同名的clean檔案。這樣,一個簡單呢的Makefile檔案就寫好了。

6、Makefile自動化變數

雖然像上述那樣可以完成編譯,但是明顯非常麻煩,接下來介紹Makefile的自動化變數。
選項名 作用
$@ 規則的目標檔名
$< 規則的第一個依賴檔名
$^ 規則的所有依賴檔案列表

我們使用這些自動化變數來嘗試從寫剛才的Makefile

.PHONY:clean
OBJ=main.o sub.o add.o print.o
main:$(OBJ)
    gcc -Wall -g $^ -o $@
main.o:main.c 
    gcc -Wall -g -c $< -o $@ 
add.o:add.c add.h
    gcc -Wall -g -c $< -o $@ 
sub.o:sub.c sub.h
    gcc -Wall -g -c $< -o $@ 
print.o:print.c print.h
    gcc -Wall -g -c $< -o $@
clean:
    rm -f *.o main

我們定義了一個變數叫OBJ,他是我們的依賴項列表。然後使用自動化變數來代替對應的檔案,如上所示。

但是,我們這些.c檔案都要生成.o檔案,這樣寫也非常麻煩,我們介紹另一些規則。
模式規則
%.o:%.c
字尾規則
.c:.o

我們來使用這兩種規則:

.PHONY:clean

CC = gcc
CFLAGS = -Wall -g
OBJ = main.o sub.o add.o print.o
main:$(OBJ)
    $(CC) $(CFLAGS) $^ -o $@
#%.o:%.c
.c.o:
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f *.o main

使用這兩個規則,就會將所有.c檔案生成同名的.o檔案,這樣,Makefile就更加簡潔。

7、make常用的內嵌函式

函式呼叫
$(function arguments)
$(wildcard PATTERN)
當前目錄寫的匹配模式的檔案
例如:src=$(wildcard *.c)
$(patsubst PATTERN,REPLACEMENT,TEXT)
模式替換函式
例如:$(patsubst %.c, %.o, \$src)
等價於$(src:.c=.o)
shell函式
執行shell命令
例如:$(shell ls -d */)

在學習GNU Make / Makefile總結了筆記,並分享出來。有問題請及時聯絡博主:Alliswell_WP,轉載請註明出處。