主要涉及到两个关键的Makfile,因为这些Makefile的自动化程度不高,所以代码显得很繁琐,但正因为如此,才相对显得比较简单。
首先是asuswrt/release/src-ra-mt7620目录下的Makefile
略去前面的变量定义部分,进入关键的部分:
image目标
image:
@if [ -z "$(BUILD_NAME)" ]; then \
echo "No BUILD_NAME is assigned"; \
exit 1; \
fi
@rm -f image/$(BUILD_NAME)_$(KERNEL_VER).$(FS_VER)_$(SERIALNO).trx
@$(MAKE) -C router image
ifeq ($(CONFIG_RALINK),y)
#开始生成image
else
#非ralink设备,只进行简单的打包
endif
生成image部分没有什么特别的编译行为,但是里面对文件进行相关的打包操作,很有技巧性,值得学习和研究。
内核打包
@rm -rf $(PLATFORMDIR)/zImage.lzma ; \
mipsel-linux-objcopy -O binary $(LINUXDIR)/vmlinux $(PLATFORMDIR)/vmlinus ; \
asustools/lzma -9 -f -c $(PLATFORMDIR)/vmlinus > $(PLATFORMDIR)/zImage.lzma ; \
cp -f $(PLATFORMDIR)/zImage.lzma $(PLATFORMDIR)/zImage.img ; \
首先生成kernel的bin目标文件vmlinus,然后调用lzma进行最高强度的压缩,生成zImage.lzma,最后将文件拷贝到$(PLATFORMDIR)目录,
通过前面的定义
export PLATFORM := mipsel-uclibc
export PLATFORMDIR := $(SRCBASE)/router/$(PLATFORM)
可知,该目录位于router/mipsel-uclibc
对内核进行字节填充
此部分的代码比较多,但是容易理解,用到了shell中的wc、awk、expr、dd、tr等命令,此处不详述,感兴趣的读者可以对照Makefile文件研究。
生成最终的刷机固件
核心代码是调用mkimage命令,生成trx刷机固件文件。
我们知道mkimage需要知道代码的入口点,这个入口点如何用程序获取呢?这个技巧值得我们去学习:
@ENTRY=`LANG=en_US readelf -h $(ROOTDIR)/$(LINUXDIR)/vmlinux | grep "Entry" | awk '{print $$4}'` ; \
ISIZE=`wc -c $(PLATFORMDIR)/zImage.img | awk '{print $$1}'` ; \
KSIZE=`wc -c $(PLATFORMDIR)/zImage.lzma | awk '{print $$1}'` ; \
RSIZE=`wc -c $(PLATFORMDIR)/target.image | awk '{print $$1}'` ; \
PAD2=`expr $${ISIZE} - $${KSIZE} - $${RSIZE}` ; \
RFSOFFSET=`expr 64 + $${KSIZE} + $${PAD2}` ; \
echo "PAD2: $${PAD2}" ; \
asustools/mkimage -A mips -O linux -T kernel -C lzma -a 80000000 -e $${ENTRY} -r $${RFSOFFSET} \
-n $(BUILD_NAME) -V "$(KERNEL_VER)" "$(FS_VER)" "0" "0" "0" "0" "0" "0" "0" "0" \
-d $(PLATFORMDIR)/zImage.img image/$(BUILD_NAME)_$(KERNEL_VER).$(FS_VER)_$(SERIALNO)_$(SWPJVER)$(EXTENDNO).trx ; \
它利用readelf -h,读出vmlinux的header部分信息:
ABI Version: 0
Type: EXEC (Executable file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0x8000c150
Start of program headers: 52 (bytes into file)
Start of section headers: 3445604 (bytes into file)
Flags: 0x70001001, noreorder, o32, mips32r2
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 2
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 18
利用grep "Entry" | awk '{print $$4}',就能获取到入口地址0x8000c150
通配符目标
利用通配符,实现了一些简化的操作,如:
mk-%:
@$(MAKE) -C router $(shell echo $@ | sed s/mk-//)
和:
%: dummy
@[ ! -d router/$* ] || $(MAKE) -C router $@
%-clean: dummy
@-[ ! -d router/$* ] || $(MAKE) -C router $@
%-install: dummy
@[ ! -d router/$* ] || $(MAKE) -C router $* $@
%-stage: dummy
@[ ! -d router/$* ] || $(MAKE) -C router $* $@
%-build: dummy
$(MAKE) $*-clean $*
%-tags: dummy
@[ ! -d router/$* ] || ctags -a -R $(CTAGS_EXCLUDE_OPT) $(SRCBASE)/../src/router/$*
all目标
有意放在最后来介绍,因为此处就要跳转到router目录,进行下一个重要编译过程
all: rt_ver
@echo ""
@echo "Building $(BUILD_NAME)_$(KERNEL_VER).$(FS_VER)_$(SERIALNO).trx"
@echo ""
@echo ""
@-mkdir image
@$(MAKE) -C router all
@$(MAKE) -C router install
@$(MAKE) image
实际上是进入到router目录,对all和install目标进行编译。
我将在下一篇文章中,对router目录中的Makefile进行描述。