<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 自動處理頭文件的依賴關系 (zz)

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

    現在我們的Makefile寫成這樣:

    all: main

    main: main.o stack.o maze.o
    gcc $^ -o $@

    main.o: main.h stack.h maze.h
    stack.o: stack.h main.h
    maze.o: maze.h main.h

    clean:
    -rm main *.o

    .PHONY: clean
    按照慣例,用all做缺省目標。現在還有一點比較麻煩,在寫main.o、stack.o和maze.o這三個目標的規則時要查看源代碼,找出它們依賴于哪些頭文件,這很容易出錯,一是因為有的頭文件包含在另一個頭文件中,在寫規則時很容易遺漏,二是如果以后修改源代碼改變了依賴關系,很可能忘記修改Makefile的規則。為了解決這個問題,可以用gcc的-M選項自動生成目標文件和源文件的依賴關系:

    $ gcc -M main.c
    main.o: main.c /usr/include/stdio.h /usr/include/features.h \
    /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
    /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \
    /usr/lib/gcc/i486-linux-gnu/4.3.2/include/stddef.h \
    /usr/include/bits/types.h /usr/include/bits/typesizes.h \
    /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
    /usr/lib/gcc/i486-linux-gnu/4.3.2/include/stdarg.h \
    /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h main.h \
    stack.h maze.h
    -M選項把stdio.h以及它所包含的系統頭文件也找出來了,如果我們不需要輸出系統頭文件的依賴關系,可以用-MM選項:

    $ gcc -MM *.c
    main.o: main.c main.h stack.h maze.h
    maze.o: maze.c maze.h main.h
    stack.o: stack.c stack.h main.h
    接下來的問題是怎么把這些規則包含到Makefile中,GNU make的官方手冊建議這樣寫:

    [plain] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. all: main  
    2.   
    3. main: main.o stack.o maze.o  
    4. gcc $^ -o $@  
    5.   
    6. clean:  
    7. -rm main *.o  
    8.   
    9. .PHONY: clean  
    10.   
    11. sources = main.c stack.c maze.c  
    12.   
    13. include $(sources:.c=.d)  
    14.   
    15. %.d: %.c  
    16. set -e; rm -f $@; \  
    17. $(CC) -MM $(CPPFLAGS) $< > $@.   ; \  
    18. sed 's,$\.o[ :]*,\1.o $@ : ,g' < $@.    > $@; \  
    19. rm -f $@.     


    sources變量包含我們要編譯的所有.c文件,$(sources:.c=.d)是一個變量替換語法,把sources變量中每一項的.c替換成.d,所以include這一句相當于:

    include main.d stack.d maze.d
    類似于C語言的#include指示,這里的include表示包含三個文件main.d、stack.d和maze.d,這三個文件也應該符合Makefile的語法。如果現在你的工作目錄是干凈的,只有.c文件、.h文件和Makefile,運行make的結果是:

    $ make
    Makefile:13: main.d: No such file or directory
    Makefile:13: stack.d: No such file or directory
    Makefile:13: maze.d: No such file or directory
    set -e; rm -f maze.d; \
    cc -MM maze.c > maze.d.

    ; seds,\(maze\)\.o[:],\1.omaze.d:,g<maze.d.

    > maze.d; \
    rm -f maze.d.

    sete;rmfstack.d; ccMMstack.c>stack.d.

    ; \
    sed 's,stack\.o[ :]*,\1.o stack.d : ,g' < stack.d.

    >stack.d; rmfstack.d.


    set -e; rm -f main.d; \
    cc -MM main.c > main.d.

    ; seds,\(main\)\.o[:],\1.omain.d:,g<main.d.

    > main.d; \
    rm -f main.d.$$
    cc -c -o main.o main.c
    cc -c -o stack.o stack.c
    cc -c -o maze.o maze.c
    gcc main.o stack.o maze.o -o main
    一開始找不到.d文件,所以make會報警告。但是make會把include的文件名也當作目標來嘗試更新,而這些目標適用模式規則%.d: %c,所以執行它的命令列表,比如生成maze.d的命令:

     

    set -e; rm -f maze.d; \
    cc -MM maze.c > maze.d.

    ; seds,\(maze\)\.o[:],\1.omaze.d:,g<maze.d.

    > maze.d; \
    rm -f maze.d.$$
    注意,雖然在Makefile中這個命令寫了四行,但其實是一條命令,make只創建一個Shell進程執行這條命令,這條命令分為5個子命令,用;號隔開,并且為了美觀,用續行符\拆成四行來寫。執行步驟為:

     

    set -e命令設置當前Shell進程為這樣的狀態:如果它執行的任何一條命令的退出狀態非零則立刻終止,不再執行后續命令。

    把原來的maze.d刪掉。

    重新生成maze.c的依賴關系,保存成文件maze.d.1234(假設當前Shell進程的id是1234)。注意,在Makefile中$有特殊含義,如果要表示它的字面意思則需要寫兩個$,所以Makefile中的四個$傳給Shell變成兩個$,兩個$在Shell中表示當前進程的id,一般用它給臨時文件起名,以保證文件名唯一。

    這個sed命令比較復雜,就不細講了,主要作用是查找替換。maze.d.1234的內容應該是maze.o: maze.c maze.h main.h,經過sed處理之后存為maze.d,其內容是maze.o maze.d: maze.c maze.h main.h。

    最后把臨時文件maze.d.1234刪掉。

    不管是Makefile本身還是被它包含的文件,只要有一個文件在make過程中被更新了,make就會重新讀取整個Makefile以及被它包含的所有文件,現在main.d、stack.d和maze.d都生成了,就可以正常包含進來了(假如這時還沒有生成,make就要報錯而不是報警告了),相當于在Makefile中添了三條規則:

    main.o main.d: main.c main.h stack.h maze.h
    maze.o maze.d: maze.c maze.h main.h
    stack.o stack.d: stack.c stack.h main.h
    如果我在main.c中加了一行#include "foo.h",那么:

    1、main.c的修改日期變了,根據規則main.o main.d: main.c main.h stack.h maze.h要重新生成main.o和main.d。生成main.o的規則有兩條:

    main.o: main.c main.h stack.h maze.h
    %.o: %.c
    # commands to execute (built-in):
    $(COMPILE.c) $(OUTPUT_OPTION) $<
    第一條是把規則main.o main.d: main.c main.h stack.h maze.h拆開寫得到的,第二條是隱含規則,因此執行cc命令重新編譯main.o。生成main.d的規則也有兩條:

    main.d: main.c main.h stack.h maze.h
    %.d: %.c
    set -e; rm -f $@; \
    $(CC) -MM $(CPPFLAGS) $< > $@.

     

    ; \
    sed 's,$\.o[ :]*,\1.o $@ : ,g' < $@.> $@; \
    rm -f $@.
    因此main.d的內容被更新為main.o main.d: main.c main.h stack.h maze.h foo.h。

     

    2、由于main.d被Makefile包含,main.d被更新又導致make重新讀取整個Makefile,把新的main.d包含進來,于是新的依賴關系生效了。

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