makefile自动切割资源文件

曾经,有个项目,资源文件过大,mod+所有资源+sig+mif文件超过1.5MB(日本kddi有这方面限制),又不允许使用mod压缩的方法(该方法有些非常非常小的缺陷),他们说,随着mod附带一部分资源,剩下的资源文件在线下载吧。
听起来很简单,不就是把资源文件分割掉,放到网上去么,事实的情况是:程序中要知道随着mod附带了多少资源;总共有多少的资源包没有下载;下载了的资源包是否有损坏;网络通讯中间是否有错误;网络下载是否当天超过了6MB;本程序当天下载是否超过了3MB,(3MB和6MB等都是kddi的规定);下载完成之后,中间某个资源包错误之后,程序需要判断是哪一个,并且重新下载;包的分割多大为合适(用户不会希望等半天都没有进度显示);程序需要计算剩余多少没有下载。
一句话引发了一场灾难,我的项目都是使用make来编译的,资源使用make来整理的,如果make能帮我自动计算并分割,那我将会省很多事情。我很庆幸自己用命令行的方式,如果用IDE的方式,每次的更改将会是一场灾难。于是就写了下面的makefile:

OBJ=test.bin
SPLIT_SIZE=262144
OUT_DIR=out
DIST_DIR?=ready_packet
OUTFILE?=
SKIP_SIZE?=0
SIZE?=0
CRC?=0
IN_FILE?=
PACKAGE_SIZE?=1572864
POSITION?=
LENGTH?=
H_FILE=../project/source/cpp/spdata/download_data.h
ZIP=../../Tool/7z.exe
FILE_SIZE=$(word 5, $(shell ls -l $(OBJ) ))

cutfile= $($(call mvfile, $(3), $(4) ) && $(shell dd if=$(3) of=$(4) bs=1 count=$(call exprsize, $(2), -, $(1) ) skip=$(1) ) )
all:
	rm -drf $(DIST_DIR)
	mkdir -p $(DIST_DIR)
	make do_all
#	rm -drf $(OBJ)

clean:
	rm -drf  $(OUT_DIR)

otherres1:
	rm -drf $(OUT_DIR)
	mkdir -p $(OUT_DIR)
	@echo do all
	INDEX=0;PACKAGE_SIZE=$(PACKAGE_SIZE);NAME=0;SKIP_SIZE=0;while [[ "$$SKIP_SIZE" -lt $(FILE_SIZE) ]]; \
	do \
	echo "skip_size=$$SKIP_SIZE"; \
	let "skip_block=NAME";\
	make split1 OUTFILE="$(OUT_DIR)/$(basename $(OBJ))_"$$NAME".bin" SKIP_SIZE=$$skip_block;\
	let "SKIP_SIZE+=$(SPLIT_SIZE)"; \
	echo "skip_size=$$SKIP_SIZE"; \
	let "NAME+=1";\
	done;\
	let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/res.bin\"|gawk '{print $$2}'`"; \
	while [[ "$$INDEX" -lt "$$NAME" ]]; \
	do \
	let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/$(basename $(OBJ))_\"$$INDEX\".bin\"|gawk '{print $$2}'`"; \
	if [[ "$$PACKAGE_SIZE" -lt 0 ]]; \
	then \
	break; \
	fi; \
	cat "$(OUT_DIR)/$(basename $(OBJ))_"$$INDEX".bin" >> $(OUT_DIR)/res.bin; \
	let "INDEX+=1"; \
	done;\
	mkdir -p $(DIST_DIR)
#	cp -f $(OUT_DIR)/res.bin $(DIST_DIR)/res.bin
	cp -f $(OBJ) $(DIST_DIR)/res.bin

otherres:
	rm -drf $(OUT_DIR)
	mkdir -p $(OUT_DIR)
	@echo do all
	INDEX=0;PACKAGE_SIZE=$(PACKAGE_SIZE);NAME=0;SKIP_SIZE=0;while [[ "$$SKIP_SIZE" -lt $(FILE_SIZE) ]]; \
	do \
	echo "skip_size=$$SKIP_SIZE"; \
	let "skip_block=NAME";\
	make split1 OUTFILE="$(OUT_DIR)/$(basename $(OBJ))_"$$NAME".bin" SKIP_SIZE=$$skip_block;\
	let "SKIP_SIZE+=$(SPLIT_SIZE)"; \
	echo "skip_size=$$SKIP_SIZE"; \
	let "NAME+=1";\
	done;\
	let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/res.bin\"|gawk '{print $$2}'`"; \
	while [[ "$$INDEX" -lt "$$NAME" ]]; \
	do \
	let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/$(basename $(OBJ))_\"$$INDEX\".bin\"|gawk '{print $$2}'`"; \
	if [[ "$$PACKAGE_SIZE" -lt 0 ]]; \
	then \
	break; \
	fi; \
	cat "$(OUT_DIR)/$(basename $(OBJ))_"$$INDEX".bin" >> $(OUT_DIR)/res.bin; \
	let "INDEX+=1"; \
	done;\
	mkdir -p $(DIST_DIR)
	cp -f $(OUT_DIR)/res.bin $(DIST_DIR)/res.bin
#	cp -f $(OBJ) $(DIST_DIR)/res.bin



split1:
	@echo "split1 from $(SKIP_SIZE) size=$(SPLIT_SIZE)"
	dd if=$(OBJ) of=$(OUTFILE).tmp bs=$(SPLIT_SIZE) count=1 skip=$(SKIP_SIZE)
#	$(ZIP) -tgzip a $(OUTFILE).tmp1 $(OUTFILE).tmp
#	rm -f $(OUTFILE).tmp1
	make insert1 OUTFILE=$(OUTFILE) IN_FILE=$(OUTFILE).tmp POSITION=$(SKIP_SIZE) `cksum $(OUTFILE).tmp|gawk '{print "CRC="$$1,"SIZE="$$2}'`
	rm -f $(OUTFILE).tmp
insert1:	
	@echo "make insert1 $(OUTFILE) $(IN_FILE) $(CRC) $(SIZE) $(POSITION)"
#	make writehex OUTFILE=$(OUT_DIR)/res.bin SIZE=$(POSITION)	 
#	make writehex OUTFILE=$(OUT_DIR)/res.bin SIZE=$(SIZE)
#	make writehex OUTFILE=$(OUT_DIR)/res.bin SIZE=$(CRC)
	cat $(IN_FILE) >> $(OUTFILE)

do_all:
	@echo do all
	cd res/data && make clean && make
	mv stdata_sd.bin ready_packet/res.bin
	echo -e "#include \"define.h\"\nstatic _CONST_ int FILE_ARRAY[]= {" > $(H_FILE); NAME=0;SKIP_SIZE=0;while [[ "$$SKIP_SIZE" -lt $(FILE_SIZE) ]]; \
	do \
	echo "skip_size=$$SKIP_SIZE"; \
	let "skip_block=NAME";\
	make split OUTFILE="$(DIST_DIR)/$(basename $(OBJ))_"$$NAME".bin" SKIP_SIZE=$$skip_block;\
	let "SKIP_SIZE+=$(SPLIT_SIZE)"; \
	echo "skip_size=$$SKIP_SIZE"; \
	let "NAME+=1";\
	done; \
	echo -e "};\n#define NET_ALL_FILE_NUM $$NAME\n#define BLOCK_SIZE $(SPLIT_SIZE)\n#define FILE_SIZE $(FILE_SIZE)" >> $(H_FILE)
	

split:
	@echo "split from $(SKIP_SIZE) size=$(SPLIT_SIZE)"
	dd if=$(OBJ) of=$(OUTFILE).tmp bs=$(SPLIT_SIZE) count=1 skip=$(SKIP_SIZE)
#	$(ZIP) -tgzip a $(OUTFILE).tmp1 $(OUTFILE).tmp
#	rm -f $(OUTFILE).tmp1
	make insert OUTFILE=$(OUTFILE) IN_FILE=$(OUTFILE).tmp `cksum $(OUTFILE).tmp|gawk '{print "CRC="$$1,"SIZE="$$2}'`
	rm -f $(OUTFILE).tmp

insert:	
	@echo "make insert $(OUTFILE) $(IN_FILE) $(CRC) $(SIZE)"	 
	make writehex OUTFILE=$(OUTFILE) SIZE=$(SIZE)
	make writehex OUTFILE=$(OUTFILE) SIZE=$(CRC)
	cat $(IN_FILE) >> $(OUTFILE)
	echo -e " $(SIZE), $(CRC)," >> $(H_FILE)

writehex:
	COUNT=4;_SIZE=$(SIZE);while [[ "$$COUNT" -gt 0 ]];\
	do \
	let "_OUT=_SIZE%256";\
	let "_SIZE=_SIZE/256";\
	let "COUNT-=1";\
	TST=(`echo $$_OUT|gawk '{printf "%x", $$0}'`); \
	OUT="\\x$$TST"; \
	printf $$OUT >> $(OUTFILE);\
	done;
       

上面的代码应该是可以运行的,记忆有些模糊,因为最终,他们又同意mod压缩方法了,上面的代码就完全白费了。只能感叹,中国的人力资源真便宜。
实际上,在调用的时候要调用上面的makefile文件两次,第一次是在代码编译之前,生成.h文件。使用

       make DIST_DIR=net
       

的方式调用。
第二次的调用在代码编译之后,打包资源的时候,需要计算剩余可用的容量,然后打包整理,我是这样调用的:

     	PACKAGE_SIZE=0; for i in $(RES) ; \
	do \
	echo "i=$$i"; \
	let "PACKAGE_SIZE+=`cksum \"$(RESDIR)/$$i\"|gawk '{print $$2}'`"; \
	done; \
	let "PACKAGE_SIZE+=`cksum \"$(RELEASE_DIR)/$(PLAT)/$(P)/$(TARGET)/$(TARGET).$(MODULE)\"|gawk '{print $$2}'`"; \
	let "PACKAGE_SIZE+=`cksum \"$(RELEASE_DIR)/$(PLAT)/$(P)/$(TARGET).mif\"|gawk '{print $$2}'`"; \
	let "PACKAGE_SIZE+=4096"; \
	let "PACKAGE_SIZE=$(MAX_SIZE)-PACKAGE_SIZE"; \
	cd resource && make otherres PACKAGE_SIZE=$$PACKAGE_SIZE && make clean
	cp -f $(RESDIR)/res.bin $(RELEASE_DIR)/$(PLAT)/$(P)/$(TARGET)/res.bin
    

测试这边,在国内没办法使用网络下载,所以,我顺便又调用那个makefile一次,生成测试那边可以用的资源,就像他们已经下载完成了那样:

    cd resource && make otherres1 PACKAGE_SIZE=20971520 DIST_DIR=smc && make clean
    

上面的脚本执行起来比较慢,没有30分钟是搞不定的。但如果手动的话,即使快,又没办法做到自动,况且还需要添加crc校验,长度校验,因此,我个人认为,这个是可以接受的。不幸的是,项目中最后完全没有用到,不过,最后却又省了很多麻烦事,何况,自己写的代码到最后没有用处的也不在少数。

发布者

rix

如果连自己都不爱自己,哪还有谁来爱你