contiki2.6之Makefile詳細解讀二

繼續contiki2.6中makefile講解

include $(CONTIKI)/core/net/rime/Makefile.rime
include $(CONTIKI)/core/net/mac/Makefile.mac
SYSTEM  = process.c procinit.c autostart.c elfloader.c profile.c \
          timetable.c timetable-aggregate.c compower.c serial-line.c
THREADS = mt.c
LIBS    = memb.c mmem.c timer.c list.c etimer.c ctimer.c energest.c rtimer.c stimer.c \
          print-stats.c ifft.c crc16.c random.c checkpoint.c ringbuf.c
DEV     = nullradio.c
NET     = netstack.c uip-debug.c packetbuf.c queuebuf.c packetqueue.c

包含Makefile.rime,我們看一下這個文件下內容

ifdef UIP_CONF_IPV6
#RIME_UIP6      = rime-udp.c
RIME_BASE      = rimeaddr.c timesynch.c rimestats.c
else
RIME_CHAMELEON = chameleon.c channel.c chameleon-raw.c chameleon-bitopt.c
RIME_BASE      = rimeaddr.c rime.c timesynch.c \
                 rimestats.c announcement.c polite-announcement.c \
                 broadcast-announcement.c
RIME_SINGLEHOP = broadcast.c stbroadcast.c unicast.c stunicast.c \
                 runicast.c abc.c \
                 rucb.c polite.c ipolite.c
RIME_MULTIHOP  = netflood.c multihop.c rmh.c trickle.c
RIME_MESH      = mesh.c route.c route-discovery.c
RIME_COLLECT   = collect.c collect-neighbor.c neighbor-discovery.c \
   collect-link-estimate.c
RIME_RUDOLPH   = rudolph0.c rudolph1.c rudolph2.c
endif # UIP_CONF_IPV6

CONTIKI_SOURCEFILES += $(RIME_BASE) \
               $(RIME_SINGLEHOP) \
               $(RIME_MULTIHOP) \
               $(RIME_MESH) \
               $(RIME_COLLECT) \
               $(RIME_RUDOLPH) \
               $(RIME_CHAMELEON) \
               $(RIME_UIP6)

如果定義了UIP_CONF_IPV6這個變量定義了 ,則往下執行,#後面爲註釋,因爲UIP_CONF_IPV6這個變量沒有定義,所以執行else下面的語句

這幾句定義了幾個和rime協議棧相關的變量,這些變量爲相應的源文件列表。

最後追加CONTIKI_SOURCEFILES變量,將以上定義的變量引用到此變量中,注意其中RIME_UIP6爲空。

 

打開Makefile.mac

CONTIKI_SOURCEFILES += cxmac.c xmac.c nullmac.c lpp.c frame802154.c sicslowmac.c nullrdc.c nullrdc-                             noframer.c mac.c
CONTIKI_SOURCEFILES += framer-nullmac.c framer-802154.c csma.c contikimac.c phase.c

 

這兩句追加CONTIKI_SOURCEFILES變量,將mac層相關的源文件添加到將要編譯的源文件列表中。注意此源文件列表中不包含Tdma_mac.c 和Ctdma_mac.c。

 

進入到Makefile.include剛纔那兩句include的下面

定義了幾個變量分別表示contiki系統中不同部分的源文件列表,如SYSTEM表示contiki 內核進程調度等 的源文件列表。

 

ifdef UIP_CONF_IPV6
  CFLAGS += -DUIP_CONF_IPV6=1
  UIP   = uip6.c tcpip.c psock.c uip-udp-packet.c uip-split.c \
          resolv.c tcpdump.c uiplib.c simple-udp.c
  NET   += $(UIP) uip-icmp6.c uip-nd6.c uip-packetqueue.c \
          sicslowpan.c neighbor-attr.c neighbor-info.c uip-ds6.c
  ifneq ($(UIP_CONF_RPL),0)
    CFLAGS += -DUIP_CONF_IPV6_RPL=1
    include $(CONTIKI)/core/net/rpl/Makefile.rpl
  endif # UIP_CONF_RPL
else # UIP_CONF_IPV6
  UIP   = uip.c uiplib.c resolv.c tcpip.c psock.c hc.c uip-split.c uip-fw.c \
          uip-fw-drv.c uip_arp.c tcpdump.c uip-neighbor.c uip-udp-packet.c \
          uip-over-mesh.c dhcpc.c simple-udp.c
  NET   += $(UIP) uaodv.c uaodv-rt.c
endif # UIP_CONF_IPV6

如果定義了UIP_CONF_IPV6變量,則往下執行,但是到現在我們任然沒有定義它,所以不得不執行else後面的

定義UIP和追加NET變量

 

CTK     = ctk.c
CTKVNC  = $(CTK) ctk-vncserver.c libconio.c vnc-server.c vnc-out.c ctk-vncfont.c

ctk爲contiki的GUI和VNC功能

 

ifndef CONTIKI_NO_NET
  CONTIKIFILES = $(SYSTEM) $(LIBS) $(NET) $(THREADS) $(DHCP) $(DEV)
else
  CONTIKIFILES = $(SYSTEM) $(LIBS) $(THREADS) $(DEV) sicslowpan.c fakeuip.c
endif

沒有定義CONTIKI_NO_NET,所以定義CONTIKIFILES變量,其中NET相關的源文件,如果定義了此變量,則不包含與NET相關的源文件

 

CONTIKI_SOURCEFILES += $(CONTIKIFILES)

將CONTIKIFILES變量的內容添加到CONTIKI_SOURCEFILES變量中。自此我們知道了CONTIKI_SOURCEFILES變量中包含的源文件,這些都是需要編譯連接的。

 

CONTIKIDIRS += ${addprefix $(CONTIKI)/core/,dev lib net net/mac net/rime \
                 net/rpl sys cfs ctk lib/ctk loader . }

這裏追加CONTIKIDIRS變量,看字面意思就知道這個變量代表contiki的目錄列表

addprefx爲make的內置函數,這個函數完成的功能是爲後面每一個文件名添加前綴$(CONTIKI)/core/,那麼CONTIKIDORS最終的值爲$(CONTIKI)/core/dev $(CONTIKI)/core/lib $(CONTIKI)/core/net .......這些是contiki內核的源文件目錄列表。

 

oname = ${patsubst %.c,%.o,${patsubst %.S,%.o,$(1)}}

這個是自定義函數,那麼這個函數的作用是什麼呢?patsubst是make內置函數,它的功能是替換字符串中符合%.S模式的單詞替換成%.o模式,返回的值是替換後的新字符串;繼續調用patsubst,將符合%.c模式的單詞替換成%.o模式的單詞,最終返回替換後的新字符串。那麼這個函數的功能就不言而喻了,它實現的是將位置變量$(1)所代表的字符串中凡是符合%.S %.c模式的單詞都替換成%.c模式,然後返回替換後的新字符串。這裏$(1)表示的就是此函數的第一個參數值,如下面的調用中表示的就是$(CONTIKI_SOURCEFILES)

 

CONTIKI_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CONTIKI_SOURCEFILES)}}

知道了oname函數的功能,這句就很好理解了。用call調用oname函數,將CONTIKI_SOURCEFILES代表的所有源文件列表中.c或.S後綴結尾的文件名全部替換成.o結尾的文件名,然後返回;再調用addprefix函數,添加前綴$(OBJECTDIR),OBJECTDIR這個變量的值爲obj_cc2530dk,則在所有文件前面中添加前綴obj_cc2530dk,比如某一個源文件爲rime.c,執行此語句後變成obj_cc2530_rime.o,這是目標文件。

那麼CONTIKI_OBJECTFILES就是代表所有contiki中源文件在經過編譯之後生成的目標文件列表。

 

PROJECT_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(PROJECT_SOURCEFILES)}}

這一句和上面一句實現功能類似,但是我沒有找到PROJECT_SOURCEFILES的定義,那麼我可不可以理解爲這一句什麼也沒執行。這個變量代表的是工程目錄中的源文件編譯之後生成的目標文件列表。

 

### Include application makefiles

ifdef APPS
  APPDIRS += ${wildcard ${addprefix $(CONTIKI)/apps/, $(APPS)} \
      ${addprefix $(CONTIKI)/platform/$(TARGET)/apps/, $(APPS)} \
      $(APPS)}
  APPINCLUDES = ${foreach APP, $(APPS), ${wildcard ${foreach DIR, $(APPDIRS), $(DIR)/Makefile.$(APP)}}}
  -include $(APPINCLUDES)
  APP_SOURCES = ${foreach APP, $(APPS), $($(APP)_src)}
  DSC_SOURCES = ${foreach APP, $(APPS), $($(APP)_dsc)}
  CONTIKI_SOURCEFILES += $(APP_SOURCES) $(DSC_SOURCES)
endif

包含應用程序的makefile文件

如果定義了APPS,則包含,沒有就不包含,在cc2530中我們沒有定義這個變量,所以就不包含應用程序目錄中的文件。那麼在其他的平臺如sky中的某一個工程,會定義APPS,此時定義APPDIRS變量。假如APPS 爲telnet (apps目錄中的某一個目錄文件),則用wildcard函數找出與此APPS相關的一些目錄列表,wilcard後面的參數代表是的是一種模式,它是在當前目錄中搜索符合這種模式的文件,並返回這種模式的文件名列表。注意這裏在當前目錄中搜索,包括目錄的子目錄,子目錄的子目錄等。

然後定義APPINCLUDES 包含apps源文件的頭文件列表

APP_SOURCES 代表apps的源文件列表  DSC_SOURCES不知道

追加CONTIKI_SOURCEFILES變量 將上面兩個變量所代表的源文件列表添加進來。

 

 

target_makefile := $(wildcard $(CONTIKI)/platform/$(TARGET)/Makefile.$(TARGET)

在當前目錄中搜索符合上述模式的文件。即搜索文件$(CONTIKI)/platform/cc2530dk/Makefile.cc2530dk,那我們找找看!我們找到了確實有這個文件打開它看看:

這是和cc2530dk平臺相關的makefile

ifndef CONTIKI
  $(error CONTIKI not defined! You must specify where CONTIKI resides!)
endif

我們定義了CONTIKI所以跳過此句。

CONTIKI_TARGET_DIRS = . dev
CONTIKI_TARGET_MAIN = $(addprefix $(OBJECTDIR)/,contiki-main.rel)

定義兩個變量CONTIKI_TARGET_MAIN值爲obj_cc2530dk/contiki-main.rel

 

CONTIKI_TARGET_SOURCEFILES = contiki-main.c
CONTIKI_TARGET_SOURCEFILES += leds.c leds-arch.c
CONTIKI_TARGET_SOURCEFILES += sensors.c smartrf-sensors.c
CONTIKI_TARGET_SOURCEFILES += button-sensor.c adc-sensor.c
CONTIKI_TARGET_SOURCEFILES += serial-line.c slip-arch.c slip.c
CONTIKI_TARGET_SOURCEFILES += putchar.c debug.c

添加和平臺相關的源文件到CONTIKI_TARGET_SOURCEFILES變量中。

 

CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES)

將上面源文件列表添加到CONTIKI_SOURCEFILES中,這裏面的源文件纔是最終要進行編譯的文件。

 

CLEAN += *.cc2530dk

定義CLEAN變量爲*.cc2530dk

 

ifdef UIP_CONF_IPV6
  CONTIKI_TARGET_SOURCEFILES += viztool.c
endif

如果定義了UIP_CONF_IPV6 則將viztool.c添加進CONTIKI_TARGET_SOURCEFILS中(這兩句是不是要放到CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES)這一句前面???)

 

FORCE: 

 

定義了一個空的僞目標 作爲一個標籤。別忘了命令行爲空,得空一行出來,這裏我們想一下爲什麼要弄一個僞目標呢?想想!我覺得這是爲了防止下面規則中的目標文件在當前目錄中已經存在而導致命令沒有被執行,比如hello-world.cc2530dk這個文件已經存在,且相應的hello-world.cc2530dk也存在,那麼當有源文件修改的話,此時如果沒有FORCE這個標籤的話,那麼下面一條規則的命令就不會執行,而如果有了這個僞目標FORCE,那麼每次執行這個空命令時,make總是認爲它是更新過的了,所以下面一條規則它總是執行的。

 

%.$(TARGET): %.hex FORCE
 cp $< $(<:.hex=.$(TARGET))
 @echo "\nReport"
 @echo "==============="
 @echo 'Code footprint:'
 @echo    'Area                                Addr        Size' \
          '         Decimal'
 @echo    '----------------------------------  --------    --------' \
          '     --------'
 @echo -n 'HOME,CSEG,CONST,XINIT,GS*           $(HOME_START)    '
 @egrep ',CODE\)' $(<:.hex=.map) | egrep -v '(^BANK[1-9][^=])' | uniq | \
 awk '{ SUM += $$5 } END { printf "%08X =    %8d", SUM, SUM }'
 @echo '. bytes (REL,CON,CODE)'
 @egrep '(^BANK[1-9][^=])' $(<:.hex=.map) | uniq | sort
 @egrep -A 5 'Other memory' $(<:.hex=.mem)

這裏略微複雜哈,但是不急,聽我細細道來!

%.$(TARGET): %.hex FORCE 這一句涉及到make執行的規則。%.$(TARGET)依賴於%.hex,此時%.hex並不存在,所以我們要用它的描述規則去創建它,(依賴永遠要比目標新),所以此時make會尋找%.hex爲目標的規則,找到它之後執行規則後面的命令,然後生成%.hex文件,然後再回來這一行來。FORCE 爲依賴,因爲前面已經執行了FORCE規則,則會生成“FORCE文件”,這裏打個引號是因爲它是不存在,此時相當於什麼也不做,而去執行下面的命令行。這裏爲什麼要用FORCE這個爲空的僞目標呢?可能後面會用到。

下面的命令行解釋起來相當的枯燥,先擱起來,等後面再解釋。

     至此分析了大致一半,後續解讀請見下文分解!

 


 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章