目录函数
Tags : Makefileui
本周是成胖子每周一博的第五周.
更好的阅读体验,请点击这里命令行
前一篇博客中,咱们已经知道整个openwrt的编译顺序,本文咱们来探讨与开发者息息相关的单个ipk的编译过程.在开发者进行二次开发的时候,咱们既能够单个编译ipk也能够完整编译整个镜像文件.在完整编译的时候,咱们选中的单个ipk一样会被编入镜像文件中,因此完整编译一样会进行单个ipk包的编译.code
咱们前面在stampfile函数部分提升过,当编译目标为package/stamp-compile的时候,实际执行的目标为package/compile;同时根据subdir函数的定义,package/compile将会依赖于package文件夹下被make menuconfig
选中的子文件夹的compile.简而言之,当咱们执行make package/compile
至关于对全部选中的文件夹执行make package/XXX/compile
.blog
咱们以一个具体的包的编译过程来看看,本文咱们以package/network/services/dropbear这个包为例.当咱们在命令行中输入make package/network/services/dropbear/compile
的时候,make将会读入dropbear下的Makefile文件,同时目标指定为compile.1ip
由于空间问题,我在这里不展开具体的Makefile文件.相信能看这篇博客的同窗应该都有源码,本身打开即是.
下面咱们根据GNU make语法来分析这个Makefile文件.它包含了两个.mk文件:一个是rules.mk,另外一个是package.mk.ci
rules.mk
: 这个文件咱们前文已经提到过了,主要是大量变量的定义.包括各类路径的定义,编译器的定义等等.其中要说明的是.config文件也是这里被包含进来的.开发
package.mk
: 这个文件首先定义和补充了一些变量.其次是openwrt为咱们封装了BuildPackage函数,对于普通开发者而言,只须要参照模板定义相应的变量,最后调用这个函数便可.get
其他的咱们能够认为是变量的赋值语句,很明显使用它们的地方并不在这里.关于模板和变量值的说明及做用.,你能够参照官方说明,也能够在网上找到一大堆资料.编译器
最后,最重要的语句是这一句:
$(eval $(call BuildPackage,dropbear))
这里将会把dropbear做为参数值传给函数BuildPackage
Tips
: 不知道你们还记得咱们Makefile的执行顺序么?Makefile是先读入全部信息,展开,而后生成依赖关系.最后再按依赖关系前后来执行.
BuildPackage的定义在package.mk中,定义以下:
define BuildPackage $(Build/IncludeOverlay) $(eval $(Package/Default)) $(eval $(Package/$(1))) ifdef DESCRIPTION $$(error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description) endif ifndef Package/$(1)/description define Package/$(1)/description $(TITLE) endef endif BUILD_PACKAGES += $(1) $(STAMP_PREPARED): $$(if $(QUILT)$(DUMP),,$(call find_library_dependencies,$(DEPENDS))) $(foreach FIELD, TITLE CATEGORY SECTION VERSION, ifeq ($($(FIELD)),) $$(error Package/$(1) is missing the $(FIELD) field) endif ) $(if $(DUMP), \ $(Dumpinfo/Package), \ $(foreach target, \ $(if $(Package/$(1)/targets),$(Package/$(1)/targets), \ $(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \ ), $(BuildTarget/$(target)) \ ) \ ) $(if $(PKG_HOST_ONLY)$(DUMP),,$(call Build/DefaultTargets,$(1))) endef
那么这里的$(1)就是指的传入的参数dropbear.这里包含了一些检查和补充变量定义.继续深究下去的线索是第25~32行之间.这里我将它简化后就是展开BuildTarget/ipkg;同时第33行,将dropbear看成参数传给函数Build/DefaultTargets.
BuildTarget/ipkg定义在package-ipkg.mk中,咱们须要重点关注其中的冒号,这个造成咱们的依赖关系.
Build/DefaultTargets定义在package.mk中,其中造成了咱们stamp-*的依赖关系.根据这些依赖关系,我将关系图绘制以下:
当咱们得出依赖关系后,执行过程就是倒序进行而已,即从上图的右边向左执行.这也能够和咱们预料的执行过程相印证.
$(stamp-prepared)
: 主要完成代码包的准备工做,若是开发者定义了build/prepare,则执行build/prepare.若是开发者未定义,则执行build/prepare/default这其中包含了多个情形,最为常见的是将dl下的压缩包解压并打上patch.
$(stamp-built)
: 这个将会进入到build_dir/target-XXX/下对应的文件夹进行编译.同时将会带入一些定义好的变量.好比CFLAGS,LDFLAGS.
IPKG_(1)
: 这个目标将会将编译好的文件安装到对应的ipkg-arch目录下,同时将这个目录打包为ipk文件.
本周博客基本就到这里,原本私心想着元旦没啥大事,能够写两篇的.结果混着混着就到第三天晚上了.剩下的最后一篇咱们看看单个的ipk编译好了,内核的编译过程,最后的打包过程.整个镜像文件由哪些部分组成.下周再见.
所有过程分析请参见前文,至少还应包含必要的检查,tools和toolchain的编译.这里由于咱们主要分析单个ipk的编译过程,因此我将之略过↩