Linux工具入門:make工具與Makefile文件

1. make工具

利用make工具能夠自動完成編譯工做,這些工做包括:html

  • 若是修改了某幾個源文件,則只從新編譯這幾個源文件
  • 若是某個頭文件被修改了,則從新編譯全部包含該頭文件的源文件

利用這種自動編譯能夠大大簡化開發工做,避免沒必要要的從新編譯。make工具經過一個稱爲Makefile的文件來完成並自動維護編譯工做,Makefile文件描述了整個工程的編譯、鏈接規則。shell

2. Makefile文件

Makefile描述了整個工程的編譯鏈接規則。Makefile的基本規則爲:函數

TARGET...: DEPENDENCIES...
    COMMAND
    ...
  • TARGER:目標程序產生的文件,如可執行文件和目標文件,目標也能夠是要執行的動做,如clean,也稱爲僞目標。
  • DEPENDENCIES:依賴是用來產生目標的輸入文件列表,一個目標一般依賴與多個文件。
  • COMMAND:命令是make執行的動做(命令是shell命令或是可在shell下執行的程序),注意每一個命令行的起始字符必須爲TAB字符。
  • 若是DEPENDENCIES中有一個或多個文件更新的話,COMMAND就要執行,這就是Makefile最核心的內容。

3. Makefile的簡單示例

$ touch add.c add.h sub.c sub.h main.c

如今有這5個文件add.h 、sub.h中包含了函數聲明,add.c、sub.c中包含了函數實現,main.c調用了函數。Makefile的文件:工具

main:main.o add.o sub.o        【目標文件是main,它依賴於main.o,add.o,sub.o這三個文件】
        gcc -Wall -g main.o add.o sub.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

保存Makefile文件後執行make命令:spa

$ make
gcc -Wall -g -c main.c -o main.o
gcc -Wall -g -c add.c -o add.o
gcc -Wall -g -c sub.c -o sub.o
gcc -Wall -g main.o add.o sub.o -o main

能夠看到執行了make以後,因爲 目標文件main依賴於 main.o add.o sub.o ,因此是須要先 生成 這三個.o文件,最後才生成main。
若是此時再次輸入make,會看到:命令行

$ make
make: 'main' is up to date.

make的編譯規則是根據時間來進行判斷,一旦依賴列表中某個文件的更新時間比目標文件晚,則會從新生成目標,不然會出現以上提示。
默認狀況下敲擊make將生成第一個目標,也就是main。也能夠生成指定的目標:code

$ make add.o   【指定只生成add.o文件】

Makefile文件的名字不必定得命名爲「Makefile」或"makefile",使用其餘名字也是能夠的。例如咱們由一個文件叫myMakefile,一樣可使用它:htm

make -f myMakefile   【-f 選項的做用是把名字"myMakefile"做爲makefile來對待。】

4. 僞目標

TARGET...: DEPENDENCIES...
    COMMAND    【注意COMMAND以前是一個TAB,不是空格】
    ...

前面說過,TARGET除了能夠是目標文件以外,還能夠是僞目標。執行僞目標的效果等於執行了某一個動做, 並不產生目標文件。例如添加一個僞目標:blog

main:main.o add.o sub.o     
        gcc -Wall -g main.o add.o sub.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
clean :                                        【這是一個僞目標】
        rm -f $(OBJECTS) main

使用make來執行僞目標:開發

$ make clean
rm -f main.o add.o sub.o main

能夠看到make將執行僞目標下面的命令。

5. Makefile 自動化變量

從上面的Makefile文件咱們發現一些問題:有時候目標文件的依賴列表過長,或者命令重複書寫。利用Makefile自動化變量能夠解決這個問題。

選項名 做用
\(@|規則的目標文件名| |\)< 規則的第一個依賴文件名
$^ 規則的全部依賴文件列表

剛纔的Makefile文件,咱們能夠改寫爲:

main:main.o add.o sub.o
        gcc -Wall -g $^ -o $@      【等價於 gcc -Wall -g main.o add.o sub.o -o main】
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 $@

執行make,能夠看到效果和以前是同樣的:

$ make
gcc -Wall -g -c main.c -o main.o
gcc -Wall -g -c add.c -o add.o
gcc -Wall -g -c sub.c -o sub.o
gcc -Wall -g main.o add.o sub.o -o main

還能夠自定義變量

OBJECTS = main.o add .o sub.o 【OBJECTS是自定義的變量名】
main:$(OBJECTS)                        【能夠在須要的地方使用變量名進行替換,替換規則爲$(變量名)】
        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 $@

6. 編譯生成多個可執行文件

假設如今不僅是想生成可執行main,還想生成可執行文件main2,能夠這樣寫

BIN = main main2                【自定義變量BIN】
OBJECTS= main.o add.o sub.o  
all : $(BIN)   【關注重點】
main : $(OBJECTS)
        gcc -Wall -g  $< -o $@
main2: $(OBJECTS)
        gcc -Wall -g  $< -o $@
main.o : main.c
        gcc -Wall -g -c $< -o $@
main2.o :msin2.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 $@
clean :
        rm -f $(OBJECTS) $(BIN)

爲了生成目標文件all,須要先生成BIN,也便是 main main2。這樣就能夠生成兩個可執行文件了。利用自定義變量能夠再簡化這段Makefile文件:

BIN = main main2
OBJECTS= main.o add.o sub.o
CC = gcc
CFALGS = -Wall -g
all : $(BIN)
main : $(OBJECTS)
        $(CC) $(CFALGS)  $< -o $@
main2: $(OBJECTS)
        $(CC) $(CFALGS)  $< -o $@       
main.o : main.c
        $(CC) $(CFALGS) -c  $< -o $@
main2.o :msin2.c
        $(CC) $(CFALGS) -c  $< -o $@
add.o:add.c add.h
        $(CC) $(CFALGS) -c  $< -o $@
sub.o:sub.c sub.h
        $(CC) $(CFALGS) -c  $< -o $@
clean :
        rm -f $(OBJECTS) $(BIN)

可是這樣看起來,重複的內容仍是比較多,可使用下面的方法來繼續簡化:

BIN = main main2
OBJECTS= main.o add.o sub.o
CC = gcc
CFALGS = -Wall -g
all : $(BIN)
main : $(OBJECTS)
        $(CC) $(CFALGS)  $< -o $@
main2: $(OBJECTS)
        $(CC) $(CFALGS)  $< -o $@       
.o .c :                                               【關注重點在這裏】
        $(CC) $(CFALGS) -c  $< -o $@
clean :
        rm -f $(OBJECTS) $(BIN)

利用 .o.c :,能夠自動地把全部的.c文件到.o文件的生成都使用同一條命令來完成,簡化的重複的工做。

7. make經常使用的內嵌函數

首先看make中函數調用的形式:

//函數調用
$(function arguments)     【function是函數名稱,arguments是參數,使用$來調用】

值得注意的是,函數名稱與參數之間是空格。

來看三個經常使用make內嵌函數。

  • $(wildcard PATTERN) 做用是在當前目錄下匹配模式的文件。
src = $(wildcard *.c)  【在當前目錄下搜索全部.c文件,文件名稱列表保存到src中】
  • $(patsubst PATTENR,REPLACEMENT,TEXT) 模式替換函數,做用是把TEXT中文件列表從模式PATTENR替換爲REPLACEMENT模式。
$(patsubst %.c,%.o,$src)  【把src中的.c文件列表中的文件從.c替換爲.o】
等價於:
$(src:.c =.o)   【這種方式更經常使用】
  • shell函數

shell函數能夠執行shell下的命令,一樣是使用$來引用,例如

$(shell ls -d */) 【將當前目錄下的全部文件夾都列出來】

下面經過一個多級目錄的例子來使用這些函數。場景是這樣的,當前目錄下有main.c文件,同時還有若干個目錄,每一個目錄中都有各自的.c文件。利用全部的.c文件編譯生成最後的main文件:

CC       = gcc
CFLAGS   = -Wall -g
BIN      = main
SUBDIR   = $(shell ls -d */)      【SUBDIR變量保存了子目錄的列表】
ROOTSRC  = $(wildcard *.c)  【ROOTSRC保存了當前目錄下的.c文件列表】
ROOTOBJ  = $(ROOTSRC:%.c = %.o)  【ROOTBOJ 保存了當前目錄下.c文件同名的.o列表】
SUBSRC   = $(shell find $(SUBDIR) -name '*.c')  【SUBSRC 保存了全部子目錄下的的.c文件】
SUBOBJ   = $(SUBSRC:%.c = %.o)         【SUBOBJ保存了全部子目錄下的.c文件同名的.o文件列表】
$(BIN):$(ROOTOBJ) $(SUBOBJ)         【main的生成依賴與當前目錄及全部子目錄下的.o文件】
        $(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ)
.o .c:
        $(CC) $(CFLAGS) -c $< -o $@    
clean:
        rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)

文章連接:http://www.cnblogs.com/QG-whz/p/5461110.html

相關文章
相關標籤/搜索