概述
makefile.include文件,这个是在contiki系统根目录中,而非工程目录,在contiki源码中有很多工程,在example目录里面,每一个目录对应一个工程,比如cc2530dk目录中就对应的是cc2530平台的工程,记住有makefile文件的当前目录才是工程目录,所以makefile.include的当前目录就不是工程目录。
本文将从makefile.include开始解读,一步一步深入包含contiki操作系统的工程的编译过程(以cc2530dk为例)。其中会涉及到makefile和shell相关知识,我会一一解释清楚。先打开example/cc2530dk/makfile文件
- CONTIKI_PROJECT = hello-world blink-hello timer-test sensors-demo
-
- all: $(CONTIKI_PROJECT)
-
- CONTIKI = ../..
- include $(CONTIKI)/Makefile.include
CONTIKI_PROJECT变量定义的是最后生成的目标文件,即可执行文件,这里生成了四个可执行文件,为什么要这么做呢?因为通常来讲makefile只能生成一个终极目标,这里用到了all伪目标(没有命令行的规则,或者没有规则的命令),即all依赖于以上四个可执行的文件。如果不这样做的话,即没有用all伪目标,则最终只能生成一个可执行文件hello-world 或 blin-hello.第三句定义变量CONTIKI 为上级目录的上级目录,即为contiki的根目录,因为要用下面一句 include $(CONTIKI)/Makefile.include 包含根目录里面的makefile.include ,此时make就会停止读取当前的Makefile,转而去读Makefile.include, Makefile.include,内容较多,我们逐步来解析。
这里ifndef是用来判断一个变量是否已经定义,因为之前定义了CONTIKI,所以不会执行,即不会报错!
- ifeq ($(TARGET),)
- -include Makefile.target
- ifeq ($(TARGET),)
- ${info TARGET not defined, using target 'native'}
- TARGET=native
- else
- ${info using saved target '$(TARGET)'}
- endif
- endif
ifeq是用来判断两个参数是否相等,如果相等,则往下执行。因为之前没有的定义TARGET变量,所以其为空,即条件判断为真,往下执行...包含Makefile.target,记住此时还是在makefile的当前目录中工作,而不是转到根目录了。所以会在工程目录里面包含Makefile.target文件,我们找到打开它:
TARGET = cc2530dk 只有这一句就是定义TARGET变量为cc2530dk继续上面的第二个ifeq,此时TARGET变量不为空了,所以下面一句不会执行,而执行else语句info为一个显示信息的工具,显示using saved target cc2530dk
- ifeq ($(DEFINES),)
- -include Makefile.$(TARGET).defines
- ifneq ($(DEFINES),)
- ${info using saved defines '$(DEFINES)'}
- endif
- endif
这几句和上面的意思一样,只不过换成DEFINES变量,工程目录中没有Makefile.cc2530dk.defines文件,所以DEFINES仍为空,所以ifneq条件判断为假,所以什么也不执行。
- ifndef HOST_OS
- ifeq ($(OS),Windows_NT)
- ## TODO: detect more specific Windows set-ups,
- ## e.g. CygWin, MingW, VisualC, Watcom, Interix
- HOST_OS := Windows
- else
- HOST_OS := $(shell uname)
- endif
- endif
这几句就不用解释了,提一下$(shell uname)值为Linux,所以HOST_OS要么为Windows,要么为Linux。
- usage:
- @echo "make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets]"
-
- targets:
- @ls -1 $(CONTIKI)/platform $(TARGETDIRS) | grep -v CVS
-
- savetarget:
- -@rm -f Makefile.target
- @echo "saving Makefile.target"
- @echo >Makefile.target "TARGET = $(TARGET)"
-
- savedefines:
- -@rm -f Makefile.$(TARGET).defines
- @echo "saving Makefile.$(TARGET).defines"
- @echo >Makefile.$(TARGET).defines "DEFINES = $(DEFINES)"
这一句是将usage作为伪目标,如果执行make的时候,指定了终极目标为usage,即make usage,则回显
make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets],这句是指导我们怎么用make命令来编译contiki源码。记住echo前要加@,要不然会显示echo"make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets]"。
这句同样以targets为终极目标时,将会列出contiki/platform目录下的所有文件(TARGETDIRS变量此时为空),
grep -v CVS 是显示所有不包含CVS的行,这里还没弄清楚CVS是啥意思!我们不用管,例如我们执行
make targets 则出现
- apple2enh
- atari
- avr-atmega128rfa1
- avr-raven
- avr-ravenlcd
- avr-ravenusb
- avr-rcb
- avr-zigbit
- c128
- c64
- cc2530dk
- cc2538dk
- cooja
- econotag
- esb
- ...
这里也是将savetarget作为终极目标,第一句是强制删除Makefile.target文件,然后回显saving Makefile.target,这里提一下在@rm前面的'-',它的作用就是如果这条命令执行失败的话,make工作照常进行,即往下执行。
然后将TARGET=cc2530dk重定向到Makefile.target文件中,这里将>Makefile.target放在"TARGET = $(TARGET)"的后面也可以,这里面有一个问题就是,当我执行这个命令的时候,会提示权限不够,只有进入了root,才会顺利执行这个命令,但是当我们执行make命令的时候,权限为普通用户,那么如果执行savetarget怎么会执行第三句呢?
那么以savetarget为终极目标有啥用呢?答案在 根目录中的README-BUILDING文件
- OBJECTDIR = obj_$(TARGET)
定义变量OBJECTDIR为obj_cc2530dk
- LOWERCASE = -abcdefghijklmnopqrstuvwxyz
- UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ
- TARGET_UPPERCASE := ${strip ${shell echo $(TARGET) | sed y!$(LOWERCASE)!$(UPPERCASE)!}}
- CFLAGS += -DCONTIKI=1 -DCONTIKI_TARGET_$(TARGET_UPPERCASE)=1
首先定义了LOWERCASE和UPPERCASE变量,第三局看起来有点复杂,我们从最里面一层一层往外剥,首先看sed命令,可以去这个博客看sed的用法http://lsscto.blog.51cto.com/779396/880538,!为分隔符(/ ,也可以) ,y表示转换资料中的字元,即将echo显示的内容作为sed的输入或资料进行转换,将其中的小写字母转换成大写字母,即将cc2530dk转换成CC2530DK,然后作为shell的返回值提供给strip,strip是make的内置函数,其作用是去掉该字串中开头和结尾的空格符,并将中间多个连续空字符合并为一个空字符。则最终TARGET_UPPERCASE变量的值为CC2530DK。第四句追加变量CFLAGS,此为c编译器的命令行选项变量,定义了CONTIKI=1 CONTIKI_TARGET_CC2530DK=1
- 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
- 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
- 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)
这几句定义了几个和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
进入到Makefile.include刚才那两句include的下面,定义了几个变量分别表示contiki系统中不同部分的源文件列表,如SYSTEM表示contiki 内核进程调度等的源文件列表。
- include $(CONTIKI)/core/net/Makefile.uip
- include $(CONTIKI)/core/net/rpl/Makefile.rpl
-
- CTK = ctk.c
- CTKVNC = $(CTK) ctk-vncserver.c libconio.c vnc-server.c vnc-out.c ctk-vncfont.c
- ifndef CONTIKI_NO_NET
- CONTIKIFILES = $(SYSTEM) $(LIBS) $(NET) $(THREADS) $(DHCP) $(DEV)
- else
- CONTIKIFILES = $(SYSTEM) $(LIBS) $(THREADS) $(DEV) sicslowpan.c fakeuip.c
- endif
-
- CONTIKI_SOURCEFILES += $(CONTIKIFILES)
- CONTIKIDIRS += ${addprefix $(CONTIKI)/core/,dev lib net net/mac net/rime
- net/rpl sys cfs ctk lib/ctk loader . }
- oname = ${patsubst %.c,%.o,${patsubst %.S,%.o,$(1)}}
-
- CONTIKI_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CONTIKI_SOURCEFILES)}}
-
- PROJECT_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(PROJECT_SOURCEFILES)}}
- ifdef APPS
- APPDS = ${wildcard ${foreach DIR, $(APPDIRS), ${addprefix $(DIR)/, $(APPS)}}}
- ${wildcard ${addprefix $(CONTIKI)/apps/, $(APPS)}
- ${addprefix $(CONTIKI)/platform/$(TARGET)/apps/, $(APPS)}
- $(APPS)}
- APPINCLUDES = ${foreach APP, $(APPS), ${wildcard ${foreach DIR, $(APPDS), $(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
- target_makefile := $(wildcard $(CONTIKI)/platform/$(TARGET)/Makefile.$(TARGET) ${foreach TDIR, $(TARGETDIRS), $(TDIR)/$(TARGET)/Makefile.$(TARGET)})
-
- ifeq ($(strip $(target_makefile)),)
${error The target platform "$(TARGET)" does not exist (maybe it was misspelled?)}
else
ifeq (${wildcard $(OBJECTDIR)},)
DUMMY := ${shell mkdir $(OBJECTDIR)}
endif
ifneq (1, ${words $(target_makefile)})
${error More than one TARGET Makefile found: $(target_makefile)}
endif
include $(target_makefile)
endif
最后
以上就是粗暴蛋挞为你收集整理的Contiki Makefile 详细解读的全部内容,希望文章能够帮你解决Contiki Makefile 详细解读所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复