<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系統、金蝶與條碼系統對接、用友與條碼系統對接

    MakefileLinux下程序開發的自動化編譯工具,一個好的Makefile應該準確的識別編譯目標與源文件的依賴關系,并且有著高效的編譯效率,即每次重新make時只需要處理那些修改過的文件即可。Makefile擁有很多復雜的功能,這里不可能也沒必要一一介紹,為了簡化問題的復雜性,本文僅和大家討論針對單目錄下的C/C++項目開發,如何寫一個通用的Makefile

    首先,我們假設當前工程目錄為prj/,該目錄下有6個文件,分別是:main.cabc.cxyz.cabc.hxyz.hMakefile。其中main.c包含頭文件abc.hxyz.habc.c包含頭文件abc.hxyz.c包含頭文件xyz.h,而abc.h又包含了xyz.h。它們的依賴關系如圖1

     

     

    文件依賴關系

    第一次使用Makefile應該寫成這個樣子(假設生成目標main):

    main:main.o abc.o xyz.o

        gcc main.o abc.o xyz.o -o main

    main.o:main.c abc.h xyz.h

        gcc -c main.c –o main.o -g

    abc.o:abc.c abc.h xyz.h

        gcc -c abc.c –o abc.o -g

    xyz.o:xyz.c xyz.h

        gcc -c xyz.c -o xyz.o -g

    clean:

        rm main main.o abc.o xyz.o -f

    雖然這樣Makefile完全符合Makefile的書寫規則,但是當代碼文件再增加幾倍后,再管理這些命令將會是一個噩夢!!!因此Makefile提供了默認規則和自動推導幫我們完成一些常用功能。然后,我們將Makefile修改如下:

    EXE=main

    CC=gcc

    OBJ=main.o abc.o xyz.o

    CFLAGS=-g

    (EXE):(OBJ)

        (CC)^ -o $@

    clean:

        rm (EXE)(OBJ) -f

    變量EXECCOBJ分別代指目標程序名,編譯器名,目標文件名。CFLAGSMakefile的預定義變量,它會附加在每條編譯命令(gcc -c)之后。

    $(EXE)是對變量的引用,$^代指所有的依賴項——即$(OBJ)$@代指目標項——即$(EXE)。該命令等價于:(CC)(OBJ) -o $(EXE)

    這個Makefile只有目標文件鏈接的命令,源文件的編譯命令都被忽略了!這正是Makefile的自動推導功能——它可以將目標文件自動依賴于同名的源文件,即:

    main.o:main.c

        gcc -c main.c -o main.o

    abc.o:abc.c

        gcc -c abc.c -o abc.o

    xyz.o:xyz.c

        gcc -c xyz.c -o xyz.o

     

    按照上述方式,只要工程下增加了源文件后,只需要在OBJ初始化處增加一個*.o即可。但是這種方式是有問題的,Makefile的自動推導功能只會推導出目標文件對源文件的依賴關系,而不會增加頭文件的依賴關系!!!這導致的直接問題就是修改項目的頭文件,不會導致make的自動更新!除非修改頭文件后運行一次make clean,再運行make…… :-)

    為了能讓make自動包含頭文件的依賴關系,我們需要做一點額外的工作。幸運的是gcc為我們提供了一個編譯選項(gcc -M,對于g++-MM),能輸出目標文件的依賴關系!比如:

    $gcc -M main.c

    main.o:main.c abc.h xyz.h

    如果將每個源文件的依賴關系包含到Makefile里,就可以使得目標文件自動依賴于頭文件了!再次修改原先的Makefile

    EXE=main

    CC=gcc

    SRC=$(wildcard *.c)

    OBJ=$(SRC:.c=.o)

    CFLAGS=-g

    all:depend $(EXE)

    depend:

    @(CC)−MM(SRC) > .depend

    -include .depend

    (EXE):(OBJ)

    (CC)(OBJ) -o $(EXE)

    clean:

    @rm (EXE)(OBJ) .depend -f

    我們虛設了一個目標all,它依賴于depend和實際的目標EXE。而depend正式將所有的源文件對應的目標文件的依賴關系輸入到.depend文件,并包含在Makefile內!這里有幾個細節需要說明:

    1.depend文件是隱藏文件,避免和工程的文件混淆。

    2include命令之前增加符號‘-’,避免第一次make時由于.depend文件不存在報告錯誤信息。

    3SRC初始化為wildcard *.c表示當前目錄下的所有.c源文件,這就省去了我們手動輸入新增的源文件。

    4OBJ初始化為SRC:.c=.o,表示將SRC中所有.c結尾的文件名替換為.o結尾的,這樣就自動生成了源文件的目標文件序列。

    5cleanrm命令錢@符號表示執行該命令時不輸出任何信息。

    這樣,每次執行make時都會重新計算目標文件的依賴關系,并輸出到.depend文件,然后包含到Makefile后進行編譯工作,這樣目標文件的依賴關系就不會出錯了!而我們得到了一個能自動包含源文件和識別頭文件依賴關系的Makefile,將該文件應用于任何單目錄的C/C++工程(C++需要修改部分細節,不作贅述)都能正常工作。

    但是,這種方式也有一定的不足,當頭文件的依賴關系不發生變化時,每次make也會重新生成.depend文件。如果這樣使得工程的編譯變得不盡人意,那么我們可以嘗試將依賴文件拆分,使得每個源文件獨立擁有一個依賴文件,這樣每次make時變化的只是一小部分文件的依賴關系。

    EXE=main

    CC=gcc

    SRC=$(wildcard *.c)

    OBJ=$(SRC:.c=.o)

    DEP=(patsubst(SRC))

    CFLAGS=-g

    (EXE):(OBJ)

    (CC)^ -o $@

    $(DEP):.%.d:%.c

    @set -e;\

    rm -f $@;\

    (CC)−M< > @.$$$;\

    sed 's,$∗\.o[ :]*,\1.o @:,g′<@.

      > $@;\

     

    rm -f @.$$$

    -include $(DEP)

    clean:

    @rm (EXE)(OBJ) $(DEP) -f

    Makefile增加了一個變量DEP,初始化為patsubst %.c,.%.d,$(SRC),表示將SRC中的以*.c結尾的源文件名替換為.*.d的形式,比如main.c對應著文件.main.d,這就是main.c的依賴關系文件,且是隱藏的。

    為了生成每個源文件的依賴文件,建立了目標依賴關系$(DEP):.%.d:%.c,該關系表示,對于目標DEP,通過$@可以訪問一個依賴文件,通過$>則訪問對應的同名源文件。命令部分使用\連接,表示當前命令作為一個整體在一個進程內執行。該組命令的含義是:將gcc -M生成的信息輸出到一個臨時文件,然后在:之前加上當前的文件名輸出到依賴文件。比如對于main.c生成的臨時文件信息為:

    main.o:main.c abc.h xyz.h

    處理后依賴文件信息是:

    main.o .main.d:main.c abc.h xyz.h

    這樣的依賴關系表示main.o和它的依賴關系文件的依賴項是一致的,只要相關的源文件或頭文件發生了改變,才會重新生成目標文件和依賴關系文件,也就達到了依賴關系文件單獨更新的目的了。

    雖然如此,但是這樣的Makefile也不是完美的。現假設工程目錄內新增一個源文件lmn.c,按照Makefile的指令make后會產生.lmn.d依賴關系文件。而如果我們再刪除lmn.c源文件后,重新make.lmn.d依然存在!尤其是當重復增刪很多源文件后,工程目錄下可能會存在很多無用的依賴文件,當然這些問題可以通過make clean解決。

    通過前邊的討論,我們得到一個能在單目錄工程下工作的通用Makefile,至于是實現為單獨一個依賴文件的形式,還是每個源文件產生一個獨立的依賴文件,要根據程序作者自己的喜惡來選擇。雖然每種方法都有一些細微的瑕疵,但是不影響這個通用的Makefile的實用性,試想一下在工程目錄下拷貝一份當前的Makefile,稍加修改便可以正確的編譯開發,一定會令人心情大好。希望本文對你學習Linux寫的程序開發有所幫助!

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