Makefile自動生成依賴文件,並自動編譯


轉載於: http://blog.sina.com.cn/s/blog_87c063060101ky45.html

1.關於GCC怎么樣自動生成‘依賴’.網上有很多版本,有使用“正則法則”實現的,也有其他方法實現的.

筆者通過比較,覺得最簡單的還是Linux內核里面的規則最簡單.
 
2.在GCC的命令行加一條這樣的語句就OK了. 
  -Wp,-MD,drivers/leds/.XXX.o.d   (其中drivers/leds/.XXX.o.d為依賴文件,里面記錄了很多依賴信息)
 
3.就這么簡單,來舉個例子.Linux內核的一條命令
 
cmd_drivers/leds/led-core.o := arm-linux-gcc -Wp,-MD,drivers/leds/.led-core.o.d  
-nostdinc -isystem /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/include 
-D__KERNEL__ -Iinclude  -include include/linux/autoconf.h 
-mlittle-endian 
-Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing 
-fno-common -Os -marm -fno-omit-frame-pointer 
-mapcs -mno-sched-prolog -mapcs-32 -mno-thumb-interwork 
-D__LINUX_ARM_ARCH__=4 -march=armv4t -mtune=arm9tdmi -malignment-traps -msoft-float 
-Uarm -fno-omit-frame-pointer -fno-optimize-sibling-calls 
-g  -Wdeclaration-after-statement     
-D"KBUILD_STR(s)=\#s" -D"KBUILD_BASENAME=KBUILD_STR(led_core)"  
-D"KBUILD_MODNAME=KBUILD_STR(led_core)" 
-c -o drivers/leds/led-core.o drivers/leds/led-core.c
   
4.自己來舉個例子吧!
  ①四個文件:def.h  hello.c  main.c  Makefile
   ②四個文件的內容分別為
  def.h:
  #ifndef  __DEF_H
  #define  __DEF_H
  #define  A      5
  void hello();
  #endif   //__DEF_H
   
  hello.c:
  #include<stdio.h>
  #include"def.h"
  void hello()
  {
        printf("hello world!\n");
        printf("A = %d\n",A);
  }
 
  main.c:
  #include<stdio.h>
  #include"def.h"
  int main(void)
  {
        hello();
        return 0;
  }
 
  Makefile:
  PHONY := test
  CROSS_COMPILE =
  CC  = $(CROSS_COMPILE)gcc
 
  CFLAGS := -Wall -Werror -O2 -g
  LDFLAGS =
  test: hello.o main.o
        $(CC) $(LDFLAGS) -o $@  $^
 
  %.o : %.c
        $(CC) $(CFLAGS)   -c -o $@ $<        
  clean:
        rm *.o  test .*.d
 
  ③現象
   在終端輸入命令:make
   gcc -Wall -Werror -O2 -g -c -o hello.o hello.c 
   gcc -Wall -Werror -O2 -g -c -o main.o main.c 
   gcc  -o test  hello.o main.o
 
   運行:./test
   hello world!
   A = 5
   
   ④來修改一個文件,把def.h當中的 #define  A      5 改為 #define  A      10  然后再make一下. 
    make: `test' is up to date.
 
   ⑥來修改一下Makefile
  PHONY := test
  CROSS_COMPILE =
  CC  = $(CROSS_COMPILE)gcc
 
  CFLAGS := -Wall -Werror -O2 -g
  LDFLAGS =
  test: hello.o main.o
        $(CC) $(LDFLAGS) -o $@  $^
  dep_file = .$@.d        (特別注意:這里只能用 = ,也就是遞歸展開 ,而不能用 := ,進行直接展開)
  <讀者可以修改觀察一下現象,就可以知道 遞歸展開 = 與 直接展開 := 的區別了,可以感性認識一下二者的區別.> 
   %.o : %.c
        $(CC) $(CFLAGS) -Wp,-MD,$(dep_file)  -c -o $@ $<         
  clean:
        rm *.o  test .*.d
    
   再來 make 一下:
   提示: make: `test' is up to date.
   那么,make clean 之后,再來make看看:
   提示信息:
    gcc -Wall -Werror -O2 -g -Wp,-MD,.hello.o.d  -c -o hello.o hello.c
    gcc -Wall -Werror -O2 -g -Wp,-MD,.main.o.d  -c -o main.o main.c
    gcc  -o test  hello.o main.o
    執行一下看看:./test 
     hello world!
     A = 10
    用ls -al 命令看看: 確實生成了“依賴文件”
    .hello.o.d
    .main.o.d
 
   ⑦再一次修改def.h試試:
    把def.h當中的 #define  A      10 改為 #define  A      20  然后再make一下.
    make: `test' is up to date.
    明明已經生成依賴文件了,為什么make還會提示,說沒有更新呢?(后面我們用:時間軸更新 來說明)
 
    筆者也折騰了一陣,后來發現,是“依賴文件”沒有"被包含"進Makefile,導致make的“時間軸”沒有更新.
 
   ⑧再來修改Makefile:
     在Makefile里面加這么一句:  include .*.o.d  表示包含所以的 .d文件(依賴文件).
     注意:有的需要寫成這種形式 -include .*.o.d   
     再一次make:
     提示信息:
     gcc -Wall -Werror -O2 -g -Wp,-MD,.hello.o.d  -c -o hello.o hello.c
     gcc -Wall -Werror -O2 -g -Wp,-MD,.main.o.d  -c -o main.o main.c
     gcc  -o test  hello.o main.o
     果然成功了.
     再來執行一下:  ./test 
     hello world!
     A = 20    
   
5.總結
  在Makefile中,“依賴關系”也是一個比較重要的規則,尤其是“自動生成依賴”.這里筆者舉了個簡單的例子加以說明.對於Linux,尤其是這種內容,講起來會比較抽象,盡量自己多去舉幾個例子,去實踐實踐,結果很快就可以出來了,也可以加深理解!
   
6.補充
  關於,在Makefile中, include 與 -include 的區別
  通過試驗,筆者得出  include 與 -include 存在着用法上的區別,而且內核的Makefile當中,也同時出現過這兩種情況.
  在上個實驗當中, 用 include.*.o.d 出現了如下錯誤提示: 
  Makefile:31: .*.o.d: No such file or directory
  make: *** No rule to make target `.*.o.d'.  Stop.
   而用 -include .*.o.d 卻解決了問題 
 
在網上找了一篇文章:http://blog.csdn.net/xiaozhi_su/article/details/4202779
 

      指示符include”、-include”和sinclude

       如果指示符include指定的文件不是以斜線開始(絕對路徑,如/usr/src/Makefile...),而且當前目錄下也不存在此文件;make將根據文件名試圖在以下幾個目錄下查找:

       首先,查找使用命令行選項-I”或者--include-dir”指定的目錄,如果找到指定的文件,則使用這個文件;

       否則,繼續依此搜索以下幾個目錄(如果其存在):/usr/gnu/include”、/usr/local/include”和/usr/include”。     

       當在這些目錄下都沒有找到include”指定的文件時,make將會提示一個包含文件未找到的告警提示,但是不會立刻退出。而是繼續處理Makefile的后續內容。當完成讀取整個Makefile后,make將試圖使用規則來創建通過指示符include”指定的但未找到的文件,當不能創建它時(沒有創建這個文件的規則),make將提示致命錯誤並退出。會輸出類似如下錯誤提示:

       Makefile:錯誤的行數:未找到文件名:提示信息(No such file or directory

       Make: *** No rule to make target ‘<filename>’. Stop

       通常我們在Makefile中可使用-include”來代替include,來忽略由於包含文件不存在或者無法創建時的錯誤提示(-”的意思是告訴make,忽略此操作的錯誤make繼續執行)。像下邊那樣:

       -include FILENAMES...

       使用這種方式時,當所要包含的文件不存在時不會有錯誤提示、make也不會退出;除此之外,和第一種方式效果相同。以下是這兩種方式的比較:

       使用include FILENAMES...”,make程序處理時,如果FILENAMES”列表中的任何一個文件不能正常讀取而且不存在一個創建此文件的規則時make程序將會提示錯誤並退出

 

       使用-include FILENAMES...”的情況是,當所包含的文件不存在或者不存在一個規則去創建它,make程序會繼續執行,只有真正由於不能正確完成終極目標重建時(某些必需的目標無法在當前已讀取的makefile文件內容中找到正確的重建規則),才會提示致命錯誤並退出。

 

為了和其它的make程序進行兼容。也可以使用sinclude”來代替-include”(GNU所支持的方式)。


免責聲明!

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



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