一、基本概念介紹:
Makefile 文件就是告訴make命令需要怎么樣的去編譯和鏈接程序。
編寫Makefile的基本規則:
1.如果這個工程沒有編譯過,那么我們的所有C文件都要編譯並被鏈接。
2.如果這個工程的某幾個C文件被修改,那么我們只編譯被修改的C文件,並鏈接目標程序。
3.如果這個工程的頭文件被改變了,那么我們需要編譯引用了這幾個頭文件的C文件,並鏈接目標程序。
$@--目標文件,$^--所有的依賴文件,$<--第一個依賴文件。
1 直觀方式
舉個例子:一個工程有3個頭文件,和8個C文件,根據規則編寫Makefile如下:
edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
在這個makefile中,目標文件(target)包含:可執行文件 edit 和 中間目標文件(*.o),依賴文件(prerequisites)就是冒號后面的那些 .c 文件和 .h文件。每一個 .o 文件都有一組依賴文件,而這些 .o 文件又是執行文件 edit 的依賴文件。
輸入make指令后的執行內容如下:
- make會在當前目錄下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到“edit”這個文件,並把這個文件作為最終的目標文件。
- 如果edit文件不存在,或是edit所依賴的后面的 .o 文件的文件修改時間要比edit這個文件新,那么,他就會執行后面所定義的命令來生成edit這個文件。
- 如果edit所依賴的.o文件也存在,那么make會在當前文件中找目標為.o文件的依賴性,如果找到則再根據那一個規則生成.o文件。(這有點像一個堆棧的過程)
- 當然,C文件和H文件肯定存在,於是make會生成 .o 文件,然后再用 .o 文件聲明make的終極任務,也就是執行文件edit了。
1.1 進階1:使用變量
在上面的例子中,可以看到[.o]文件的字符串被重復了兩次,如果工程需要加入一個新的[.o]文件,需要在各個依賴了該[.o]文件的地方添加,如果工程比較復雜會很麻煩,所以為了makefile的易維護,在makefile中可以使用變量。
比如,聲明一個變量叫objects,也就叫 OBJECTS, objs, OBJS, obj, 或是 OBJ,只要能夠表示obj文件就行。在makefile一開始就這樣定義:
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
於是,在makefile中以“$(objects)”的方式來使用這個變量了。
進階版本1:
objects = main.o kbd.o command.o display.o insert.osearch.o files.o utils.o
edit : $(objects) cc -o edit $(objects) main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit $(objects)
於是如果有新的 .o 文件加入,只需添加到 objects 變量中即可。
1.2 進階2:讓make自動推導
GNU的make很強大,它可以自動推導文件以及文件依賴關系后面的命令,於是我們就沒必要去在每一個[.o]文件后都寫上類似的命令,只要make看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關系中,並且 cc -c xx.c 也會被推導出來。
進階版本2:
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : rm edit $(objects)
這種方法,也就是make的“隱晦規則”。上面文件內容中,“.PHONY”表示,clean是個偽目標文件。
即然make可以自動推導命令,那堆[.o]和[.h]的依賴同樣可以收攏起來。進階2.1:
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h .PHONY : clean clean : rm edit $(objects)
上面2.1的版本使makefile變得更簡單,但文件依賴關系就顯得有點凌亂,魚和熊掌不可兼得,各取所好。
2 清空目標文件的規則
每個Makefile中都應該寫一個清空目標文件(.o和執行文件)的規則,這不僅便於重編譯,也很利於保持文件的清潔。一般的風格都是:clean:
rm edit $(objects)
更為穩健的做法是:
.PHONY : clean
clean :
-rm edit $(objects)
前面說過,.PHONY意思表示clean是一個“偽目標”,不聲明偽目標的話,如果當前目錄有個名為clean的文件,就會認為目標已存在,導致后面規則不執行了。而在rm命令前面加了一個小減號的意思就是,也許某些文件出現問題,但不要管,繼續做后面的事。
二、模板:
1、編譯動態庫
#############################################################
# Makefile for shared library. # 編譯動態鏈接庫 ############################################################# #set your own environment option CC = g++ CC_FLAG = -D_NOMNG -D_FILELINE #set your inc and lib INC = LIB = -lpthread -L./ -lsvrtool #make target lib and relevant obj PRG = libsvrtool.so OBJ = Log.o #all target all:$(PRG) $(PRG):$(OBJ) $(CC) -shared -o $@ $(OBJ) $(LIB) .SUFFIXES: .c .o .cpp .cpp.o: $(CC) $(CC_FLAG) $(INC) -c $*.cpp -o $*.o .PRONY:clean clean: @echo "Removing linked and compiled files......; rm -f $(OBJ) $(PRG)
2、編譯靜態庫
#############################################################
# Makefile for static library. # 編譯靜態鏈接庫 ############################################################# #set your own environment option CC = g++ CC_FLAG = -D_NOMNG -D_FILELINE #static library use 'ar' command AR = ar #set your inc and lib INC = LIB = -lpthread -L./ -lsvrtool #make target lib and relevant obj PRG = libsvrtool.a OBJ = Log.o #all target all:$(PRG) $(PRG):$(OBJ) ${AR} rv ${PRG} $? .SUFFIXES: .c .o .cpp .cpp.o: $(CC) $(CC_FLAG) $(INC) -c $*.cpp -o $*.o .PRONY:clean clean: @echo "Removing linked and compiled files......" rm -f $(OBJ) $(PRG)
3、可執行程序
###########################################
#Makefile for simple programs ########################################### INC= LIB= -lpthread CC=CC CC_FLAG=-Wall PRG=threadpooltest OBJ=CThreadManage.o CThreadPool.o CThread.o CWorkerThread.o threadpooltest.o $(PRG):$(OBJ) $(CC) $(INC) $(LIB) -o $@ $(OBJ) .SUFFIXES: .c .o .cpp .cpp.o: $(CC) $(CC_FLAG) $(INC) -c $*.cpp -o $*.o .PRONY:clean clean: @echo "Removing linked and compiled files......" rm -f $(OBJ) $(PRG)