以编译ls2k pai 为例,编译步骤如下

$ cd zloader.ls2k
$ make cfg              //
$ make tgt=rom         // 生成gzrom.bin
$ make dtb              // 生成gzrom-dtb.bin ,即包含设备树

构建过程如下:

  1. 通过脚本getname获取当前的目录名,以确定具体的板卡,设置相应的变量
  2. 处理libc, libm, libzMakefile
  3. 创建文件夹Targets/LS2K/compile
  4. 进入Targets/LS2K/conf 目录,执行pmoncfg ls2kls2k 是配置文件指定选用哪些驱动模块和命令, files.LS2Kconf/files指定了每个模块或命令对应的实现文件和宏定义。执行pmoncfg ls2k 之后会生成Targets/LS2K/compile/ls2k目录,目录里面有相应的文件。
  5. 跳转到 Targets/LS2K/compile/ls2k 执行命令make depend clean
  6. 根据编译时指定的参数tgt=romtgt=romld.script.S生成Targets/LS2K/conf/ld.script文件。 主要区别是start的地址不同。
  7. Target/LS2K/compile/ls2k/生成pmon, pmon.bin, start.o,拷贝Target/LS2K/compile/ls2k/start.o 到当前位置(zloader.ls2k)。其中pmon.bin是通过objcopy -o binary pmon而来, 如果编译时参入DEBUG=-g 参数则会生成pmon.gdb 文件,用于调试。
  8. pmon.bin通过gzip 压缩成pmon.bin.gz
  9. pmon.bin.gz 通过bin2c 转换成为C数组文件pmon.bin.c,数组名为biosdata
  10. 通过 ./genrom ../Targets/LS2K/compile/ls2k/pmon > initmips.c 生成initmips.c
  11. genrom 的功能是通过执行objdump -x pmon获取pmon的符号表和重定位信息,通过匹配正则表达式从中获取 startinitmips的地址,initmips.c的功能用于将biosdata解压到start处,之后再跳转到initmips处执行。 所以pmon的执行过程是从start.S 开始跳转到zloader.ls2k/initmips.c中的initmips,之后再跳转到Targets/LS2K/ls2k/tgt_machdep.c中的initmips函数
  12. zloader.c inflate.c malloc.c memop.c pmon.bin.c initmips.c 编译成zloader.o
  13. 链接start.ozloader.o 生成gzrom
  14. 通过objcopygzrom转成raw binary gzrom.bin即去除符号表和重定位信息。
  15. 进入Targets/LS2K/compile/ls2k,以Targets/LS2K/conf/ls2k.dts为输入文件,LS2K.dtb.i为输出文件,执行make dtb通过dtcLS2K.dtb.i转换成LS2K.dtb
  16. 通过../tools/pmonenv.pydtb和内核启动参数追加到gzrom.bin形成gzrom-dtb.bin

简化后的Makefile.inc

ifndef PMONCC
CC=$(CROSS_COMPILE)gcc -mabi=32
CROSS_COMPILE ?= mipsel-linux-
else
CC=${PMONCC}
endififeq "$(shell echo ${CC}|grep  'mips-elf-')" ""ifeq "$(shell echo ${CC}|grep  '\-mabi=64')" ""
LD        = $(CROSS_COMPILE)ld  -m elf32ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf32-tradlittlemips"else
LD        = $(CROSS_COMPILE)ld  -m elf64ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf64-tradlittlemips"endif
else
ENDIAN_FLAG= -EL
LD        = $(CROSS_COMPILE)ld  -m elf32ebmip -G 0 -static -n -nostdlib -EL
CC :=${CC} -EL
OUT_FORMAT="elf32-littlemips"
endifRAMSTARTADDR?=0xffffffff88000000
GZROMSTARTADDR?=0xffffffff8f900000
ROMSTARTADDR?=0xffffffff8f010000
export CROSS_COMPILE
export CC += ${MYCC}  -mno-abicalls -fno-pic
export LD
export MKDEP=makedepend
ifeq ("${tgt}","rom")
gencode=./genrom
endififndef tgt
help:@echo use make tgt=sim for sim in linux@echo use make tgt=rom for generate romfile gzrom.bin@echo use make tgt=ram for generate ramfile gzram@echo use make cfg     for config@echo use make recfg   for change config@echo use make tgt=rom DEBUG=-g MYCC="'"-g3 -DMYDBG='"printf(\"debug:%s,%d\\n\",__FILE__,__LINE__);"'"'" to support MYDBG macro.
else
all: ${tgt}
ejtag_rom ejtag_rom1 ejtag_ram rom: clean ${START} zloader.o gcc  -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.bin${START}:rm -f ../Targets/${TARGET}/compile/${TARGETEL}/${START}gcc  -DSTARTADDR=${ROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/cp ../Targets/${TARGET}/compile/${TARGETEL}/${START} .zloader.o: zloader.c inflate.c  malloc.c  memop.c  pmon.bin.c initmips.c$(CC) -c zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}initmips.c:  ../Targets/${TARGET}/compile/${TARGETEL}/pmon${gencode} $< > initmips.cpmon.bin.c:  ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bingzip $< -c > pmon.bin.gz./bin2c pmon.bin.gz pmon.bin.c biosdataendifdtb:make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/${TARGET}.dtb.i DTB_I=`pwd`/../Targets/${TARGET}/conf/${TARGET}.dts dtb./dtc -I dts -O dtb -o ${TARGET}.dtb  ${TARGET}.dtb.i( echo  "#include <include/load_dtb.h>";echo NVRAM_OFFS; echo DTB_OFFS; )| make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/dtbinfo.txt DTB_I=- dtb[ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin && python ../tools/pmonenv.py -O $$((`tail -n 1 dtbinfo.txt`)) -o $$((`tail -n 2 dtbinfo.txt|head -n 1`)) -f gzrom-dtb.bin -d ${TARGET}.dtb -w  al=\(usb0,0\)/boot/vmlinuz al1=\(wd0,0\)/boot/vmlinuz append="'console=ttyS0,115200 console=tty initcall_debug=1 loglevel=20'" FR=1
cleanall: cleanmake -C ../Targets/${TARGET}/compile/${TARGETEL}/ clean
clean:rm -rf *.o zlib_gzip zloader pmon.bin.c gzrom gzrom.bin gzram  initmips.c pmon.bin.gz zlib_deflate/*.o zlib_inflate/*.o zlib_gzrom zlib_gzrom.bin
cfg:# DO NOT DELETEperl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libc/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libm/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libz/Makefile mkdir -p ../Targets/${TARGET}/compilecd ../Targets/${TARGET}/conf/;pmoncfg ${TARGETEL}make -C ../Targets/${TARGET}/compile/${TARGETEL}/ depend clean

详细分析

make 命令是通过对Makefile 文件进行解释编译的,故我们来看Makefile 文件。

$ cat Makefile
include $(shell ./getname)
# DO NOT DELETE

通过上面可知是要执行的Makefile文件名为执行getname后得到的结果

$ cat getname
#echo $(pwd0=$(pwd);pwd1=$(dirname $pwd0)/zloader.;echo Makefile.${pwd0#$pwd1})
pwd=$(pwd);
if [ "${pwd#*/zloader.}" = "$pwd" ];then
echo Makefile.cpci
else
echo Makefile.${pwd#*/zloader.}
fi

通过上面可知是得到的是Makefile.ls2k

$ cat Makefile.ls2k
TARGET=LS2K
TARGETEL=ls2k
export START=start.o
MEMSIZE=128
ZLOADER_OPTIONS=-mips3
include Makefile.inc

通过查看Makefile.ls2k可知其他主要是定义了一些变量和调用Makefile.inc

$ cat Makefile.inc
ifndef PMONCC
CC=$(CROSS_COMPILE)gcc -mabi=32
CROSS_COMPILE ?= mipsel-linux-
else
CC=${PMONCC}
endififeq "$(shell echo ${CC}|grep  'mips-elf-')" ""ifeq "$(shell echo ${CC}|grep  '\-mabi=64')" ""
LD      = $(CROSS_COMPILE)ld  -m elf32ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf32-tradlittlemips"else
LD      = $(CROSS_COMPILE)ld  -m elf64ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf64-tradlittlemips"endif
else
ENDIAN_FLAG= -EL
LD      = $(CROSS_COMPILE)ld  -m elf32ebmip -G 0 -static -n -nostdlib -EL
CC :=${CC} -EL
OUT_FORMAT="elf32-littlemips"
endifRAMSTARTADDR?=0xffffffff88000000
GZROMSTARTADDR?=0xffffffff8f900000
ROMSTARTADDR?=0xffffffff8f010000
export CROSS_COMPILE
export CC += ${MYCC}  -mno-abicalls -fno-pic
export LD
export MKDEP=makedepend
ifeq ("${tgt}","rom")
gencode=./genrom
endififeq ("${tgt}","ejtag_rom")
gencode=./genrom_ejtag
endififeq ("${tgt}","ejtag_rom1")
gencode=./genrom
CC += -DBOOT_FROM_EJTAG
endififeq ("${tgt}","ejtag_ram")
gencode=./genrom
ROMSTARTADDR=0xffffffffff200200
endififeq ("${tgt}","rom1")
gencode=./genrom
endififdef obj
export CC += -g3
pwd=$(shell pwd)
gcc_E:cd ../Targets/${TARGET}/compile/${TARGETEL};${pwd}/mymake  ${obj} > /tmp/tmp.c
endififndef tgt
help:@echo use make tgt=sim for sim in linux@echo use make tgt=rom for generate romfile gzrom.bin@echo use make tgt=ram for generate ramfile gzram@echo use make cfg     for config@echo use make recfg   for change config@echo use make tgt=rom DEBUG=-g MYCC="'"-g3 -DMYDBG='"printf(\"debug:%s,%d\\n\",__FILE__,__LINE__);"'"'" to support MYDBG macro.
else
all: ${tgt}
sim: clean pmon.bin.cgcc -o zloader  -DSIM zloader.c
ejtag_rom ejtag_rom1 ejtag_ram rom: clean ${START} zloader.o gcc  -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.binram: clean startram.o zloader.o ${CC}  -DSTARTADDR=${RAMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ld.script${LD}  -T ld.script -e start -o gzram startram.o zloader.o ${START}:rm -f ../Targets/${TARGET}/compile/${TARGETEL}/${START}gcc  -DSTARTADDR=${ROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/cp ../Targets/${TARGET}/compile/${TARGETEL}/${START} .startram.o:gcc  -DSTARTADDR=${RAMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/ DEBUG='-g -DMYDBG="printf(\"debug:%s,%d\\n\",__FILE__,__LINE__);"'$(CC) -D_LOCORE -G 0  -nostdinc   -DMIPS  -DCONS_BAUD="B115200"  -DCONFIG_CACHE_64K_4WAY  -D_KERNEL -D__OpenBSD__ -DPMON -D__PMON__ -mno-abicalls -c startram.S ${ZLOADER_OPTIONS} -D MEMSIZE=${MEMSIZE}
# $(CC) -D_LOCORE -G 0  -nostdinc   -DMIPS  -DCONS_BAUD="B115200"  -DCONFIG_CACHE_64K_4WAY  -D_KERNEL -D__OpenBSD__ -DPMON -D__PMON__ -EL -mno-abicalls -mcpu=r4000 -c startram.S -D MEMSIZE=${MEMSIZE}
zloader.o: zloader.c inflate.c  malloc.c  memop.c  pmon.bin.c initmips.c$(CC) -c zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}rom1: clean ${START} zloader1.o gcc  -DSTARTADDR=0xffffffff9fc00000 -D_ROM1 -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.binzloader1.o: zloader.c inflate.c  malloc.c  memop.c  pmon.bin.c initmips.c program.o xmodem.osed -i 's/initmips/initmips1/' initmips.csed -i 's/flush_cache2();//;s/flush_cache();//' initmips.c$(CC) -g -c -o zloader.tmp.o zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}${LD}  -r -o zloader.o zloader.tmp.o program.o xmodem.oprogram.o: program.Smake -C  ../Targets/${TARGET}/compile/${TARGETEL}/ `pwd`/$@xmodem.o: xmodem.cmake -C  ../Targets/${TARGET}/compile/${TARGETEL}/ `pwd`/$@zlib_loader.o: zlib_loader.c  ./zlib_gzip zlib_pmon.bin.c initmips.ccd zlib_inflate;$(CC) -I ../../include -c *.c#cd zlib_inflate;$(CC) -I ../../include -EL -mcpu=r4000 -c *.c#$(CC) -I ../include -EL -mcpu=r4000 -c zlib_loader.c $(CC) -I ../include -c zlib_loader.c initmips.c:  ../Targets/${TARGET}/compile/${TARGETEL}/pmon${gencode} $< > initmips.czlib_pmon.bin.c:  ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bin./zlib_gzip $<  zlib_pmon.bin.gz./bin2c zlib_pmon.bin.gz zlib_pmon.bin.c biosdatapmon.bin.c:  ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bingzip $< -c > pmon.bin.gz./bin2c pmon.bin.gz pmon.bin.c biosdataendififeq ("${tgt}","rom")
gencode=./genrom
endififeq ("${tgt}","zlib_rom")
gencode=./genrom
endififndef gencode
gencode=./genram
endifdtb:make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/${TARGET}.dtb.i DTB_I=`pwd`/../Targets/${TARGET}/conf/${TARGET}.dts dtb./dtc -I dts -O dtb -o ${TARGET}.dtb  ${TARGET}.dtb.i( echo  "#include <include/load_dtb.h>";echo NVRAM_OFFS; echo DTB_OFFS; )| make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/dtbinfo.txt DTB_I=- dtb[ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin && python ../tools/pmonenv.py -O $$((`tail -n 1 dtbinfo.txt`)) -o $$((`tail -n 2 dtbinfo.txt|head -n 1`)) -f gzrom-dtb.bin -d ${TARGET}.dtb -w  al=\(usb0,0\)/boot/vmlinuz al1=\(wd0,0\)/boot/vmlinuz append="'console=ttyS0,115200 console=tty initcall_debug=1 loglevel=20'" FR=1
cleanall: cleanmake -C ../Targets/${TARGET}/compile/${TARGETEL}/ clean
clean:rm -rf *.o zlib_gzip zloader pmon.bin.c gzrom gzrom.bin gzram  initmips.c pmon.bin.gz zlib_deflate/*.o zlib_inflate/*.o zlib_gzrom zlib_gzrom.bin
cfg:# DO NOT DELETEperl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libc/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libm/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libz/Makefile mkdir -p ../Targets/${TARGET}/compilecd ../Targets/${TARGET}/conf/;pmoncfg ${TARGETEL}make -C ../Targets/${TARGET}/compile/${TARGETEL}/ depend clean
recfg:vi ../Targets/${TARGET}/conf/$(TARGETEL)make cfgzlib_gzip: zlib_gzip.ccd zlib_deflate/;gcc -I ../../include -c *.ccd zlib_inflate/;gcc -I ../../include -c *.cgcc -o zlib_gzip zlib_gzip.c zlib_deflate/*.o zlib_inflate/*.o

从上可知Makefile.inc 是真正执行编译的控制文件。我们从编译步骤一步一步来分析。

make cfg,对应的过程

cfg:# DO NOT DELETEperl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libc/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libm/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libz/Makefile mkdir -p ../Targets/${TARGET}/compilecd ../Targets/${TARGET}/conf/;pmoncfg ${TARGETEL}make -C ../Targets/${TARGET}/compile/${TARGETEL}/ depend clean

其中TARGETTARGETELMakefile.ls2k 中定义了,分别是LS2Kls2k
make tgt=cfg 对四件事:

  1. 处理libc, libm, libzMakefile
  2. 创建文件夹Targets/LS2K/compile
  3. 进入Targets/LS2K/conf 目录,进行pmoncfg ls2kls2k 是配置文件指定选用哪些驱动模块和命令, files.LS2Kconf/files指定了每个模块或命令对应的实现文件和宏定义。执行pmoncfg ls2k 之后会生成Targets/LS2K/compile/ls2k目录,目录里面有相应的文件。
$ ls
ahci_cdrom.h  cd.h          cmd_shell.h  flash.h    logfile.h  mod_debugger.h     mod_sisfb.h    mod_usb_kbd.h      mod_vesa.h          options     raw_ether.h  usbnet.h
ahci_sd.h     cmd_env.h     cs5536.h     gzip.h     loopdev.h  mod_display.h      mod_smi502.h   mod_usb_ohci.h     mod_vgacon.h        pcibr.h     sdcard.h     wd.h
atp.h         cmd_hist.h    elf32only.h  ide_cd.h   machine    mod_framebuffer.h  mod_smi712.h   mod_usb_storage.h  mod_x86emu.h        pci.h       sd.h
bpfilter.h    cmd_lwdhcp.h  ether.h      ioconf.c   mainbus.h  mod_load.h         mod_symbols.h  mod_usb_uhci.h     mod_x86emu_int10.h  pcinvme.h   target
bridge.h      cmd_more.h    fd.h         iso9660.h  Makefile   mod_s3load.h       mod_tod.h      mod_usb_xhci.h     nand.h              ramfiles.h  tcp.h
  1. 跳转到 Targets/LS2K/compile/ls2k 执行命令make depend clean

Targets/LS2K/compile/ls2k下的Makefile节选

IDENT=-DVGAROM_IN_BIOS -DLOONGSON_2K -DBOOT_PARAM -DVRAM_SIZE="0x10" -DSYSTYPE="\"FCR\"" -DTARGETNAME="\"FCR\"" -DLS2K_STR -DBONITOEL -DDEVBD2E -DMIPS -DINET -DLS3_HT -Dloongson3A3 -D
LSMC_2 -DDDR3_DIMM -DAUTO_DDR_CONFIG -DLOONGSON_GMAC -DDTB -DINTERFACE_3A780E -DCONS_BAUD="B115200" -DMY40IO -DMY61IO -DVGA_BASE="0xb0000000" -DVGA_NO_ROM -DNOPCINAMES -DCONFIG_VIDEO_
16BPP -DNOSNOOP -DHAVE_TOD -DINTERNAL_RTC -DHAVE_NVENV -DHAVE_LOGO -DUSE_SUPERIO_UART -DAUTOLOAD -DCONFIG_CACHE_64K_4WAY -DNVRAM_IN_FLASH -DSET_DDR_FREQ -DIDE_DMA -DIDECD -DFOR_GXEMUL-DFLOATINGPT -DCOM3_BASE_ADDR="0xbfe001e0" -DINPUT_FROM_BOTH -DOUTPUT_TO_BOTH -DKBD_CHECK_FAST -DTEST_USB_HOST -DCONFIG_SLOW_PCI_FOR_BROKENDEV -DCONFIG_VIDEO_SW_CURSOR -DHPET_RTCS!=    echo `/bin/pwd`/../../../..
ENDIAN=EL
ifndef S
S:=$(shell cd ../../../..; pwd)
endif
TARGET= ${S}/Targets/LS2K
SUBTARGET?=ls2k
CPPFLAGS=-mips3OBJS=  wdc.o mainbus.o pcibr.o if.o if_ethersubr.o if_loop.o if_media.o \radix.o raw_cb.o raw_usrreq.o route.o rtsock.o if_ether.o in.o \
...
...
...CFILES= $S/sys/dev/ic/wdc.c $S/pmon/dev/mainbus.c $S/pmon/dev/pcibr.c \$S/sys/net/if.c $S/sys/net/if_ethersubr.c $S/sys/net/if_loop.c \
...
...
...SFILES=all: pmonpmon: ${SYSTEM_DEP} newvers${SYSTEM_LD_HEAD}${SYSTEM_LD}${SYSTEM_LD_TAIL}export CFILES OBJS SFILES
include ${S}/Makefile.inc

根目录下的Makefile.inc,这里面主要是包含了libc,libz, libm等的编译规则

$ cat Makefile.inc
#   $Id: Makefile.Bonito2fdev,v 1.1.1.1 2006/09/14 01:59:09 root Exp $
#
# Makefile for PMON2000 EV64240
#
# This makefile is constructed from a machine description:
#   config machineid
# Most changes should be made in the machine description
#   /sys/arch/pmonppc/conf/``machineid''
# after which you should do
#   config machineid
# Machine generic makefile changes should be made in
#   /sys/arch/pmonppc/conf/Makefile.pmonppc
# after which config should be rerun for all machines of that type.
#
# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
#   IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
#
.SUFFIXES:  .S .c .oCROSS_COMPILE   ?=mipsel-linux-#
# Include the make variables (CC, etc...)
#AS     = $(CROSS_COMPILE)as
LD      = $(CROSS_COMPILE)ld  -m elf32ltsmip -G 0 -static -n -nostdlib
CC      ?= $(CROSS_COMPILE)gcc
CPP     = $(CC) -E
AR      = $(CROSS_COMPILE)ar
NM      = $(CROSS_COMPILE)nm
STRIP       = $(CROSS_COMPILE)strip
OBJCOPY     = $(CROSS_COMPILE)objcopy
OBJDUMP     = $(CROSS_COMPILE)objdump
RANLIB      = $(CROSS_COMPILE)ranlib
SIZE        = $(CROSS_COMPILE)sizeifeq "$(shell echo ${CC}|grep  'mips-elf-')" ""ifeq "$(shell echo ${CC}|grep  '\-mabi=64')" ""
LD      = $(CROSS_COMPILE)ld  -m elf32ltsmip -G 0 -static -n -nostdlibelse
LD      = $(CROSS_COMPILE)ld  -m elf64ltsmip -G 0 -static -n -nostdlibendif
else
ENDIAN_FLAG= -EL
LD      = $(CROSS_COMPILE)ld  -m elf32ebmip -G 0 -static -n -nostdlib -EL
endifOPT?= -O2
IDENT:=${IDENT} $(shell echo  ${IDENT}|sed -n 's/.*-DX\([0-9]\+\)x\([0-9]\+\).*/ -DFB_XSIZE=\1 -DFB_YSIZE=\2 /p')
IDENT:=${IDENT} $(shell echo  ${IDENT}|sed -n 's/.*-DCONFIG_VIDEO_\([0-9]\+\)BPP.*/ -DFB_COLOR_BITS=\1 /p')all: pmon# source tree is located via $S relative to the compilation directory
ifndef S
S:=$(shell cd ../../../..; pwd)
endif# DefinesSTART?=start.o
MACHINE=mips
MACHINE_ARCH=mips
COMPILEDIR=${shell pwd}
OBJDIR=${COMPILEDIR}
PMONDIR=${S}INCLUDES= -I. -I${S}/include -I./machine -I${S} \-I${S}/sys/arch/${MACHINE}/include -I${S}/sys \-I${TARGET} -I${COMPILEDIR} -I${PATH1} -nostdinc -fno-strict-aliasing -fno-picifneq "$(findstring $S/x86emu/src,$(CFILES))" ""INCLUDES += -I${S}/x86emu/src/x86emu/ -I${S}/x86emu/src/x86emu/include
elseINCLUDES += -I${S}/x86emu/int10/x86emu/include -I${S}/x86emu/int10/x86emu/src/x86emu/x86emu
endifCPPFLAGS := ${CPPFLAGS} ${ENDIAN_FLAG}    ${INCLUDES} ${IDENT} -D_KERNEL -D__OpenBSD__ -DPMON -D__PMON__\-mmemcpy -mno-abicalls -fno-builtin#-march=r4600
#CWARNFLAGS=   -Werror -Wall -Wmissing-prototypes -Wstrict-prototypes \-Wno-uninitialized -Wno-format -Wno-main
CWARNFLAGS=    -Wall -Wstrict-prototypes \-Wno-uninitialized -Wno-format -Wno-main
CFLAGS=        ${DEBUG} ${CWARNFLAGS} ${OPT} -G 0
AFLAGS=        -D_LOCORE -G 0
LFLAGS=    ${ENDIAN_FLAG} -N -G 0 -T../../conf/ld.script -e start
STRIPFLAGS=    -g -S --strip-debugHOSTCC?=    ${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS= ${CFLAGS}include ${S}/lib/libc/Makefile.inc
LIBC=${CLIB}
include ${S}/lib/libm/Makefile.inc
LIBM=${MLIB}
include ${S}/lib/libz/Makefile.inc
LIBZ=${ZLIB}# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP}
# where TYPE is NORMAL, DRIVER, or PROFILE}; SUFFIX is the file suffix,
# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file
# is marked as config-dependent.USRLAND_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
USRLAND_C_C=   ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<DRIVER_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
DRIVER_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $<
NORMAL_S_C=    ${AS}  ${COPTS} ${PARAM} $< -o $@# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP}
#   ${SYSTEM_LD_HEAD}
#   ${SYSTEM_LD}
#   ${SYSTEM_LD_TAIL}
#SYSTEM_OBJ=   ${START} crtbegin.o param.o ioconf.o ri.o ${OBJS} ${LIBC} ${LIBM} ${LIBZ} \SYSTEM_OBJ= ${START} crtbegin.o param.o ioconf.o ri.o ${OBJS} ${LIBC} ${LIBM} ${LIBZ} \crtend.o
SYSTEM_DEP=    Makefile ${SYSTEM_OBJ}
SYSTEM_LD_HEAD=    rm -f $@
SYSTEM_LD= @echo ${LD} ${LFLAGS} -o $@ ${LIBDIR} '${SYSTEM_OBJ}' vers.o; \${LD} ${LFLAGS} -o $@ ${LIBDIR} ${SYSTEM_OBJ} vers.o -L../../../../examples/math/ -lgcc
SYSTEM_LD_TAIL=    @${SIZE} $@; chmod 755 $@ ; \${OBJCOPY} -O binary $@ $@.binDEBUG?=
ifneq ("${DEBUG}", "")
LFLAGS+=  -X
SYSTEM_LD_TAIL+=; \echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@
else
LFLAGS+=  -S
endifparam.c: $S/sys/kern/param.crm -f param.ccp $S/sys/kern/param.c .param.o: param.c Makefile${NORMAL_C_C}ioconf.o: ioconf.c${NORMAL_C}
ri.o:ri.c Makefile${NORMAL_C_C}
ri.c: $S/pmon/arch/mips/ri.crm -f ri.ccp $S/pmon/arch/mips/ri.c .
crtbegin.c: $S/pmon/arch/mips/crtbegin.crm -f crtbegin.ccp $S/pmon/arch/mips/crtbegin.c .crtbegin.o: crtbegin.c Makefile${NORMAL_C_C}crtend.c: $S/pmon/arch/mips/crtend.crm -f crtend.ccp $S/pmon/arch/mips/crtend.c .crtend.o: crtend.c Makefile${NORMAL_C_C}newvers: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}sh $S/conf/newvers.sh${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.cclean::rm -f eddep *netbsd netbsd.gdb tags *.[io] [a-z]*.s \[Ee]rrs linterrs makelinks genassym genassym.o lint:@lint -hbxncez -DGENERIC -Dvolatile= ${CPPFLAGS} -UKGDB \${CFILES} \ioconf.c param.c | \grep -v 'static function .* unused'tags:@echo "see $S/kern/Makefile for tags"links:egrep '#if' ${CFILES} | sed -f $S/conf/defines | \sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlinkecho ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \sort -u | comm -23 - dontlink | \sed 's,../.*/\(.*.o\),rm -f \1; ln -s ../GENERIC/\1 \1,' > makelinkssh makelinks && rm -f dontlinkSRCS=    ${TARGET}/${SUBTARGET}/start.S \param.c ioconf.c ri.c ${CFILES} ${SFILES}
depend:: .depend
.depend: ${SRCS} param.c${MKDEP} ${AFLAGS} ${shell echo ${CPPFLAGS}|sed -e 's/ -f[^ ]*//g' } ${TARGET}/${SUBTARGET}/start.S${MKDEP} -a ${CFLAGS} ${shell echo ${CPPFLAGS}|sed -e 's/ -f[^ ]*//g' } param.c ioconf.c ${CFILES}
ifneq (${SFILES}, "")${MKDEP} -a ${AFLAGS} ${shell echo ${CPPFLAGS}|sed -e 's/ -f[^ ]*//g' } ${SFILES}
endif# depend on root or device configuration
autoconf.o conf.o: Makefile# depend on network or filesystem configuration
uipc_proto.o vfs_conf.o: Makefile${START}: ${TARGET}/${SUBTARGET}/${START:.o=.S} Makefile${NORMAL_S}dtb:${CC} ${AFLAGS} ${CPPFLAGS}  -E  -D__ASSEMBLY__ -D__DTS__ -x assembler-with-cpp -o $(DTB_O) $(DTB_I)zpmon: startz.orm start.o && cp -f startz.o start.omake pmonmake -C ../zboot zpmon
startz.o: ${TARGET}/${SUBTARGET}/startz.S Makefile${NORMAL_S}

make tgt=rom 对应的过程

Makefile.inc部分节选

${START}:rm -f ../Targets/${TARGET}/compile/${TARGETEL}/${START}gcc  -DSTARTADDR=${ROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/cp ../Targets/${TARGET}/compile/${TARGETEL}/${START} .

根据编译时指定的参数tgt=romtgt=romld.script.S生成Targets/LS2K/conf/ld.script文件。 主要区别是start的地址不同。
编译生成pmon, pmon.bin, start.o,拷贝Target/LS2K/compile/ls2k/start.o 到当前位置(zloader.ls2k
其中pmon.bin是通过objcopy -o binary pmon而来。根目录下Makefile.inc的编译规则:

SYSTEM_LD_TAIL= @${SIZE} $@; chmod 755 $@ ; \${OBJCOPY} -O binary $@ $@.bin

如果编译时参入DEBUG=-g 参数则会生成pmon.gdb 文件,用于调试。根目录下Makefile.inc的编译规则:

DEBUG?=
ifneq ("${DEBUG}", "")
LFLAGS+=  -X
SYSTEM_LD_TAIL+=; \echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@
else
LFLAGS+=  -S
endif

Makefile.inc的部分节选,rom, zloader.o 目标

ejtag_rom ejtag_rom1 ejtag_ram rom: clean ${START} zloader.o gcc  -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S  > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.binzloader.o: zloader.c inflate.c  malloc.c  memop.c  pmon.bin.c initmips.c$(CC) -c zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}

链接start.ozloader.o 生成gzrom, 通过objcopygzrom转成raw binary gzrom.bin即去除符号表和重定位信息。

生成initmips.c

initmips.c:  ../Targets/${TARGET}/compile/${TARGETEL}/pmon${gencode} $< > initmips.cpmon.bin.c:  ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bingzip $< -c > pmon.bin.gz./bin2c pmon.bin.gz pmon.bin.c biosdataifeq ("${tgt}","rom")
gencode=./genrom
endif

pmon.bin通过gzip 压缩成pmon.bin.gz
pmon.bin.gz 通过bin2c 转换成为C数组文件pmon.bin.c,数组名为biosdata
genrom 的功能是通过执行objdump -x pmon获取pmon的符号表和重定位信息,通过匹配正则表达式从中获取 startinitmips的地址,initmips.c的功能用于将biosdata解压到start处,之后再跳转到initmips处执行。 所以pmon的执行过程是从start.S 开始跳转到zloader.ls2k/initmips.c中的initmips,之后再跳转到Targets/LS2K/ls2k/tgt_machdep.c中的initmips函数

通过上面可知 initmips.c 是通过 ./genrom ../Targets/LS2K/compile/ls2k/pmon > initmips.c 生成的

genrom 的内容:

$ cat genrom
#!/usr/bin/perl
my ($myedata,$myend,$initmips,$mystart);
open(F,qq(objdump -x $ARGV[0]|));
while(<F>)
{
chomp;
if(/([0-9a-f]+).+_edata/){$myedata=qq(0x$1);}if(/([0-9a-f]+).+_end$/){$myend=qq(0x$1);}
if(/([0-9a-f]+).+initmips$/){$myinitmips=qq(0x$1);}
if(/([0-9a-f]+).+\s_start$/){$mystart=qq(0x$1);}
}
printf(<< "END"
void stringserial(char *msg);
void realinitmips(unsigned long long msize);
void enable_cache()
{__asm__ volatile(".set mips2;\\n" \\
"        mfc0   \$4,\$16;\\n" \\
"        and    \$4,\$4,0xfffffff8;\\n" \\
"        or     \$4,\$4,0x3;\\n" \\
"        mtc0   \$4,\$16;\\n" \\
"      .set mips0;\\n":::"\$4");
}#ifndef NOCACHE2
void flush_cache2()
{
asm volatile(\
".set mips3;\\n" \\
"  mfc0    \$3, \$15;          # read processor ID register;\\n" \\
"  li      \$2, 0x6303;                #godson2f prid;\\n" \\
"  beq     \$2, \$3, godson_2f;\\n" \\
"  nop;\\n" \\
"  li      \$2, 0x6302;                #godson2e prid;\\n" \\
"  bne     \$2, \$3,11f;             #godson3a/2g need not flush\\n" \\
"  nop;\\n" \\
"# godson2e;\\n" \\
" godson_2f: " \\
"  li    \$2, 0x80000000;\\n" \\
"   addu  \$3,\$2,512*1024;\\n" \\
"10:\\n" \\
"  cache   3, 0(\$2);\\n" \\
"  cache   3, 1(\$2);\\n" \\
"  cache   3, 2(\$2);\\n" \\
"  cache   3, 3(\$2);\\n" \\
"  addu    \$2, 32;\\n" \\
"  bne     \$2,\$3, 10b;\\n" \\
"  nop;\\n" \\
"11:\\n" \\
:::"\$2","\$3"
);
}
#else
void flush_cache()
{#ifndef WAYBIT
#define WAYBIT 0
#endif
#define WAY__(x) #x
#define WAY_(x,y) WAY__((x<<y))
#define WAY(x) WAY_(x,WAYBIT)
asm volatile(\
"      .set mips3;\\n"
"        li    \$5,0x80000000;\\n"
"        addu  \$6,\$5,16384;\\n"
"1:\\n"
"        cache  1," WAY(0) "(\$5);\\n"
"        cache  1," WAY(1) "(\$5);\\n"
"        cache  1," WAY(2) "(\$5);\\n"
"        cache  1," WAY(3) "(\$5);\\n"
"        cache  0," WAY(0) "(\$5);\\n"
"        cache  0," WAY(1) "(\$5);\\n"
"        cache  0," WAY(2) "(\$5);\\n"
"        cache  0," WAY(3) "(\$5);\\n"
"        add    \$5,\$5,32;\\n"
"        bne    \$5,\$6,1b;\\n"
"        nop;\\n"
"      .set mips0;\\n"
::: "\$5","\$6");
}
#endif
void initmips(unsigned long long msize,unsigned long long dmsize, unsigned long long dctrl)
{long *edata=(void *)$myedata;long *end=(void *)$myend;int *p;int debug=(msize==0);
#ifdef LS3A2H_STRlong long str_ra,str_flag,str_sp;str_ra = *((long long*)0xafaaa040);str_sp = *((long long*)0xafaaa048);str_flag = *((long long*)0xafaaa050);
#endif
//  CPU_TLBClear();stringserial("Uncompressing Bios");if(!debug||dctrl&1)enable_cache();#ifdef LS3A2H_STRif ((str_sp < 0x9800000000000000) || (str_ra < 0xffffffff80000000)|| (str_flag != 0x5a5a5a5a5a5a5a5a)) {
#endifwhile(1){if(run_unzip(biosdata,$mystart)>=0)break;}
#ifdef LS3A2H_STR}
#endif  stringserial("OK,Booting Bios\\r\\n");for(p=edata;p<=end;p++){*p=0;}memset($mystart-0x1000,0,0x1000);//$mystart-0x1000 for frame(registers),memset for pretty
#ifdef NOCACHE2flush_cache();
#elseflush_cache2();
#endifrealinitmips(debug?dmsize:msize);
}void realinitmips(unsigned long long msize)
{stringserial("zloader/initmips.c realinitmips ...\\r\\n");asm ("li  \$29,$mystart-0x4000;\\n" \\
"             li \$2,$myinitmips;\\n" \\
"             move \$4,\%0;\\n" \\
"             jalr \$2;\\n" \\
"             nop;\\n" \\
"            1: b 1b;nop;" \\:: "r" (msize): "\$29", "\$2","\$4");}
END
);

make dtb 对应的过程

dtb:make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/${TARGET}.dtb.i DTB_I=`pwd`/../Targets/${TARGET}/conf/${TARGET}.dts dtb./dtc -I dts -O dtb -o ${TARGET}.dtb  ${TARGET}.dtb.i( echo  "#include <include/load_dtb.h>";echo NVRAM_OFFS; echo DTB_OFFS; )| make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/dtbinfo.txt DTB_I=- dtb[ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin && python ../tools/pmonenv.py -O $$((`tail -n 1 dtbinfo.txt`)) -o $$((`tail -n 2 dtbinfo.txt|head -n 1`)) -f gzrom-dtb.bin -d ${TARGET}.dtb -w  al=\(usb0,0\)/boot/vmlinuz al1=\(wd0,0\)/boot/vmlinuz append="'console=ttyS0,115200 console=tty initcall_debug=1 loglevel=20'" FR=1

进入Targets/LS2K/compile/ls2k,以Targets/LS2K/conf/ls2k.dts为输入文件,LS2K.dtb.i为输出文件,执行make dtb
通过dtcLS2K.dtb.i转换成LS2K.dtb
通过../tools/pmonenv.pydtb和内核启动参数追加到gzrom.bin生成gzrom-dtb.bin

make dtb 的编译规则(根目录下的Makefile.inc):

dtb:${CC} ${AFLAGS} ${CPPFLAGS}  -E  -D__ASSEMBLY__ -D__DTS__ -x assembler-with-cpp -o $(DTB_O) $(DTB_I)

tools/pmonenv.py

$ cat  ../tools/pmonenv.py
"""
python pmonenv.py -f gzrom.bin -o 0x70000 -s 512 al=/dev/mtd0 append="'root=/dev/mtdblock0'"
python ../tools/pmonenv.py -f gzrom-dtb.bin -d ls2k.dtb -w  al=/dev/ram@p0x110000000 al1=/dev/ram@p0x110000000 append="'console=ttyS0,115200 initcall_debug=1 loglevel=20 nosmp'" FR=1
"""
import struct
import sys
import getopt
def readenv(fname,foff,fsz,argv):f=open(fname,'rb+')f.seek(foff,0)a=f.read(fsz);a=a.ljust(fsz,b'\x00')f.close()d={}b = struct.unpack('!'+str(len(a)//2)+'H',a)if(sum(b)&0xffff):print('checksum error, rebuild env')t = argvelse:e = a[2:].find(b'\x00\x00')t = a[2:2+e].split(b'\x00')+list(map(lambda x:x.encode('utf8'),argv))for i in t:a=i.split(b'=',1)if len(a) > 1:d[a[0]] = a[1]elif a[0] in d:del d[a[0]]return ddef writeenv(fname,foff,fsz,d):a=b'\x00\x00'for i in d.keys():a += i+b'='+d[i]+b'\x00'a=a.ljust(fsz,b'\x00')b = struct.pack('!H',(-sum(struct.unpack('!'+str(len(a)//2)+'H',a)))&0xffff)a=b+a[2:]f=open(fname,'rb+')f.seek(foff,0)f.write(a)f.close()def writehexenv(fname,hexbin):f=open(fname,'rb+')f.seek(foff+fsz, 0)f.write('\xff'*256)for b in hexbin.split(','):i,v = b.split(':')f.seek(foff+int(i,0),0)f.write(v.decode('hex'))f.close()def writedtb(fname,dtb,foff):f=open(dtb,'rb')a=f.read();f.close()a=a.ljust(0x4000-8,'\x00')b = struct.pack('I',(-sum(struct.unpack(''+str(len(a)//4)+'I',a)))&0xffffffff)a=b+a+bf=open(fname,'rb+')f.seek(foff-0x4000,0)f.write(a)f.close()if __name__ == '__main__':opt,argv=getopt.getopt(sys.argv[1:],'b:o:s:f:wd:')opt=dict(opt)foff = int(opt['-o'],0) if '-o' in opt  else 0x000ff000fsz = int(opt['-s'],0) if '-s' in opt else 500fname = opt['-f'] if '-f' in opt else 'gzrom.bin'd=readenv(fname,foff,fsz,argv)print(d)if '-w' in opt:writeenv(fname,foff,fsz,d)if '-b' in opt: writehexenv(fname, opt['-b'])if '-d' in opt: writedtb(fname, opt['-d'], foff)

pmon构建过程分析相关推荐

  1. 深入Vue - 源码目录及构建过程分析

    摘要: Vue源码阅读第一步. 原文:深入vue - 源码目录及构建过程分析 公众号:前端小苑 Fundebug经授权转载,版权归原作者所有. 本文主要梳理一下vue代码的目录,以及vue代码构建流程 ...

  2. Kubernetes构建过程分析

    构建方式 Kubernetes的构建方式可以分为3种,分别是本地环境构建.容器环境构建.Bazel环境构建. Kubernetes构建方式: 本地环境构建 make make all 容器环境构建 m ...

  3. ConsumeQueue构建过程分析

    1. 前言 理论上来说,RocketMQ只要有CommitLog文件就可以正常运行了,那为何还要维护ConsumeQueue文件呢? ​ ConsumeQueue是消费队列,引入它的目的是为了提高消费 ...

  4. 国产处理器/操作系统迅为iTOP-2K1000开发板

    [龙芯LS2K1000]开发环境搭建 P1 开发板环境说明:https://www.bilibili.com/video/BV1VU4y1c7Gc?p=1   P2 认识龙芯LS2K1000处理器:h ...

  5. MPB:南京​湖泊所王建军组-​群落构建过程的定量指标——扩散-生态位连续体指数...

    为进一步提高<微生物组实验手册>稿件质量,本项目新增大众评审环节.文章在通过同行评审后,采用公众号推送方式分享全文,任何人均可在线提交修改意见.公众号格式显示略有问题,建议电脑端点击文末阅 ...

  6. 优酷 Android 构建速度优化实践

    作者:苏彦郊(木磊) Android 项目一般使用 gradle 作为构建打包工具,gradle 简洁.动态的功能特性为人津津乐道,同样,构建执行速度缓慢的缺陷也一直为人诟病. 近年来,随着优酷功能特 ...

  7. vue源码解析(3)—— Vue.js 源码构建

    Vue.js 源码构建 Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下. 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.json ...

  8. Android系统开发和性能优化——查漏补缺【建议收藏】

    做了这么久性能相关的工作,也接触了不少模块,说实话要做好性能这一块,真心不容易.为什么这么说? 是因为需要接触的知识实在是太多了, Android 是一个整体,牵一发而动全身,不是说只懂一个模块就可以 ...

  9. as安装过程中gradle_重新认识AndroidStudio和Gradle,这些都是我们应该知道的

    前言 主要从AndroidStudio的环境安装升级GradleEclipse转AS,多渠道配置Maven私服Action,Option快捷键等几个方面出发讲一些操作技巧以及我对AndroidStud ...

  10. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

最新文章

  1. python开发好学吗-Python的前景和Python好不好学呢?
  2. 这13个开源GIS软件,你了解几个?【转】
  3. 【Python教程】常见字符串去除空格的教程
  4. android 取色器_老板夸我PPT配色高级,以为我学过设计,其实我都是从Logo取色
  5. 内置系统账户:Local system/Network service/Local Service 区别
  6. Android Sdk 安装配置
  7. camera (14)---智能手机双摄像头原理解析:RGB +Depth
  8. MIT6.828 boot.S文件分析
  9. ASP.NET文件的上传与下载
  10. 最适合程序猿的笔记软件
  11. JS-加入收藏夹的代码
  12. 我的实用小软件(持续更新)
  13. #VMware ESXI7.0的下载
  14. [基本功练习素材]播音初学者资料—口部操,唇舌力量控制;声母韵母难点练习
  15. 大数据量分页存储过程效率测试附代码(转http://www.cnblogs.com/lli0077/archive/2008/09/03/1282862.html)...
  16. mysql server has fone away
  17. “语象观察”-爬取人民日报并统计词频
  18. js实现京东商城导航
  19. 讲座录播|图数据库中的子图匹配算法-邹磊
  20. 网络分析仪测试线损_求e5071c网络分析仪校50欧姆阻抗与线损方法,标准...

热门文章

  1. html5手机的注册页面,H5页面结合vue实现登录注册组件
  2. win10启用php_zip,win10右键没有压缩文件选项怎么办
  3. 计算机主机房净高,机房建设标准
  4. 地图标注不完整图片_“地图帝”不规范使用图件之Anton Balazh作品介绍
  5. Linux 的shell脚本的分享,运用了多个不同的方法,实现使用脚本批量巡检服务器,非常有借鉴作用...
  6. 如何自定义TCP通信协议
  7. 上位机和下位机的概念
  8. 酷狗音乐api接口php,【教程分享】酷狗音乐API接口大全(40+个)
  9. GMS地下水数值模拟
  10. 【控制理论】预测控制分析