目标文件生成的相互依赖关系
Makefile的最终目的是为了生成可执行的目标文件,所以makefile文件的最终是归结于一系列的更新目标文件 的命令,命令主要包含:系统命令(GCC、SDCC等),命令执行的选项,命令执行的源文件等等。
本微博我们从最终的目标文件入手来探究目标文件生成的相互依赖关系。
make命令执行后目标的匹配
当我们在终端中的命令行中输入make后,它会在工程目录下的makefile文件中找到终极目标为all,它依赖于 hello-world blink-hello timer-test sensors-demo这四个文件,那么make就会去寻找第一个依赖文件的重建规则,hello-world,好像我们找了半天都没找到与它先关的规则,呵呵!那是因为在contiki系统中,所有重建过程都是用的模式规则,当然就看到以hello-world为目标的规则了!
Makefile的目标重建是从Makefile.include文件中开始的,在Makefile.include文件的末尾有如下语句:
# Cancel the predefined implict rule for compiling and linking
# a single C source into a binary to force GNU make to consider
# the match-anything rule below instead.
%: %.c
单独的%表示可以匹配任意字符,目标hello-world当然可以匹配它了,它的依赖文件为相应的hello-world.c文件。命令行为空,未完成对目标的更新,则make继续寻找。
# Match-anything pattern rule to allow the project makefiles to
# abstract from the actual binary name. It needs to contain some
# command in order to be a rule, not just a prerequisite.
%: %.$(TARGET)
重新匹配到上面的规则,目标hello-world依赖于文件hello-world.CC2530dk,因为这个文件在我们的当前目录下不存在,make继续寻找见建立它的规则。
【注意】:此处一个目标hello-world对应有两个规则,但是只能有一个规则有命令,其他的规则没有命令行,当要重建这个目标时,make会把它的依赖文件合并成为一个依赖文件列表。然后执行那个有命令的规则。
为hello-world.cc2530dk找到的规则是:
(1)在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
(2)在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)
首先按照makefile的读取顺序,第(2)个规则应该优先执行,同时,第(1)个规则中的条件判断不成立。
hello-world.cc2530dk依赖于hello-world.hex文件,这个文件在当前目录下不存在,make则寻找建立它的规则。
makefile.cc253x文件中寻找到的相关的规则。
最终执行的有效命令为:
%.hex: %.ihx
$(PACKIHX) $< > $@
%.ihx: $(OBJECTDIR)/%.app.rel $(CONTIKI_TARGET_MAIN) contiki-$(TARGET).lib
$(CC) $(LDFLAGS) -o $@ $(CONTIKI_TARGET_MAIN) $(OBJECTDIR)/$*.app.rel -llibsdcc.lib -lcontiki-$(TARGET).lib > /dev/null
hello-world.hex文件依赖于hello-world.ihx文件,而hello-world.ihx文件依赖于三部分
1.obj_cc2530/hello-world.app.rel
2.contiki-main.rel(变量CONTIKI_TARGET_MAIN的定义在platform/Makefile.cc2530dk中)
3.contiki-cc2530dk.lib
这三个文件分别与应用application、系统contiki和库文件相关。
obj_cc2530/hello-world.app.rel
$(CC) $(call c_seg,$<,$@) -DAUTOSTART_ENABLE $(CFLAGS) -c $< -o $@
经过分析,SEGMENT_RULE_FILES 表示的是在某些目录中的segment.rules文件列表。找到相关的文件,有:
(1)cpu/cc253x/segment.rules
(2)platform/cc2530dk/segment.rules
而SEGMENT_RULES = $(OBJECTDIR)/segment.rules,再结合命令,我们可以确定本部分的意思是:
将SEGMENT_RULE_FILES文件列表中的文件作为sed命令的输入,调用sed命令处理后,将结果重新定向到 obj_cc2530dk/segment.rules文件中,这个文件不存在就创建它。
sed命令的含义:将segment.rules文件中不符合如下要求的字符行全部替换为空,或者是删除。
(1)以#开头的第二个字符的非换行符的任意行
(2)以任意空白符开头,后面接任意字符(或者没有)的行
(3)^匹配行首,两个$表示一个$符号,表示匹配行尾,则第三个表达式表示空白行
最终生成的segment.rules文件的内容如下:
HOME contiki-main.c
HOME button-sensor.c
HOME intr.c
HOME rtimer-arch.c
HOME clock.c
contiki-main.rel
$(OBJECTDIR)/%.rel: %.c $(SEGMENT_RULES)
$(CC) $(call c_seg,$<,$@) $(CFLAGS) -c $< -o $@ -Wp,-MMD,$(@:.rel=.d),-MQ,$@
@$(FINALIZE_SDCC_DEPENDENCY)
它的依赖文件有contiki-main.c和SEGMENT_RULES文件列表。两个文件均已得到更新,则直接调用后续的命 令完成对contiki-main.rel的更新。
contiki-cc2530dk.lib
contiki-$(TARGET).lib: $(CONTIKI_OBJECTFILES) $(PROJECT_OBJECTFILES) \
$(CONTIKI_ASMOBJECTFILES) $(CONTIKI_CASMOBJECTFILES)
rm -f $@
for target in $^; do echo $$target >> $@; done
这个文件对应的是一些相关的库文件。它的依赖文件都是编译过程的中间目标文件,都已经生成了,所以直接 执行后续的命令即可。
%.ihx: $(OBJECTDIR)/%.app.rel $(CONTIKI_TARGET_MAIN) contiki-$(TARGET).lib
$(CC) $(LDFLAGS) -o $@ $(CONTIKI_TARGET_MAIN) $(OBJECTDIR)/$*.app.rel -llibsdcc.lib -lcontiki-$(TARGET).lib > /dev/null
上面三个hello-world.ihx的依赖文件都生成后,我们就可以利用后续的命令对hello-world.ihx文件进行更新。
此命令主要包含以下部分:
(1)$(CC): cc2530平台使用的工具链是SDCC,根据工具链的不同,定义不同的变量。
(2)$(LDFLAGS): 编译选项
(3)-o $@:输出文件
(4)$(CONTIKI_TARGET_MAIN) :contiki工程系统的部分,main函数所在
(5)$(OBJECTDIR)/$*.app.rel:应用app相关的部分,已经被编译成中间文件.rel
(6)-llibsdcc.lib:通过-l选项添加sdcc的库
(7)-lcontiki-$(TARGET).lib 通过-l选项添加目标相关的库文件
(8)>/dev/null : 最终编译的输出信息定向到/dev/null中。
至此我们便生成了最终的hello-world.hex文件。