uboot的源文件众多,学习庞然大物首先找到脊椎--顶层的makfile,逐一破解。但是,uboot的makefile同样是一个庞然大物,所以也要找到它的主线。倘若过分专注部分细节,很难做到把握全局,实际上也不可能很好理解细节。

介于此,笔者已经写了一篇uboot makefile整体解析,可以先从主体上把握makefile。然后,再读这篇makefile强大功能实现的细节,才能做到循序渐进。

说明:uboot顶层makefile的注释机会全部源码都搬上来了,而注释都是黑体加粗以与源码有强烈的区别。

VERSION = 1            //主版本号

PATCHLEVEL = 1       //次级版本号

SUBLEVEL = 6

EXTRAVERSION =     //版本号扩展

U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)   //这个Uboot的版本为1.1.6

VERSION_FILE = $(obj)include/version_autogenerated.h

//生成uboot的版本信息

HOSTARCH := $(shell uname -m | \

sed -e s/i.86/i386/ \

-e s/sun4u/sparc64/ \

-e s/arm.*/arm/ \

-e s/sa110/arm/ \

-e s/powerpc/ppc/ \

-e s/macppc/ppc/)

//获取主机架构,笔者电脑是酷睿双核,#uname –m输出结构是i686,执行替换命令sed -e s/i.86/i386/后,就变成了i386,

//并且将这个值保存在HOSTARCH变量中。

HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \

sed -e 's/\(cygwin\).*/cygwin/')

//获取主机操作系统,执行#uname -s可以查看自己的操作系统类型,笔者使用的操作系统是Linux。tr '[:upper:]' '[:lower:]'

//具有大写转小写的功能,所以最终HOSTOS的值为linux。

export     HOSTARCH HOSTOS

//将两个变量导出,可以供嵌套的makefile调用

# Deal with colliding definitions from tcsh etc.

VENDOR=

#########################################################################

# U-boot build supports producing a object files to the separate external

# directory. Two use cases are supported:

# 1) Add O= to the make command line

# 'make O=/tmp/build all'

# 2) Set environement variable BUILD_DIR to point to the desired location

# 'export BUILD_DIR=/tmp/build'

# 'make'

# The second approach can also be used with a MAKEALL script

# 'export BUILD_DIR=/tmp/build'

# './MAKEALL'

# Command line 'O=' setting overrides BUILD_DIR environent variable.

# When none of the above methods is used the local build is performed and

# the object files are placed in the source directory.

//上边的注释讲的是uboot支持编译时,将目标文件生成在其他的目录中,这样可以保持源文件的干净,另外从目标

//文件的生成目录中查看生成的文件时一目了然。如果想要这样做,提供了两种方法。第一种方法是执行命令

//#make O=/tmp/build all;第二种方法,可以先在命令行模式定义环境变量export BUILD_DIR=/tmp/build',

//然后再执行make就行了。通常懒惰的编译方式就是让生成的目标文件和源文件混在一起,那么BUILD_DIR就会没定义。

ifdef O

ifeq ("$(origin O)", "command line")

BUILD_DIR := $(O)

endif

endif

//这是第一种方法的实现过程,$(origin O)是输出变量O的定义来源,假设在命令行模式输//入#make O=/tmp/build all

//来编译,那么O的定义来源是命令行,函数的输出是command line。

ifneq ($(BUILD_DIR),)

//倘若BUILD_DIR定义过了,也就是不希望目标文件与源文件混在一起,那么直到“endif # //ifneq ($(BUILD_DIR),)”

//的内容都有效;倘若没有定义BUILD_DIR,那么这部分代码将不起作用。

saved-output := $(BUILD_DIR)

// 将BUILD_DIR保存在saved-output变量中

# Attempt to create a output directory.

$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})

//-d是判断BUILD_DIR是否存在,倘若不存在就就创建。mkdir的-p参数代表若路径中的

//某些目录不存在,也一并创建

# Verify if it was successful.

//核查BUILD_DIR是否已经创建

BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)

//试图进入$(BUILD_DIR),倘若能进入,则将它的路径赋给BUILD_DIR,注意这时的BUILD_DIR已经是一个真实存在

//目录的代言人,而之前的只是希望创建的目录。需要说明的是倘若BUILD_DIR还没有创建,那么cd $(BUILD_DIR)将执

//行错误,返回值是空,虽然这时发生错误,但是编译会忽略这个错误还能继续进行

$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))

// 如果没有创建成功,就执行error函数,输出信息output directory "$(saved-output)" does not exist),然后编译终止

endif # ifneq ($(BUILD_DIR),)

OBJTREE             := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))

//如果BUILD_DIR不为空,目标目录就等于BUILD_DIR;倘若没定义,就取为当前目录

SRCTREE   := $(CURDIR)//源文件目录等于当前文件夹

TOPDIR         := $(SRCTREE)//顶层目录等于源文件目录

LNDIR           := $(OBJTREE)  //连接目录等于BUILD_DIR

export     TOPDIR SRCTREE OBJTREE//将这三个变量导出

MKCONFIG   := $(SRCTREE)/mkconfig//指定mkconfig的位置

export MKCONFIG //将MKCONFIG变量导出

ifneq ($(OBJTREE),$(SRCTREE)) //如果目标目录和源文件目录不相等

REMOTE_BUILD        := 1  //就定义REMOTE_BUILD变量并取值为1

export REMOTE_BUILD    //然后再将变量导出

endif

# $(obj) and (src) are defined in config.mk but here in main Makefile

# we also need them before config.mk is included which is the case for

# some targets like unconfig, clean, clobber, distclean, etc.

//obj和src的定义也出现在了顶层目录的config.mk中,但是config.mk中的定义由于受下边//红色加粗判断语句的影响,只有

//在“make *_config”执行后($(OBJTREE)/include/config.mk就会存在),再执行的make程序才能将config.mk包含进顶

//层makefile中。而在没有先执行“make *_config”或者$(OBJTREE)/include/config.mk不存在的情况下,如果想执行unconfig

//, clean, clobber, distclean,而这些命令用到了变量obj、src,所以这里提前包含进去。

//但是我也有疑惑,为什么不能将顶层目录的config.mk包含在全局中,设计者为什么要把它放在条件执行里边。

ifneq ($(OBJTREE),$(SRCTREE))

obj := $(OBJTREE)/

src := $(SRCTREE)/

else

obj :=

src :=

endif

export obj src

//定义变量obj和src,并将这两个变量导出,obj是编译目标文件的前缀,从而实现生成的目标文件在于源文件相区别的目录中

#########################################################################

ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))

//这个ifeq横跨的范围非常广,用红色加粗字体表明。只有$(OBJTREE)/include/config.mk存在(也就是说已经

//执行了make *.config)的情况下,这部分包含的内容才有效

# load ARCH, BOARD, and CPU configuration

include $(OBJTREE)/include/config.mk   //将make *_config生成的config.mk文件包含进来

export     ARCH CPU BOARD VENDOR SOC //导出5个变量以供其他子目录的makefile调用

ifndef CROSS_COMPILE

ifeq ($(HOSTARCH),ppc)

CROSS_COMPILE =

else

ifeq ($(ARCH),ppc)

CROSS_COMPILE = powerpc-linux-

endif

ifeq ($(ARCH),arm)

CROSS_COMPILE = arm-linux- //根据变量ARCH可以使这行满足条件,确定了交叉编译使//用arm-linux-

endif

ifeq ($(ARCH),i386)

ifeq ($(HOSTARCH),i386)

CROSS_COMPILE =

else

CROSS_COMPILE = i386-linux-

endif

endif

ifeq ($(ARCH),mips)

CROSS_COMPILE = mips_4KC-

endif

ifeq ($(ARCH),nios)

CROSS_COMPILE = nios-elf-

endif

ifeq ($(ARCH),nios2)

CROSS_COMPILE = nios2-elf-

endif

ifeq ($(ARCH),m68k)

CROSS_COMPILE = m68k-elf-

endif

ifeq ($(ARCH),microblaze)

CROSS_COMPILE = mb-

endif

ifeq ($(ARCH),blackfin)

CROSS_COMPILE = bfin-elf-

endif

ifeq ($(ARCH),avr32)

CROSS_COMPILE = avr32-

endif

endif

endif

export     CROSS_COMPILE  //导出交叉编译变量

# load other configuration

include $(TOPDIR)/config.mk //将顶层的config.mk也包含进来

#########################################################################

# U-Boot objects....order is important (i.e. start must be first)

OBJS  = cpu/$(CPU)/start.o

ifeq ($(CPU),i386)

OBJS += cpu/$(CPU)/start16.o

OBJS += cpu/$(CPU)/reset.o

endif

ifeq ($(CPU),ppc4xx)

OBJS += cpu/$(CPU)/resetvec.o

endif

ifeq ($(CPU),mpc83xx)

OBJS += cpu/$(CPU)/resetvec.o

endif

ifeq ($(CPU),mpc85xx)

OBJS += cpu/$(CPU)/resetvec.o

endif

ifeq ($(CPU),mpc86xx)

OBJS += cpu/$(CPU)/resetvec.o

endif

ifeq ($(CPU),bf533)

OBJS += cpu/$(CPU)/start1.o      cpu/$(CPU)/interrupt.o  cpu/$(CPU)/cache.o

OBJS += cpu/$(CPU)/cplbhdlr.o   cpu/$(CPU)/cplbmgr.o   cpu/$(CPU)/flush.o

endif

//确定目标文件构成

OBJS := $(addprefix $(obj),$(OBJS))

//给待生成的目标文件带上路径

LIBS  = lib_generic/libgeneric.a

LIBS += board/$(BOARDDIR)/lib$(BOARD).a

LIBS += cpu/$(CPU)/lib$(CPU).a

ifdef SOC

LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a

endif

LIBS += lib_$(ARCH)/lib$(ARCH).a

LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \

fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a

LIBS += net/libnet.a

LIBS += disk/libdisk.a

LIBS += rtc/librtc.a

LIBS += dtt/libdtt.a

LIBS += drivers/libdrivers.a

LIBS += drivers/nand/libnand.a

LIBS += drivers/nand_legacy/libnand_legacy.a

LIBS += drivers/sk98lin/libsk98lin.a

LIBS += post/libpost.a post/cpu/libcpu.a

LIBS += common/libcommon.a

LIBS += $(BOARDLIBS)

//确定库文件构成

LIBS := $(addprefix $(obj),$(LIBS))

//给待生成的库文件带上路径

.PHONY : $(LIBS)

//将带生成的库文件作为伪目标来处理

# Add GCC lib

PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc

//添加系统标准库

# The "tools" are needed early, so put this first

# Don't include stuff already done in $(LIBS)

SUBDIRS      = tools \

examples \

post \

post/cpu

.PHONY : $(SUBDIRS)

//定义make执行要首先处理的目录

ifeq ($(CONFIG_NAND_U_BOOT),y)

NAND_SPL = nand_spl

U_BOOT_NAND = $(obj)u-boot-nand.bin

endif

//假若定义了CONFIG_NAND_U_BOOT,那么将总目标all中添加$(obj)u-boot-nand.bin,否则不添加

__OBJS := $(subst $(obj),,$(OBJS))

__LIBS := $(subst $(obj),,$(LIBS))

//OBJS、LIBS除去$(obj)部分的路径

#########################################################################

ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)

//总目标的构成,也可以人为添加其他的目标

all:          $(ALL)

//定义总目标all

$(obj)u-boot.hex:   $(obj)u-boot

$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@

//生成16进制的可执行程序

$(obj)u-boot.srec:   $(obj)u-boot

$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@

$(obj)u-boot.bin:    $(obj)u-boot

$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@

//生成2进制的可执行程序

$(obj)u-boot.img:   $(obj)u-boot.bin

./tools/mkimage -A $(ARCH) -T firmware -C none \

-a $(TEXT_BASE) -e 0 \

-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \

sed -e 's/"[      ]*$$/ for $(BOARD) board"/') \

-d $< $@

$(obj)u-boot.dis:    $(obj)u-boot

$(OBJDUMP) -d $< > $@

//生成反汇编文件u-boot.dis

$(obj)u-boot:         depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)

UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\

cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \

--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \

-Map u-boot.map -o u-boot

//生成elf格式的u-boot文件

$(OBJS):

$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))

//中间目标文件生成

$(LIBS):

$(MAKE) -C $(dir $(subst $(obj),,$@))

//中间库文件生成

$(SUBDIRS):

$(MAKE) -C $@ all

//SUBDIRS目录处理

$(NAND_SPL):     version

$(MAKE) -C nand_spl/board/$(BOARDDIR) all

$(U_BOOT_NAND):     $(NAND_SPL) $(obj)u-boot.bin

cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin

version:

@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \

echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \

echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \

$(TOPDIR)) >> $(VERSION_FILE); \

echo "\"" >> $(VERSION_FILE)

//版本头文件生成

gdbtools:

$(MAKE) -C tools/gdb all || exit 1

updater:

$(MAKE) -C tools/updater all || exit 1

env:

$(MAKE) -C tools/env all || exit 1

depend dep:

for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done

//执行make depend或者make dep都能触发命令

tags ctags:

ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \

lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \

fs/cramfs fs/fat fs/fdos fs/jffs2 \

net disk rtc dtt drivers drivers/sk98lin common \

\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`

etags:

etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \

lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \

fs/cramfs fs/fat fs/fdos fs/jffs2 \

net disk rtc dtt drivers drivers/sk98lin common \

\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`

$(obj)System.map: $(obj)u-boot

@$(NM) $< | \

grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \

sort > $(obj)System.map

//生成map文件

#########################################################################

else

all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \

$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \

$(SUBDIRS) version gdbtools updater env depend \

dep tags ctags etags $(obj)System.map:

@echo "System not configured - see README" >&2

@ exit 1

endif

//倘若没有include $(OBJTREE)/include/config.mk 文件,将打印出错误信息“System not configured

//- see README”,并且make程序也结束

.PHONY : CHANGELOG

CHANGELOG:

git log --no-merges U-Boot-1_1_5.. | \

unexpand -a | sed -e 's/\s\s*$$//' > $@

#########################################################################

unconfig:

@rm -f $(obj)include/config.h $(obj)include/config.mk \

$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp

//删除配置文件,即与make *_config过程相反

//剩下的*_config,属于相似内容,只举一个常见的smdk2410_config,以作说明

smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0

//执行make smdk2410_config,就会调用顶层目录中的mkconfig(shell脚本),同时给这个脚本传入参数

//arm arm920t smdk2410 NULL s3c24x0。mkconfig脚本根据这些传入的参数生成与开发板相适应的一系列配置文件。

#########################################################################

//不要忘记makfile的最后边,还有一部分很重要的内容

clean: //clean删除
find $(OBJTREE) -type f \
\( -name 'core' -o -name '*.bak' -o -name '*~' \
-o -name '*.o' -o -name '*.a' \) -print \
| xargs rm -f
rm -f $(obj)examples/hello_world $(obj)examples/timer \
$(obj)examples/eepro100_eeprom $(obj)examples/sched \
$(obj)examples/mem_to_mem_idma2intr $(obj)examples/82559_eeprom \
$(obj)examples/smc91111_eeprom $(obj)examples/interrupt \
$(obj)examples/test_burst
rm -f $(obj)tools/img2srec $(obj)tools/mkimage $(obj)tools/envcrc \
$(obj)tools/gen_eth_addr
rm -f $(obj)tools/mpc86x_clk $(obj)tools/ncb
rm -f $(obj)tools/easylogo/easylogo $(obj)tools/bmp_logo
rm -f $(obj)tools/gdb/astest $(obj)tools/gdb/gdbcont $(obj)tools/gdb/gdbsend
rm -f $(obj)tools/env/fw_printenv $(obj)tools/env/fw_setenv
rm -f $(obj)board/cray/L1/bootscript.c $(obj)board/cray/L1/bootscript.image
rm -f $(obj)board/netstar/eeprom $(obj)board/netstar/crcek $(obj)board/netstar/crcit
rm -f $(obj)board/netstar/*.srec $(obj)board/netstar/*.bin
rm -f $(obj)board/trab/trab_fkt $(obj)board/voiceblue/eeprom
rm -f $(obj)board/integratorap/u-boot.lds $(obj)board/integratorcp/u-boot.lds
rm -f $(obj)include/bmp_logo.h
rm -f $(obj)nand_spl/u-boot-spl $(obj)nand_spl/u-boot-spl.map

clobber: clean //除了调用clean删除,还要再执行额外的删除命令
find $(OBJTREE) -type f \( -name .depend \
-o -name '*.srec' -o -name '*.bin' -o -name u-boot.img \) \
-print0 \
| xargs -0 rm -f
rm -f $(OBJS) $(obj)*.bak $(obj)ctags $(obj)etags $(obj)TAGS $(obj)include/version_autogenerated.h
rm -fr $(obj)*.*~
rm -f $(obj)u-boot $(obj)u-boot.map $(obj)u-boot.hex $(ALL)
rm -f $(obj)tools/crc32.c $(obj)tools/environment.c $(obj)tools/env/crc32.c
rm -f $(obj)tools/inca-swap-bytes $(obj)cpu/mpc824x/bedbug_603e.c
rm -f $(obj)include/asm/proc $(obj)include/asm/arch $(obj)include/asm
[ ! -d $(OBJTREE)/nand_spl ] || find $(obj)nand_spl -lname "*" -print | xargs rm -f

ifeq ($(OBJTREE),$(SRCTREE))
mrproper \
distclean: clobber unconfig //倘若目标目录与源目录相同,distclean调用clobber unconfig来删除
else
mrproper \
distclean: clobber unconfig //倘若目标目录与源目录不相同,distclean调用clobber unconfig来删除
rm -rf $(OBJTREE)/*         //而且,还要删除OBJTREE目录下的所有内容
endif

backup: //打包备份
F=`basename $(TOPDIR)` ; cd .. ; \                         //跳到当前目录的外边,然后打包整个文件夹
gtar --force-local -zcvf `date "+$ $F-%Y-%m-%d-%T.tar.gz"` $ $F //打包,名字中插入日期

#########################################################################

//最后,插入编译过程中重要的打印信息(要深入理解u-boot的makefile工作原理,必须做实际的实验,实际的make一下,

//看看你正想了解的地方发生了什么)

start.o

libsmdk2410.a

libarm920t.a

all目标的实现

参考博客:U-Boot Makefile分析

uboot 顶层makefile细节分析的更多相关文章

  1. u-boot顶层Makefile分析

    1.u-boot制作命令 make forlinx_nand_ram256_config: make all; 2.顶层mkconfig分析,参考 U-BOOT顶层目录mkconfig分析 mkcon ...

  2. TQ210 —— S5PV210 uboot顶层Makefile分析

    转自:http://blog.csdn.net/wqx521/article/details/52469759 # (C) Copyright 2000-2008 # Wolfgang Denk, D ...

  3. tiny210——uboot移植Makefile文章分析

    这东西已经写,我们没有时间发布,如今,终于有时间稍微长送记录汇总uboot学习过程.具体了.以后忘了也能够再温习回来嘛有些特殊字符显示得乱掉了 Makefile追踪技巧: 技巧1:能够先从编译目标開始 ...

  4. 2014-10 u-boot 顶层config.mk分析

    /** ****************************************************************************** * @author    Maox ...

  5. uboot顶层config.mk分析

    uboot顶层目录中的config.mk定义了确定了当前执行makefile所对应的源文件目录.目标文件目录,编译的程序编译.连接的选项,以及目标文件生成的规则等等.它被包含在顶层的makefile以 ...

  6. uboot makefile构建分析

    前言 几年前分析过uboot的构建及启动过程,做了笔记,但最终没有转为文章.这次又有机会开发嵌入式产品了(之前一年多都是在搞x86 linux),看了下uboot的构建过程,觉得有必要写下整个分析过程 ...

  7. uboot主Makefile分析(t配置和编译过程详解)

    1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_c ...

  8. uboot 主Makefile 分析。

    本文以uboot_1.1.6 对应的CPU是S3C2440 为例 uboot_1.1.6 根目录下的主Makefile开头: VERSION = PATCHLEVEL = SUBLEVEL = EXT ...

  9. uboot makefile构建分析-续

    前言 这篇博文是 uboot makefile构建分析的续篇,继续分析uboot构建u-boot.bin的过程 构建u-boot.bin过程分析 makefile一开始,就是确定链接脚本.在构建ubo ...

随机推荐

  1. CountDownLatch(倒计时计数器)使用说明

    方法说明:   public void countDown()      递减锁存器的计数,如果计数到达零,则释放所有等待的线程.如果当前计数大于零,则将计数减少.如果新的计数为零,出于线程调度目的, ...

  2. JS实现各种页面的刷新

    JS实现各种页面的刷新功能 1.刷新当前页面 opener.location.replace(opener.location.href); 或者window.opener.window.locatio ...

  3. 20151225jquery学习笔记---选项卡UI

    圣诞节快乐,哈哈哈....选项卡(tab),是一种能提供给用户在同一个页面切换不同内容的 UI. 尤其是在页面布局紧凑的页面上,提供了非常好的用户体验.一. 使用 tabs使用 tabs 比较简单,但 ...

  4. MyEclipse常见配置及调试

    常见配置 1.配置workspace ----- 建议不要采用含有空格和中文目录 所有代码保存workspace空间中2.新建工程时,设置工程需要jre环境MyEclipse提供多种内置layout ...

  5. iOS 设置图片imageView圆角——对图片进行裁剪

    以前设置图片圆角总是把imageView设置成圆形,然后设置maskToBounds为YES,其实这样处理很消耗性能,图片多了之后比较卡,最好将图片进行裁剪后显示:这里有个分类可以用: UIImage ...

  6. Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGB

    Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGB ...

  7. js 获取时间对象代码

    /** * 获取时间对象 */function getDateObj(addDayCount) { var dd = new Date(); dd.setDate(dd.getDate()+addDa ...

  8. 10.08_逛逛OSC

    (1)每天逛逛OSC是我的习惯了. JNative.JACOB.Shrinkwrap  API? .Lua.WSO2 Identity Server .JBoss Forge.Bugzilla.Cou ...

  9. Leaflet交流

    GIS科研网 Leaflet交流 谢绝转载 http://www.3sbase.com欢迎加群交流  108299288 http://www.3sbase.com/3sbase/webgistest ...

  10. Poj 3061 Subsequence(二分+前缀和)

    Subsequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12333 Accepted: 5178 Descript ...