<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主要內容都放在頂層目錄下的Makefile.env中,子層Makefile包含這個Makefile.env,只要增加一些變量就可以編譯,特別方便添加新的功能模塊
    • 自動解析頭文件依賴

    我的程序的目錄結構是這樣的:

    1. 源文件目錄src,模塊xxx放在src/xxx下,主程序在src/main下面

    2.公共頭文件放在include目錄下,模塊xxx的頭文件放在include/xxx目錄下

    3.模塊輸出的鏈接庫放在lib目錄下

    4.可執行文件放在bin目錄下

    先來看一下Makefile.env,這個類似于c的頭文件,包含了所有Makefile的公共部分,

    復制代碼
    ###########  MakeFile.env  ##########
    # Top level pattern, include by Makefile of child directory
    # in which variable like TOPDIR, TARGET or LIB may be needed
    
    CC=gcc
    MAKE=make
    
    AR=ar cr
    RM = -rm -rf
    
    CFLAGS+=-Wall
    
    dirs:=$(shell find . -maxdepth 1 -type d)
    dirs:=$(basename $(patsubst ./%,%,$(dirs)))
    dirs:=$(filter-out $(exclude_dirs),$(dirs))
    SUBDIRS := $(dirs)
    
    SRCS=$(wildcard *.c)
    OBJS=$(SRCS:%.c=%.o)
    DEPENDS=$(SRCS:%.c=%.d)
    
    
    all:$(TARGET)  $(LIB) subdirs
    
    $(LIB):$(OBJS) 
        $(AR)  $@  $^
        cp $@ $(LIBPATH) 
    
    subdirs:$(SUBDIRS)
        for dir in $(SUBDIRS);\
        do $(MAKE) -C $$dir all||exit 1;\
        done
    
    $(TARGET):$(OBJS)
        $(CC) -o $@ $^ $(LDFLAGS)
        cp $@ $(EXEPATH)
    
    
    $(OBJS):%.o:%.c
        $(CC) -c $< -o $@ $(CFLAGS)
    
    
    -include $(DEPENDS)
    
    $(DEPENDS):%.d:%.c
        set -e; rm -f $@; \
        $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
        sed 's,\($*\)\.o[:]*,\1.o $@:,g' < $@.$$$$ > $@; \
        rm $@.$$$$
    
    clean:
        for dir in $(SUBDIRS);\
        do $(MAKE) -C $$dir clean||exit 1;\
        done
        $(RM) $(TARGET) $(LIB)  $(OBJS) $(DEPENDS)
    復制代碼

    當前目錄下的子目錄是通過shell命令自動得到的,subdirs:$(SUBDIRS) 這塊會進入每個子目錄執行make,當然有些子目錄并不需要編譯,可以通過exclude_dirs指定,比如頂層目錄的exclude_dirs=bin lib include。

    $(DEPENDS):%.d:%.c 這塊作用是自動生成頭文件依賴,這部分包括5條命令,看起來很復雜,其實原理很簡單,假設main.c,包含頭文件depend.h, 解析過程如下:

    1. @set –e 命令設置當前Shell進程狀態為:如果執行的任何一條命令的退出狀態非零則立刻終止當前進程。

    2. rm -f $@ 刪除原來的main.d文件

    3. gcc的-MM參數能夠生成文件的依賴關系main.o:main.c depend.h,寫入文件main.d. $$$$,$$是進程號

    4. sed命令作用是將main.o:main.c depend.h替換成main.o main.d:main.c depend.h, 并寫入main.d文件

    5. rm -f $@.$$$$刪除臨時文件

    Include $(SRCS:.c=.d)將main.d包含進來后,Makefile增加了以下依賴

    main.o main.d:main.c depend.h

    不管是main.c還是depend.h的變化都會更新main.o 以及main.d,main.d的更新又反過來更新上面這條依賴關系。

    這條依賴下面并沒有對應的命令,為什么會更新目標文件呢?這跟Makefile的運行步驟有關系,引用下陳浩先生的《跟我一起寫Makefile》

    GNU的 make 工作時的執行步驟如下:

    1、讀入所有的 Makefile。

    2、讀入被 include 的其它 Makefile。

    3、初始化文件中的變量。

    4、推導隱晦規則,并分析所有規則。

    5、為所有的目標文件創建依賴關系鏈。

    6、根據依賴關系,決定哪些目標要重新生成。

    7、執行生成命令。

    所以1-5 步為第一個階段,形成了所有的依賴關系鏈,6-7 為第二個階段,決定了所有需要生成的目標文件后,執行對應的命令。上面的依賴關系雖然沒有命令,但是確定了main.o要重新生成,就會找到以下編譯模塊生成目標文件

    $(OBJS):%.o:%.c
        $(CC) -c $< -o $@ $(CFLAGS)

    假設有一個模塊first,源文件都放在src/first下,Makefile如下

    復制代碼
    TOPDIR=./../..
    
    LIB=libfirst.a
    
    INCPATH=$(TOPDIR)/include/first
    LIBPATH=$(TOPDIR)/lib
    CFLAGS= -I$(INCPATH)
    
    include $(TOPDIR)/Makefile.env
    復制代碼

    TOPDIR是相對于頂層目錄的相對路徑,LIB是要生成的鏈接庫,這樣只要幾行命令就可以完成當前模塊的編譯了,而且first下面還可以添加子模塊。

    假設main.c在src/main目錄下,調用了first模塊,Makefile如下

    復制代碼
    TOPDIR=./../..
    
    TARGET=main
    
    LIBPATH=$(TOPDIR)/lib
    EXEPATH=$(TOPDIR)/bin
    
    CFLAGS= -I$(TOPDIR)/include/first 
    LDFLAGS= -lfirst
    
    include $(TOPDIR)/Makefile.env
    復制代碼

    TARGET是生成的可執行文件名,在LIBPATH目錄下尋找鏈接庫,生成的可執行文件會被mv到EXEPATH目錄下

    src下沒有源文件,只有目錄,所以Makefile非常簡單

    TOPDIR=./..
    
    include $(TOPDIR)/Makefile.env

    頂層目錄下的Makefile也很簡單,相對增加了exclude_dirs,排除不需要編譯的目錄

    TOPDIR=.
    
    exclude_dirs= include  bin  lib
    
    include $(TOPDIR)/Makefile.env

    現在只需要在頂層目錄下make一下,src下所有目錄都會編譯,生成的鏈接庫放在lib下,可執行文件在bin目錄中。如果要增加新的功能模塊,只要在src/目錄下新建目錄,增加一個類似first下的Makefile即可,是不是很方便?

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