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文件裏面去看看,一看就明白了,我把最終定向生成的文件給大家看看

    

看到了吧 就只剩下幾個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的知識,之前都是對它一知半解的,現在明朗多了!如果這中間有什麼問題,或分析的有錯,還請不吝指正!

 


 

 

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