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这个为空的伪目标呢?可能后面会用到。
下面的命令行解释起来相当的枯燥,先搁起来,等后面再解释。
至此分析了大致一半,后续解读请见下文分解!