1. 程式人生 > >從入門到製作編譯多目錄檔案的makefile

從入門到製作編譯多目錄檔案的makefile

makefile作用:用於管理編譯檔案。通常編譯linux專案時,有長達幾千個檔案,在某次更改其中一個檔案的話,若要將整個工程全部編譯,太繁瑣耗時。引入makefile,它依據檔案更新的時間,從而只編譯改動過的檔案。

1 makefile名詞解釋:

目標:指編譯後生成檔案。

依賴:生成這個目標,所依賴的檔案。(注意在執行這條規則時,makefile首先會去遍歷這些依賴,如不存在,則會從這makefile檔案中尋找依賴,並執行依賴所在的規則)。

eg:

test:a1.o  a2.o  
	gcc  a1.o  a2.o  –o test
a1.o:a1.c
	gcc –c a1.c
a2.o:a2.c
	gcc –c a2.c

命令:如何生成標。(命令列首格 按tab鍵,否則報錯)

2 makefile基礎規則

2.1賦值

A = 1  #普通賦值

B:= 2  #立即賦值,不管B之前有沒有被賦值,立即被賦值為2

B?=3  #詢問賦值,若B在之前沒有被賦值,則賦值。若有,則不賦值

C =$A  #將變數A的值賦值給C  “$”在makefile中特別常用,用於變數的賦值

2.2 特殊符號

[email protected]: 目標
$^:  全部依賴

$<: 第一個依賴

%:萬用字元

3 編寫一個所有檔案均在同一目錄下的makefie

TGT = a.out
SRC = test.c  tst.c
OBJ := $(SRC:.c = .o)
CC = gcc

$(TGT):$(OBJ)
	$(CC) –o 
[email protected]
$^ %.o : %.c $(CC) –o [email protected] –c $< .PHONY:clean clean: rm –rf $(SRC) $(OBJ)

4上面那個makefile,標頭檔案發生更改時,由於沒有加入檢測標頭檔案更新的機制,在執行make的時候會忽略標頭檔案的更改。下面完善檢測標頭檔案機制的makefile

%.d:%.c TGT=a.out
SRC=test.c tst.c
OBJ := $(SRC:.c = .o)
CROSS_COMPILER= #arm-linux-
CC=$(CROSS_COMPILER)gcc
CUR_DIR=$(shell pwd)
DIR=$(CUR_DIR)/head
CFLAGF=-I$(DIR)
$(TGT):$( OBJ )
        $(CC) $^  -o 
[email protected]
$(CFLAGF) %.o:%.c $(CC) $< -c -o [email protected] $(CC) $< -MM > [email protected] -include $(SRC:.c=.d) clean: rm -vf $(TGT) $( OBJ ) $(SRC:.c=.d) .PHONY:clean

5 編寫一個所有檔案均在不同目錄下的makefie

目錄結構為:

[email protected]:~/makefile/04$ tree

.

├── head

│   └── head.h

├── head.h

├── main.c

├── makefile

├── test

│   ├── hello

│   │   ├── head.h

│   │   ├── hello.c

│   │   └── makefile

│   ├── makefile

│   └── test.c

└── tst

    ├── makefile

    └── tst.c

5.1在當前目錄(主目錄)makefile檔案為

export CC = gcc 
export LD =ld 
SRC=main.c
TGT =a.out
SUB_DIR =test tst  
export SUB_TGT =build-in.o
TOP_DIR =$(shell pwd)
HEAD_DIR =$(TOP_DIR)/head
export CFLAGS=-I $(HEAD_DIR)
$(TGT):$(SUB_DIR) $(SRC:.c=.o)
        $(CC)  $(CFLAGS)  $(SUB_DIR:=/$(SUB_TGT)) $(SRC:.c=.o)

$(SUB_DIR):
        make -C [email protected]
%.o:%.c
        $(CC) $(CFLAGS) -c  $<
%.d:%.c
        $(CC) $(CFLAGS) -MM $<  > [email protected]
sinclude $(SRC:.c=.d)
clean:
        rm -vf $(TGT)
        rm -vf $(SRC:.c=.o)  $(SRC:.c=.d)
        for dir in $(SUB_DIR); do \  
make -C $$dir clean; \
        done
.PHONY:clean $(SUB_DIR)

解析:在通過makefile編譯的過程中,SUB_DIR指定了要去遍歷的子目錄,通過make -C [email protected]

語句,執行各個子目錄下的makefile檔案,並生成一個叫build-in.o的檔案,通過export SUB_TGT =build-in.o 指定。等待各個子目錄都被編譯完了,然後在返回主目錄,連同build-in.o和main.o生成TGT。

5.2在test目錄下的makefile檔案為:

SRC =test.c
SUB_DIR=hello

$(SUB_TGT):$(SUB_DIR)  $(SRC:.c=.o) 
        $(LD)   $(SRC:.c=.o) $(SUB_DIR:=/$(SUB_TGT))  -r -o [email protected]

%.o:%.c
        $(CC) $(CFLAGS) $< -c 

%.d:%.c
        $(CC)  $(CFLAGS) -MM $<  >  [email protected]
$(SUB_DIR):
        make -C [email protected]

sinclude $(SRC:.c=.d)

clean:
        rm -rvf $(SUB_TGT)
        rm -rvf $(SRC:.c=.d) $(SRC:.c=.o)
        for dir in $(SUB_DIR); do \
        make -C $$dir clean; \
        done
.PHONY:clean $(SUB_DIR)  

解析:通過主目錄執行該子目錄的makefile檔案,該目錄下有test.c檔案和hello目錄,大體執行與主目錄相同。它先去hello目錄執行該目錄的makefile,並生成build-o,然後將build-o檔案和該目錄下的test.o一起打包生成build.o檔案。

5.3 在hello目錄下的makefile檔案

SRC =hello.c
SUB_DIR=

$(SUB_TGT):$(SRC:.c=.o) $(SUB_DIR)
        $(LD)   $(SRC:.c=.o) $(SUB_DIR:=/$(SUB_TGT))  -r -o [email protected]

%.o:%.c
        $(CC) $(CFLAGS) $< -c 

%.d:%.c
        $(CC)  $(CFLAGS) -MM $<  >  [email protected]
$(SUB_DIR):
        make -C [email protected]

sinclude $(SRC:.c=.d)

clean:
        rm -rvf $(SUB_TGT)
        rm -rvf $(SRC:.c=.d) $(SRC:.c=.o)
        for dir in $(SUB_DIR); do \
        make -C $$dir clean; \
        done
.PHONY:clean $(SUB_DIR)  

解析:該makefile 與上面基本相同,由於該目錄下沒有其他目錄,所以SUB_DIR=

為空。

5.4 在tst目錄下的makefile

SRC =tst.c
SUB_DIR=

$(SUB_TGT):$(SRC:.c=.o) $(SUB_DIR)
        $(LD)   $(SRC:.c=.o) $(SUB_DIR:=/$(SUB_TGT))  -r -o [email protected]

%.o:%.c
        $(CC) $(CFLAGS) $< -c
        echo $(CFLAGS) 

%.d:%.c
        $(CC)  $(CFLAGS) -MM $<  >  [email protected]
$(SUB_DIR):
        make -C [email protected]

sinclude $(SRC:.c=.d)

clean:
        rm -rvf $(SUB_TGT)
        rm -rvf $(SRC:.c=.d) $(SRC:.c=.o)
        for dir in $(SUB_DIR); do \
        make -C $$dir clean; \
        done
.PHONY:clean $(SUB_DIR)

解析:同上

make之後的目錄結構

[email protected]:~/makefile/04$ tree

.

├── a.out

├── head

│   └── head.h

├── head.h

├── main.c

├── main.d

├── main.o

├── makefile

├── test

│   ├── build-in.o

│   ├── hello

│   │   ├── build-in.o

│   │   ├── head.h

│   │   ├── hello.c

│   │   ├── hello.d

│   │   ├── hello.o

│   │   └── makefile

│   ├── makefile

│   ├── test.c

│   ├── test.d

│   └── test.o

└── tst

    ├── build-in.o

    ├── makefile

    ├── tst.c

    ├── tst.d

    └── tst.o