栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

OpenWrt之跳过tools编译

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

OpenWrt之跳过tools编译

文章目录
    • @[toc]
  • OpenWrt之跳过tools编译
    • 前言
    • 分析代码
    • SDK分析
    • 顶层`Makefile`分析
    • tools/Makefile分析
    • subdir.mk分析
    • host-build.mk分析
    • depends.mk分析
    • 硬改源码
    • 后话
OpenWrt之跳过tools编译
前言

OpenWrt在编译tools这块还是比较费时间, 于是本着缩短编译时间的目的, 想办法使用OpenWrt提供的SDK中已经编译好的tools使用


分析代码

在分析OpenWrt源码的时候, 越分析, 看的代码就越多, 需要懂的知识也就越多, 看得我头都大了, 下面会分成几个模块来发现是如何判断tools是否应该rebuild, 前面废话太多了, 不想看废话 直接快进到 硬改源码


SDK分析

在OpenWrt提供的SDK中, 本文主要用到

  • build_dir
  • staging_dir

这两个文件夹, 里面包含了文本需要用到的tools和toolchain


顶层Makefile分析

这里先讲两个重要的变量, 谨防有人不清楚

  • TOPDIR 这个是顶层路径, 也就是源代码的目录
  • CURDIR 这个是当前路径, 也就是当前文件所在的目录

export PATH:=$(TOPDIR)/staging_dir/host/bin:$(PATH)

下面就导入了一个PATH环境变量$(TOPDIR)/staging_dir/host/bin, 也就是tools的工具目录了


$(toolchain/stamp-compile): $(tools/stamp-compile) $(if $(CONFIG_BUILDBOT),toolchain_rebuild_check)
$(target/stamp-compile): $(toolchain/stamp-compile) $(tools/stamp-compile) $(BUILD_DIR)/.prepared

world的最后, 这里调用了toolchain与tools的时间戳stamp文件生成有关


tools/Makefile分析
tools_enabled = $(foreach tool,$(sort $(tools-y) $(tools-)),$(if $(filter $(tool),$(tools-y)),y,n))
$(eval $(call stampfile,$(curdir),tools,compile,,_$(subst $(space),,$(tools_enabled)),$(STAGING_DIR_HOST)))
$(eval $(call stampfile,$(curdir),tools,check,$(TMP_DIR)/.build,,$(STAGING_DIR_HOST)))

这里也是调用了subdir.mk来生成stamp


subdir.mk分析
ifndef DUMP_TARGET_DB
# Parameters:      
# 1: subdir
# 2: target
# 3: build type
# 4: build variant
# 5: all variants
define stampfile
  $(1)/stamp-$(3):=$(if $(6),$(6),$(STAGING_DIR))/stamp/.$(2)_$(3)$(5)
  $$($(1)/stamp-$(3)): $(TMP_DIR)/.build $(4)
	@+$(SCRIPT_DIR)/timestamp.pl -n $$($(1)/stamp-$(3)) $(1) $(4) || 
		$(MAKE) $(if $(QUIET),--no-print-directory) $$($(1)lags-$(3)) $(1)/$(3)
	@mkdir -p $$$$(dirname $$($(1)/stamp-$(3)))
	@touch $$($(1)/stamp-$(3))

  $$(if $(call debug,$(1),v),,.SILENT: $$($(1)/stamp-$(3)))

  .PRECIOUS: $$($(1)/stamp-$(3)) # work around a make bug

  $(1)//clean:=$(1)/stamp-$(3)/clean
  $(1)/stamp-$(3)/clean: FORCE
	@rm -f $$($(1)/stamp-$(3))

endef
endif

这里还调用了timestamp.pl来生成stamp, 所以大概也了解到OpenWrt是依靠判断stamp来决定是否重新编译tools和toolchain


host-build.mk分析
HOST_STAMP_PREPARED=$(HOST_BUILD_DIR)/.prepared$(if $(HOST_QUILT)$(DUMP),,$(shell $(call find_md5,${CURDIR} $(PKG_FILE_DEPENDS),))_$(call confvar,CONFIG_AUTOREMOVE $(HOST_PREPARED_DEPENDS)))
HOST_STAMP_CONFIGURED:=$(HOST_BUILD_DIR)/.configured
HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.built
HOST_BUILD_PREFIX?=$(if $(IS_PACKAGE_BUILD),$(STAGING_DIR_HOSTPKG),$(STAGING_DIR_HOST))
HOST_STAMP_INSTALLED:=$(HOST_BUILD_PREFIX)/stamp/.$(PKG_NAME)_installed

ifneq ($(if $(HOST_QUILT),,$(CONFIG_AUTOREBUILD)),)
  define HostHost/Autoclean
    $(call rdep,${CURDIR} $(PKG_FILE_DEPENDS),$(HOST_STAMP_PREPARED))
    $(if $(if $(Host/Compile),$(filter prepare,$(MAKECMDGOALS)),1),,$(call rdep,$(HOST_BUILD_DIR),$(HOST_STAMP_BUILT)))
  endef
endif
  • HOST_BUILD_DIR --> build_dir/host/

  • HOST_BUILD_PREFIX --> staging_dir/host/ , 这个在toolchain-build.mk中有定义

大胆猜则, 应该是通过几个隐藏文件来判断tools是否是编译安装好

  • .prepared${md5}_${confvar}
  • .configured
  • .built
  • .$(PKG_NAME)_installed

但是HOST_STAMP_PREPARED中有findmd5和confvar函数, 还有PKG_FILE_DEPENDS和HOST_PREPARED_DEPENDS变量, 还得搞懂是怎么生成.

  • 在rules.mk中, 发现了confvar函数定义
confvar=$(shell echo '$(foreach v,$(1),$(v)=$(subst ',''',$($(v))))' | $(MKHASH) md5)
  • HOST_PREPARED_DEPENDS这玩意好像没在其他地方出现过.
  • PKG_FILE_DEPENDS 在 package/base-files/Makefile中被定义
PKG_FILE_DEPENDS:=$(PLATFORM_DIR)/ $(GENERIC_PLATFORM_DIR)/base-files/
  • $(PLATFORM_DIR) 与GENERIC_PLATFORM_DIR 在 include/target.mk
PLATFORM_DIR:=$(TOPDIR)/target/linux/$(BOARD)
GENERIC_PLATFORM_DIR := $(TOPDIR)/target/linux/generic
  • 传参总结

所以我们find_md5一共传入了三个参数, 分别是${CURDIR}, $(PLATFORM_DIR), $(GENERIC_PLATFORM_DIR)


depends.mk分析
# define a dependency on a subtree
# parameters:
#	1: directories/files
#	2: directory dependency
#	3: tempfile for file listings
#	4: find options

DEP_FINDPARAMS := -x "*/.svn*" -x ".*" -x "*:*" -x "*!*" -x "* *" -x "*\#*" -x "*/.*_check" -x "*/.*.swp" -x "*/.pkgdir*"

find_md5=find $(wildcard $(1)) -type f $(patsubst -x,-and -not -path,$(DEP_FINDPARAMS) $(2)) -printf "%p%T@n" | sort | $(MKHASH) md5

define rdep
  .PRECIOUS: $(2)
  .SILENT: $(2)_check

  $(2): $(2)_check
  check-depends: $(2)_check

ifneq ($(wildcard $(2)),)
  $(2)_check::
	$(if $(3), 
		$(call find_md5,$(1),$(4)) > $(3).1; 
		{ [ ! -f "$(3)" ] || diff $(3) $(3).1 >/dev/null; } && 
	) 
	{ 
		[ -f "$(2)_check.1" ] && mv "$(2)_check.1"; 
	    $(TOPDIR)/scripts/timestamp.pl $(DEP_FINDPARAMS) $(4) -n $(2) $(1) && { 
			$(call debug_eval,$(SUBDIR),r,echo "No need to rebuild $(2)";) 
			touch -r "$(2)" "$(2)_check"; 
		} 
	} || { 
		$(call debug_eval,$(SUBDIR),r,echo "Need to rebuild $(2)";) 
		touch "$(2)_check"; 
	}
	$(if $(3), mv $(3).1 $(3))
else
  $(2)_check::
	$(if $(3), rm -f $(3) $(3).1)
	$(call debug_eval,$(SUBDIR),r,echo "Target $(2) not built")
endif

endef
  • wildcard:扩展通配符, 这里是直接传入三个路径, 不做处理

  • patsubst:替换通配符, 把DEP_FINDPARAMS中-x替换成-and -not -path

  • $(1): 这个传入的是上面三个路径

  • $(2): 空

  • 拆解命令参数

  • 主命令为find

  • 次命令为sort与md5sum(代替scripts/mkhash.c), 计算出find分类之后md5值

find {path1, path2, path3} -type f -and -not -path "*/.svn*" -and -not -path ".*" -and -not -path "*:*" -and -not -path "*!*" -and -not -path "* *" -and -not -path "*\#*" -and -not -path "*/.*_check" -and -not -path "*/.*.swp" -and -not -path "*/.pkgdir" -printf "%p%T@n" | sort | md5sum | awk '{print $1}'

$(call rdep,${CURDIR} $(PKG_FILE_DEPENDS),$(HOST_STAMP_PREPARED))
$(if $(if $(Host/Compile),$(filter prepare,$(MAKECMDGOALS)),1),,$(call rdep,$(HOST_BUILD_DIR),$(HOST_STAMP_BUILT)))

上面的语句,对应着下面的结果

$(call rdep,tools/flock,build_dir/host/flock-2.18/.prepared${find_md5}_${confvar}
$(call rdep,build_dir/host/flock-2.18,build_dir/host/flock-2.18/.built)

分析得头都大了, 搞不下去了, 只能应该源码达到适配效果了

硬改源码

既然他是用md5检测的话, 我也改成md5检测, 就根据tools/xxx文件夹的改动时间取md5做对照就好了, 果断改host-build.mk

源代码:

HOST_STAMP_PREPARED=$(HOST_BUILD_DIR)/.prepared$(if $(HOST_QUILT)$(DUMP),,$(shell $(call find_md5,${CURDIR} $(PKG_FILE_DEPENDS),))_$(call confvar,CONFIG_AUTOREMOVE $(HOST_PREPARED_DEPENDS)))

改动之后:

HOST_STAMP_PREPARED=$(HOST_BUILD_DIR)/.prepared$(shell stat -c %Y ${CURDIR} | $(MKHASH) md5)

这样, 校验方式就变成了我们想要的了


后话

我们把SDK中的staging_dir和build_dir移动到源码目录之后

mkdir -p staging_dir/host/stamp
tools_name="$(ls -F ./tools/ | grep "/$")"
for a in ${tools_name}; do
    if [ "${a}" != 'include/' ]; then
    PKG_NAME=$(cat "./tools/${a}Makefile" | grep '^PKG_NAME' | cut -d '=' -f 2 | sed 's/^[ t]*//g')
    PKG_VERSION=$(cat "./tools/${a}Makefile" | grep '^PKG_VERSION' | cut -d '=' -f 2 | sed 's/^[ t]*//g')

    touch staging_dir/host/stamp/.${PKG_NAME}_installed

    mkdir -p build_dir/host/${PKG_NAME}-${PKG_VERSION}

    prepared_md5=$(stat -c %Y "./tools/${a}" | md5sum | cut -d ' ' -f 1)

    touch build_dir/host/${PKG_NAME}-${PKG_VERSION}/.prepared${prepared_md5}
    touch build_dir/host/${PKG_NAME}-${PKG_VERSION}/.configured
    touch build_dir/host/${PKG_NAME}-${PKG_VERSION}/.built
    
    echo ${PKG_VERSION} >build_dir/host/${PKG_NAME}-${PKG_VERSION}/.version
    echo ${PKG_VERSION} >build_dir/host/${PKG_NAME}-${PKG_VERSION}/.tarball-version

    fi
done

这样就可以跳过tools的编译了, 最简单的方法还是是把所有tools/Makefile里面的tools清空掉


Enjoy it ~~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1038898.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号