[置顶] contiki2.6之Makefile详细解读五

     继续上篇未完的内容。

%.hex: %.ihx
     $(PACKIHX) $< > $@

这里我们寻找依赖文件hello-world.ihx的建立规则,

%.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

继续寻找obj_cc2530/hello-world.app.rel 的建立规则

$(OBJECTDIR)/%.app.rel: %.c $(SEGMENT_RULES)
        $(CC) $(call c_seg,$<,$@) -DAUTOSTART_ENABLE $(CFLAGS) -c $< -o $@

依赖文件hello-world.c文件已经存在,所以寻找SEGMENT_RULES变量所代替的文件的重建规则。


SEGMENT_RULE_FILES = $(foreach dir, . $(CONTIKI_PLATFORM_DIRS) \
         $(CONTIKI_CPU_DIRS_LIST), $(wildcard $(dir)/segment.rules) )

$(SEGMENT_RULES): $(SEGMENT_RULE_FILES)
         cat $(SEGMENT_RULE_FILES) | \
             sed -e 's/#.*$$//' -e 's/^\s*//' -e '/^$$/d' > $@

经过分析我们知道SEGMENT_RULE_FILES表示的在某些目录中的segment.rules文件列表

好!我们找到了这个文件,分别是cpu/cc253x/segment.rules platform/cc2530dk/segment.rules

既然找到了,而且肯定比目标新,那么就执行命令。这里用到了管道,将这些segment.ruls的内容最为sed的输入调用sed命令,让后将其重定向到目标文件obj_cc2530dk/segment.rules中,这个文件不存在,那么就创建它。

这个sed命令有点烦,因为它用到了正则表达式,-e选项表示后面跟的是正则表达式。s为替换命令,我大致说一下意思,就是将segment.rules文件中不符合它要求的字符行全部替换为空,或者删除。这些不符合要求的行为

1、以#开头的第二个字符非换行符的任意行

2、以任意空白符开头,后面接任意字符(或者没有)的行

3、这里知道^为匹配行首,两个$表示一个$符号,表示匹配行尾,那么就是空白行

其实我们可以去segment.rules文件里面去看看,一看就明白了,我把最终定向生成的文件给大家看看

     [置顶] contiki2.6之Makefile详细解读五_第1张图片

看到了吧 就只剩下几个segment的语句了。这几句表示什么意思,我们可以不用管!这是编译器的事!

$(OBJECTDIR)/%.app.rel: %.c $(SEGMENT_RULES)
        $(CC) $(call c_seg,$<,$@) -DAUTOSTART_ENABLE $(CFLAGS) -c $< -o $@

既然生成了$(SEGMENT_RULES)即obj_cc2530dk/segment.rules,hello-world.c文件也存在,那么执行下面这个命令,这里才真正用到了sdcc编译器的编译命令,调用了c_seg函数,这里我找到了它的定义
ifeq ($(HAVE_BANKING),1)
  ## Yes
  MEMORY_MODEL=huge
  LDFLAGS += -Wl-r
  LD_PRE_FLAGS += -Wl-bBANK1=0x018000
  CFLAGS += -DHAVE_SDCC_BANKING
  #use this in $(call c_seg,$<) to get segment for a source file.
  c_seg = --codeseg $(shell python $(BANK_ALLOC) $1 $(SEGMENT_RULES) $2)
else
  ## No banking
  MEMORY_MODEL=large
  c_seg =
endif

显然这里c_seg为空,因为HAVE_BANKING定义为0

所以sdcc的第一个参数为空,-DAUTOSTART_ENABLE,定义宏DAUTOSTART_ENABLE,然后编译.app.rel后缀的文件。这里相当于生成里hello-world.app.rel文件。好,我们继续回溯,

%.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

第一个依赖文件生成了,第二个依赖文件是obj_cc2530dk/contiki-main.rel(以.rel结尾的文件都是sdcc编译产生的目标文件,相当c编译器的.o文件),这个文件有吗?貌似现在还没有吧

那么我们得找这个文件的生成规则,找到了一个模式规则;

$(OBJECTDIR)/%.rel: %.c $(SEGMENT_RULES)
           $(CC) $(call c_seg,$<,$@) $(CFLAGS) -c $< -o $@ -Wp,-MMD,$(@:.rel=.d),-MQ,$@
           @$(FINALIZE_SDCC_DEPENDENCY)

它的依赖文件为contiki-main.c文件,我们在platform/cc2530dk目录下找到了这个文件,那么继续找第二个依赖文件,显然在上面已经生成了,所以调用下面的命令,这里的sdcc命令添加了几个预处理的选项-Wp,-MMD,$(@:.rel=.d),-MQ,$@这几个什么意思我们可以不用管它!

接着执行下面命令这是一个多行定义的变量

define FINALIZE_SDCC_DEPENDENCY
cp $(@:.rel=.d) $(@:.rel=.$$$$); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
    -e '/^$$/ d' -e 's/$$/ :/' < $(@:.rel=.$$$$) >> $(@:.rel=.d); \
rm -f $(@:.rel=.$$$$)
endef

我大致说下它的意思先将目标文件名替换成obj_cc2530dk/contiki-main.d,然后复制它,并以obj_cc2530dk/contiki-main.$$$$名字替换复制之后的文件名,然后以该目标文件为输入,重定向到sed命令中,然后再将sed的执行结果输出到obj_cc2530dk/contiki-main.d文件中,最后删除obj_cc2530dk/contiki-main.$$$$

好,我们现在生成了obj_cc2530dk/contiki-main.rel文件,回到这里:

%.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

看一下第三个依赖文件,继续在makefile中找相关的模式匹配

contiki-$(TARGET).lib: $(CONTIKI_OBJECTFILES) $(PROJECT_OBJECTFILES) \
      $(CONTIKI_ASMOBJECTFILES) $(CONTIKI_CASMOBJECTFILES)
         rm -f $@
         for target in $^; do echo $$target >> $@; done

它依赖文件显然已经都生成了,因为这些都是我们编译生成的中间目标文件,所以直接执行下面的命令

开始强制删除目标文件,为什么呢?因为等哈我们要生成这个文件,所以先删除旧的文件。

下面执行一个for循环,将规则中的所有依赖文件一次赋值给target,然后将其追加输出到目标文件中。我们可以make整个工程之后查看contiki-cc2530dk.lib文件,里面都是一些目标文件

现在生成了contiki-cc2530dk.lib文件,我们又回到了

%.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

 

貌似好几次了。好,这三个依赖文件都生成了,那么开始执行命令。这个命令没得话说,命令的用法跟gcc差不多,将最终编译输出的信息定向到/dev/null中。

好,产生了hello-world.ihx文件,这个文件对有的cpu,它是可执行文件,但是对于我们cc2530来说还不是,所以还得将其转换成.hex文件。回到

%.hex: %.ihx
 $(PACKIHX) $< > $@

这个命令packihx将其转换,我猜也只不过是一些头信息的转换。至此我们的hello-world.hex文件生成了,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)

我们的目标是hello-world.cc2530dk,依赖文件已经生成了,那么就执行下面命令,大概就是显示一些编译生成.hex文件中各个存储区的大小,这里我们不用关注。生成了hello-world.cc2530dk之后再回溯到Makefile.include文件中的

%: %.$(TARGET)
   @

依赖文件生成了,那么执行命令,这里光一个@符号表示什么呢,我们姑且当做是执行一个空命令,执行完之后生成helloworld文件,这是文件吗,实际上着只是一个伪目标,是不存在的!那么我们在目录中当然就找不到这个文件了。然后回到最开始的Makefile文件中

all: $(CONTIKI_PROJECT)


对于另外blink-hello timer-test sensors-demo其make 的流程跟hello-world一样的,也生成了几个相应的hex文件。

最终构建终极目标,但是是伪目标,make并不产生这个文件。至此整个make的工作结束!

 

     我们以cc2530dk的平台为例,将cc2530的工程编译过程走了一遍,哪些地方需要添加我们自己定义的文件很一目了然了!那么我们在写自己的工程的时候,添加什么文件,其文件名是什么,这些都清楚了。

   这五篇讲解makefile的过程,我自己也学到不少make的知识,之前都是对它一知半解的,现在明朗多了!如果这中间有什么问题,或分析的有错,还请不吝指正!

 


 

 

你可能感兴趣的:(makefile,CC2530,contiki2.6)