上次分析到了这里:
CONTIKI_TARGET_DIRS_CONCAT = ${addprefix ${dir $(target_makefile)}, $(CONTIKI_TARGET_DIRS)}
CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, $(CONTIKI_CPU_DIRS)}
经分析CONTIKI_TARGET_DIRS_CONCAT的值为$(CONTIKI)/platform/cc2530dk/.dev
CONTIKI_CPU_DIRS_CONCAT的值为$(CONTIKI)/cpu/cc253x/. dev
SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \
$(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(APPDIRS) ${dir $(target_makefile)}
定义SOURCEFIRS值为. 表示当前目录,$(PROJECTDIRS),没找到这个变量的值,然后是$(CONTIKI)/platform/cc2530dk/.dev$(CONTIKI)/cpu/cc253x/. dev$(CONTIKI)/core/dev $(CONTIKI)/core/lib $(CONTIKI)/core/net .......
对于cc2530我们没有定义APPS 所以这里$(APPDIRS)为空 以及
$(CONTIKI)/platform/cc2530dk/
这个SOURCEFRS指定了需要被编译的所有源文件的目录
vpath %.c $(SOURCEDIRS)
vpath %.S $(SOURCEDIRS)
vpath关键字指定了makefile中出现某文件的搜索路径。在这里它指定了所有在Makefile文件中出现的以.c和.S为后缀的源文件的搜索路径为$(SOURCEDIRS) 。 这一步为我们后面的编译过程所用的模式规则做好准备。
CFLAGS += ${addprefix -I,$(SOURCEDIRS)}
指定了头文件的搜索路径,因为在很多源文件目录中有相应的头文件
RELSTR=${shell git describe --tags 2>/dev/null}
ifneq ($(RELSTR),)
CFLAGS += -DCONTIKI_VERSION_STRING=\"Contiki-$(RELSTR)\"
endif
这几行貌似有点多余 ,因为在contiki-version.h文件中已经指定了CONTIKI_VERSION_STRING为"Contiki 2.6"
ifneq ($(MAKECMDGOALS),clean)
-include ${addprefix $(OBJECTDIR)/,$(CONTIKI_SOURCEFILES:.c=.d) \
$(PROJECT_SOURCEFILES:.c=.d)}
endif
MAKECMDGOALS为make的环境变量,它会存放你所指定的终极目标的列表。那么上面几句表示如果执行的命令不是make clean 则包含include指定的makefile文件,这些文件是什么呢?obj_cc2530dk/....中以.d为后缀的文件
define FINALIZE_DEPENDENCY
cp $(@:.o=.d) $(@:.o=.$$$$); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.$$$$) >> $(@:.o=.d); \
rm -f $(@:.o=.$$$$)
endef
多行定义变量FINALIZE_DEPENDENCY,其值为下面三个命令。这三个命令具体是干啥的,下面用到的时候再说!
clean:
rm -f *~ *core core *.srec \
*.lst *.map \
*.cprg *.bin *.data contiki*.a *.firmware core-labels.S *.ihex *.ini \
*.ce *.co $(CLEAN)
-rm -rf $(OBJECTDIR)
clean伪目标用于删除所有编译链接产生的文件
下面都是一些编译源代码的一些规则。那么我们就从整个make执行的流程来看一下这个contiki系统是如何被编译,包括工程文件。
首先在工程目录中的makefile文件中找到终极目标为all,它依赖于 hello-world blink-hello timer-test sensors-demo
这四个文件,那么make就会去寻找第一个依赖文件的重建规则,hello-world,好像我们找了半天都没找到与它先关的规则,呵呵!那是因为在contiki系统中,所有重建过程都是用的模式规则,当然就看到以hello-world为目标的规则了!
我们按照make读取makefile文件的过程来分析,首先读取makefile.include,途中读取了makefile.cc2530dk,在此文件中也没发现与hello-world相关的规则,在makefile.cc2530dk文件中又引入了makefile.cc253x文件,在此文件中也没找到,那么make就回到makefile.include文件中继续寻找。返现在makefile.include文件的末尾有这两句:
%: %.c
注意这里的空行
%: %.$(TARGET)
@
单独一个%表示可以匹配任意字符,那么我们的目标hello-world当然可以匹配它了,所以就执行上面第一句。它的依赖文件为相应的hello-world.c文件,发现在工程目录中确实有这个文件,显然它比目标更新,所以执行下面语句!但是,居然为空命令,所以这一句相当于什么也不执行,但是make不服气啊?因为目标还没生成怎么就返回呢?所以继续找,那就是下面一个规则,它的依赖为hello-world.cc2530dk,那么这个文件显然在我们的目录中是没有的,所以make就去寻找建立它的规则。其实这里是多规则目标,一个hello-world对应两个规则,但是只能有一个规则有命令,其他的规则没有命令行,当要重建这个目标时,make会把它的依赖文件合并成一个依赖文件列表,然后执行那个有命令的规则!
为hello-world.cc2530dk找规则......
一个是在makefile.include中
ifndef CUSTOM_RULE_LINK
%.$(TARGET): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a
$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -o $@
endif
一个是在makefile.cc2530dk中
%.$(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)
那么我们执行哪个呢?显然make搜索是从头开始,那么按照makefile的读取顺序,当然是下面那个规则先执行,况且上面那个规则中还判断CUSTOM_RULE_LINK是否定义了,经查证,它定义了,那么上面那个规则对于cc2530dk来说永远不会执行!所以看下面那个规则。
它依赖于helloworld.hex文件,这个文件在目录中显示是不存在的,那么make就继续寻找建立它的规则。
在makefile.cc253x中又找到了两个,但是实际上有一个规则使用了条件判断的。(没有定义UIP_CONF_IPV6,且
HAVE_BANKING=0) 所以:
%.hex: %.ihx
$(PACKIHX) $< > $@
根据上面说的make工作原理,这样一直找下去,直到找到能生成目标的规则!!!这应该给大家提供了一种read makefile的思路吧!
先休整一下,得去看看sdcc的东西,因为接下来大多都是sdcc编译器编译链接的事了!且听下回分解!