Linux學習:Makefile簡介及模板


一、基本概念介紹:

   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指令后的執行內容如下:

  1.   make會在當前目錄下找名字叫“Makefile”或“makefile”的文件。
  2.   如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到“edit”這個文件,並把這個文件作為最終的目標文件。
  3.   如果edit文件不存在,或是edit所依賴的后面的 .o 文件的文件修改時間要比edit這個文件新,那么,他就會執行后面所定義的命令來生成edit這個文件。
  4.   如果edit所依賴的.o文件也存在,那么make會在當前文件中找目標為.o文件的依賴性,如果找到則再根據那一個規則生成.o文件。(這有點像一個堆棧的過程)
  5.   當然,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變得更簡單,但文件依賴關系就顯得有點凌亂,魚和熊掌不可兼得,各取所好。

清空目標文件的規則

   每個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) 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM