從入門到製作編譯多目錄檔案的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