本帖最后由 城东 于 2016-12-6 22:33 编辑
~/Share/SDK/makefile的内容请看上文:
https://bbs.elecfans.com/jishu_1098812_1_1.html
上面提到:make之后首先运行~/Share/SDK/et_app/makefile,而在这个makefile中包含了~/Share/SDK/makefile,所以这里就来分析这个makefile,如下:
ifndef PDIR
endif
ifeq ($(COMPILE), xcc)
AR = xt-ar
CC = xt-xcc
NM = xt-nm
CPP = xt-xt++
OBJCOPY = xt-objcopy
OBJDUMP = xt-objdump
else
AR = xtensa-lx106-elf-ar #创建静态库的工具
CC = xtensa-lx106-elf-gcc #C语言编译工具
NM = xtensa-lx106-elf-nm #用来列出目标文件的符号清单。Makefile中将产生的目标文件的符号清单列出工具
CPP = xtensa-lx106-elf-g++ #C++语言编译器
OBJCOPY = xtensa-lx106-elf-objcopy #格式转换工具
OBJDUMP = xtensa-lx106-elf-objdump #显示二进制文件信息,查看反汇编代码工具
endif
这里PDIR作为父目录变量没有定义,下面的工作就是定义编译器等等具体工具工具说明:
ar:http://blog.chinaunix.net/uid-25909722-id-3080444.html
NM:http://www.aiuxian.com/ar
ticle/p-2137584.html
这些工具在下面有用到。
下来对一些主要变量进行判断处理:
BOOT?=none
APP?=0
SPI_SPEED?=40
SPI_MODE?=QIO
SPI_SIZE_MAP?=0
其中?= 是如果没有被赋值过就赋予等号后面的值
这些变量在前面的说明中的~/Share/SDK/et_app/gen_misc.sh脚本中定义
下面的内容是根据调用make传进来的变量再次进行变量的定义:
ifeq ($(BOOT), new)
boot = new
else
ifeq ($(BOOT), old)
boot = old
else
boot = none
endif
endif
ifeq ($(APP), 1)
app = 1
else
ifeq ($(APP), 2)
app = 2
else
app = 0
endif
endif
ifeq ($(SPI_SPEED), 26.7)
freqdiv = 1
else
ifeq ($(SPI_SPEED), 20)
freqdiv = 2
else
ifeq ($(SPI_SPEED), 80)
freqdiv = 15
else
freqdiv = 0
endif
endif
endif
ifeq ($(SPI_MODE), QOUT)
mode = 1
else
ifeq ($(SPI_MODE), DIO)
mode = 2
else
ifeq ($(SPI_MODE), DOUT)
mode = 3
else
mode = 0
endif
endif
endif
addr = 0x01000
ifeq ($(SPI_SIZE_MAP), 1)
size_map = 1
flash = 256
else
ifeq ($(SPI_SIZE_MAP), 2)
size_map = 2
flash = 1024
ifeq ($(app), 2)
addr = 0x81000
endif
else
ifeq ($(SPI_SIZE_MAP), 3)
size_map = 3
flash = 2048
ifeq ($(app), 2)
addr = 0x81000
endif
else
ifeq ($(SPI_SIZE_MAP), 4)
size_map = 4
flash = 4096
ifeq ($(app), 2)
addr = 0x81000
endif
else
ifeq ($(SPI_SIZE_MAP), 5)
size_map = 5
flash = 2048
ifeq ($(app), 2)
addr = 0x101000
endif
else
ifeq ($(SPI_SIZE_MAP), 6)
size_map = 6
flash = 4096
ifeq ($(app), 2)
addr = 0x101000
endif
else
size_map = 0
flash = 512
ifeq ($(app), 2)
addr = 0x41000
endif
endif
endif
endif
endif
endif
endif
这里我们可以总结如下:
boot = new
app = 1
freqdiv = 0
mode = 0
size_map = 3
flash = 2048
addr = 0x01000
这里的变量应该是十分有用的变量,值得收藏
下面的内容是:
LD_FILE = $(LDDIR)/eagle.app.v6.ld
ifneq ($(boot), none)
ifneq ($(app),0)
ifeq ($(size_map), 6)
LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).2048.ld
else
ifeq ($(size_map), 5)
LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).2048.ld
else
ifeq ($(size_map), 4)
LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).1024.app$(app).ld
else
ifeq ($(size_map), 3)
LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).1024.app$(app).ld
else
ifeq ($(size_map), 2)
LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).1024.app$(app).ld
else
ifeq ($(size_map), 0)
LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).512.app$(app).ld
endif
endif
endif
endif
endif
endif
BIN_NAME = user$(app).$(flash).$(boot).$(size_map)
endif
else
app = 0
endif
这里主要的目的就是定义BIN_NAME,从前面的定义到这里我们可以推出:
LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).1024.app$(app).ld也就是说
LD_FILE = ~/Share/SDK/ld/eagle.app.v6.new.1024.app1.ld
BIN_NAME = user$(app).$(flash).$(boot).$(size_map)也就是说BIN_NAME = user1.2048.new.3
这也是最终生成的bin的名字
接下来的内容是:
CSRCS ?= $(wildcard *.c)
CPPSRCS ?= $(wildcard *.cpp)
ASRCs ?= $(wildcard *.s)
ASRCS ?= $(wildcard *.S)
SUBDIRS ?= $(patsubst %/,%,$(dir $(wildcard */Makefile)))
其中wildcard 使变量中的通配符有效:
在Makefile规则中,通配符会被自动展开。但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTERN...) 。(摘录于http://blog.csdn.net/liangkaiming/article/details/6267357)
这里的SUBDIRS定义比较复杂,这里首先获得所有*/Makefile结尾的所有目录,也就是获得包含Makefile文件的所有目录,也就是最后有编译工作的所有目录,然后dir函数得到拥有makefile文件的目录部分,然后用空格替换最后最后一个/,这里可以尝试分析~share/SDK/et_app/makefile最后得到~share/SDK/et_app,这里在之前的~/Share/SDK/et_app/makefile已经定义了SUBDIRS,所以并不会执行这里的$(patsubst %/,%,$(dir $(wildcard */Makefile)))函数,让我们看看之前定义的SUBDIRS,如下:
SUBDIRS=
user
sample_lib
driver
也就是最后编译的子目录就会在这三个文件里进行
接下来定义输出目录:
ODIR := .output
OBJODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/obj
这里的:=代表是覆盖之前的值
根据前面的判断可以得出:
ODIR = ~shareSDKet_app.output
OBJODIR=~shareSDKet_app.outputeagledebugobj,只不过在最后生成的文件中也没有看到这个目录,说明这个只是一个临时目录
注意到了这里程序所在的目录依旧是~shareSDKet_app,只是目前执行的makefile是在~shareSDK下,所以.output依旧是~shareSDKet_app.output而不是~shareSDK.output
接下来就定义了十分关键的两个变量:
OBJS := $(CSRCS:%.c=$(OBJODIR)/%.o)
$(CPPSRCS:%.cpp=$(OBJODIR)/%.o)
$(ASRCs:%.s=$(OBJODIR)/%.o)
$(ASRCS:%.S=$(OBJODIR)/%.o)
DEPS := $(CSRCS:%.c=$(OBJODIR)/%.d)
$(CPPSRCS:%.cpp=$(OBJODIR)/%.d)
$(ASRCs:%.s=$(OBJODIR)/%.d)
$(ASRCS:%.S=$(OBJODIR)/%.d)
这两个是和编译直接相关的变量,这里定义相互关联性
OBJS从表面上来看是让所有的“.c”,".s",".cpp",".S"文件都在OBJODIR目录下生成相应的“.o”文件,这个写法我也是第一次看到,DEPS就是让所有的“.c”,".s",".cpp",".S"文件都在OBJODIR目录下生成相应的“.d”的依赖文件。以后再慢慢分析。实在琢磨不出上面这些话,逼不得已往下走,在下面无意之中破解了这些话的意思,详情请看OIMAGES的说明。经过下面的分析我们知道:OBJS := $(CSRCS:%.c=$(OBJODIR)/%.o) 的意思是在OBJODIR目录下生成和CSRCS:%.c同名的.o文件,比如说有main.c(不管它在哪个目录)都会在OBJODIR目录下生成main.o,那这样的下来OBJS=file1.o file2.o................ ,这里的file既可以是c文件也可以是CPP文件也可以是.S文件和.s文件。DEPS也是同样的道理。
接下来的内容是:
LIBODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/lib
OLIBS := $(GEN_LIBS:%=$(LIBODIR)/%) #目前并不知道这是什么意思 应该是GEN_LIBS=LIBODIR
IMAGEODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/image
OIMAGES := $(GEN_IMAGES:%=$(IMAGEODIR)/%) #和OLIBS一样
BINODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/bin
OBINS := $(GEN_BINS:%=$(BINODIR)/%)
到这里我并不能够搜索到GEN_LIBS但是知道GEN_IMAGES= eagle.app.v6.out,GEN_BINS= eagle.app.v6.bin,但是$(GEN_LIBS:%=$(LIBODIR)/%)这句话是什么意思依旧不知道,和这里定义了几个目录,这些目录都是会在下面的编译命令中直接使用的,
在这里我们通过最后的生成目录知道生成的eagle.app.v6.out在~SDKet_app.outputeagledebugimage那这里我们就有理由推测OIMAGES=~shareSDKet_app.outputeagledebugimageeagle.app.v6.out,那么回过来我们可以知道了$(GEN_IMAGES:%=$(IMAGEODIR)/%) 的意思,这里的意思就是说用GEN_IMAGES替换$(IMAGEODIR)/%中的“%”,那么之前的意思我们就知道了,包括 $(GEN_LIBS:%=$(LIBODIR)/%) 和$(GEN_BINS:%=$(BINODIR)/%)
我们可以得到(猜测):
LIBODIR=~shareSDKet_app.outputeagledebuglib
OLIBS=~shareSDKet_app.outputeagledebuglib
IMAGEODIR=~shareSDKet_app.outputeagledebugimage
OIMAGES=~shareSDKet_app.outputeagledebugimageeagle.app.v6.out
BINODIR=~shareSDKet_app.outputeagledebugbin
OBINS=~shareSDKet_app.outputeagledebugeagle.app.v6.bin
接下来:
CCFLAGS +=
-g
-Wpointer-arith
-Wundef
-Werror
-Wl,-EL
-fno-inline-functions
-nostdlib
-mlongcalls
-mtext-section-literals
-ffunction-sections
-fdata-sections
# -Wall
这里设置编译选项CCFLAGS,这些选项都可以在http://blog.csdn.net/earbao/article/details/53153853看到具体的意思,这里将不再分析,接下来:
CFLAGS = $(CCFLAGS) $(DEFINES) $(EXTRA_CCFLAGS) $(INCLUDES)
DFLAGS = $(CCFLAGS) $(DDEFINES) $(EXTRA_CCFLAGS) $(INCLUDES)
这里设置了 CFLAGS和DFLAGS这里应该是最终编译用到的文件,这些东西前面都有提到,这里不展开了。接下来:
define ShortcutRule
$(1): .subdirs $(2)/$(1)
endef
这里ShortcutRule的作用应该是在 $(2)截取掉$(1),具体作用等用到再看。
befor 2016年12月1日
下面的内容过于复杂,再分析下去对我自己目前而言没有多大的用处,而且目前本人也有很多事要做,工作上面生活上面,所以到了这里本人将不再深究下去,不过这个makefile是一个十分经典的makefile了,有很多东西可以发掘,只不过最近太忙,所以不深究罢了。
直接看重点:
all: .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS)
这是执行make的第一个标签,也是编译的最终语句。这里直接看最后编译打印的语句:
xtensa-lx106-elf-gcc -L/home/esp8266/Share/SDK//lib -Wl,--gc-sections -nostdlib -T/home/esp8266/Share/SDK//ld/eagle.app.v6.new.1024.app1.ld -Wl,--no-check-sections -u call_user_start -Wl,-static -Wl,--start-group -lminic -lgcc -lhal -lphy -lpp -ljson -lpwm -lnet80211 -lwpa -lcrypto -lmain -lfreertos -llwip -lespconn -lsmartconfig -letilink -lfac -lairkiss user/.output/eagle/debug/lib/libuser.a sample_lib/.output/eagle/debug/lib/libsample.a driver/.output/eagle/debug/lib/libdriver.a -Wl,--end-group -o .output/eagle/debug/image/eagle.app.v6.out
这里注意到十分重要的连接文件是:/home/esp8266/Share/SDK//ld/eagle.app.v6.new.1024.app1.ld,所以要知道ESP8266整体的运行顺序可以直接看eagle.app.v6.new.1024.app1.ld这个文件。
下面我们就重启一篇文章来说明eagle.app.v6.new.1024.app1.ld这个文件。
这里再次特别声明:本人的真的事情太多太杂,所以这里暂时深究这个文件,但是到了这里我觉得这个文件是一个十分经典的文件,这里我记住了,以后真的有时间有需要我会回来的。