<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Makefile 自動生成依賴

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    雖然以前對Makefile有個基本概念,但是真正到自己去寫一個哪怕是簡單的Makefile時也會遇到不少的麻煩。
        現在我有如下文件 dList.h dList.c memory.c debug.c debug.h test.c aaron.h 其中包含關系如下:
        aaron.h-->dList.h debug.h
        dList.c-->aaron.h
        debug.c-->aaron.h
        test.c-->aaron.h
        memory.c-->aaron.h
        第一次寫Makefile如下:
        OBJS := test.o debug.o memory.o dList.o
        MACRO = DEBUGALL
        CFLAGS+= -g  -D$(MACRO)
        CC = gcc
        main: $(OBJS)
               $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
        clean:
            rm -f $(OBJS)
            rm -f main
        第一次看看似乎沒什么問題啊。真正運行發現這個Makefile沒有反應出.c文件對.h文件的依賴性,所以當.h文件發生變化時Makefile執行并不會發生變化。于是有了第二版:
        OBJS := test.o debug.o memory.o dList.o
        MACRO = DEBUGALL
        CFLAGS+= -g  -D$(MACRO)
        CC = gcc
        main: $(OBJS)
               $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
        %o: aaron.h
        clean:
            rm -f $(OBJS)
            rm -f main
        這樣當aaron.h發生變化時,所有.o都會被更新,從而main也會被更新。但是問題還是有,aaron是依賴于dList.h, debug.h的,如果這兩個頭文件發生變化在這個Makefile里仍然不能使main重新編譯。繼續改造:
        OBJS := test.o debug.o memory.o dList.o
        MACRO = DEBUGALL
        CFLAGS+= -g  -D$(MACRO)
        CC = gcc
        main: $(OBJS)
               $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
        %o: aaron.h dList.h debug.h
        clean:
            rm -f $(OBJS)
            rm -f main
        這下看上去能滿足我的要求。但是仔細一想就會發現如果我這個工程很大,靠手工去找到每個.c文件對應的所有頭文件然后來完成這個Makefile似乎是不太可能而且也很難維護。于是想著Makefile應該有機制能自動生成依賴關系吧。
        于是找出寶典《GNU make中文手冊》搜索了下果然有自動生成依賴相關內容。主要是利用gcc 的編譯選項-M和-MM。不過讓我看了半天也沒有看明白其中的玄機。最后又重新翻看了改寶典眾多章節總算理解了。先把代碼貼出來:
                                                                                                                                   
        MACRO = DEBUGALL
        CFLAGS+= -g -w -D$(MACRO)
        SOURCES = $(wildcard *.c)
        OBJS := $(patsubst %.c, %.o,$(SOURCES))
        
        CC = gcc
        main: $(OBJS)
               @echo "source files:" $(SOURCES)
               @echo "object files:" $(OBJS)
               $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
        sinclude $(SOURCES:.c=.d)
        %d: %c
              @echo "create depend"
              $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
              sed 's,\($*\)\.o[ :]*,\1.o $@ ,g' < $@.$$$$ > $@; \
              $(RM) $@.$$$$
              
      clean:
              rm -rf $(OBJS)
              rm -f main
        下面一行一行來分析下這個Makefile.
        前面兩行很簡單就是定義編譯變量和編譯選項。
        SOURCES = $(wildcard *.c) 這句話意思是定義一個變量SOURCES,它的值包含當前目錄下所有.c文件。 在我的例子里我把這個值打印出來了就是dList.c memory.c test.c debug.c
        $(wildcard PATTEN) 是Makefile內建的一個函數:
        函數名稱:獲取匹配模式文件名函數—wildcard
        函數功能:列出當前目錄下所有符合模式“PATTERN”格式的文件名。
        返回值:空格分割的、存在當前目錄下的所有符合模式“PATTERN”的文件名。
        函數說明:“PATTERN”使用shell可識別的通配符,包括“?”(單字符)、“*”(多字符)等
        
        
        OBJS := $(patsubst %.c, %.o,$(SOURCES)) 這一行是定義了一個變量OBJS,它的值是將變量SOURCES里的內容以空格分開,將所有.c文件替換成.o. 在我的例子里打印出來就是dList.o memory.o test.o debug.o。
        $(patsubst PATTEN, REPLACEMENT, TEXT)也是內建函數
        函數名稱:模式替換函數—patsubst。
        函數功能:搜索“TEXT”中以空格分開的單詞,將否符合模式“TATTERN”替換為“REPLACEMENT”
        
        
        sinclude $(SOURCES:.c=.d) 這一行是非常關鍵的,它在當前Makefile里去include另外的Makefile. 這里“另外”的Makefile是將SOURCES變量里所有.c替換成.d。 在我的例子里就是dList.d memory.d test.d debug.d. 意思就是執行到這里
        的時候先去依次執行dList.d memory.d test.d debug.d. 這里的.d文件就是包含了每個.c文件自動生成的對頭文件的依賴關系。這個依賴關系將由下面的%d:%c來完成。
        
        %d: %c
        此規則的含義是:所有的.d文件依賴于同名的.c文件。
    第一行;使用c編譯器自自動生成依賴文件($<)的頭文件的依賴關系,并輸出成為一個臨時文件,“$$$$”表示當前進程號。如果$(CC)為GNU的c編譯工具,產生的依賴關系的規則中,依賴頭文件包括了所有的使用的系統頭文件和用戶定義的頭文件。如果需要生成的依賴描述文件不包含系統頭文件,可使用“-MM”代替“-M”。
    第二行;使用sed處理第二行已產生的那個臨時文件并生成此規則的目標文件。經過這一行后test.d里內容如下:test.o: test.c aaron.h dList.h debug.h 其他.d里以此類推。
    第三行;刪除臨時文件。

        到這里基本的意義弄明白了,但是讓我不解的是%d: %c這個依賴的規則怎么能被執行到的?按照我的理解Makefile在執行時首先檢查終極目標main是否存在,如果不存在則建立(根據main的依賴規則),如果存在在需要查看
        main的依賴文件是否存在并且是最新的,這我的例子里就是要看test.o dList.o memory.o debug.o是否存在且最新。這樣追下去是否沒有%d: %c什么事啊, .d文件也應該不存在或者說是空的。盡管我們include了.d文件,但是沒有依賴規則去執行它啊。后來仔細閱讀了
        Makefile文件的重建才明白了。
        Makefile如果由其它文件重建(這里我的Makefile include了所有.d文件,.d也可以看成是一個Makefile),Makefile在讀入所有其他makefile文件(.d)之后,首先將所讀取的每個makefile(.d)作為一個目標,尋找更新它們的規則。同樣
        如果此目標不存在則根據依賴規則重新創建。在例子里其實.d文件開始并不存在,所以當Makefile在include這些.d文件時首先看.d存在不,不存在就要去尋找.d的依賴文件和規則。這里就找到了%d: %c從而創建出真正的.d文件。其實這里的關鍵點就是對于
        include了理解,它是把include的文件首先當成一個目標,然后要去尋找其依賴文件和規則的,而不是我事先想象的簡單的把其他文件的內容包含過來。
        到此,問題解決,基本達到預期。

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全