OpenWRT scan.mk
简述
单纯分析scan.mk太死板,本文以make命令的执行过程重点说明scan.mk的工作机制,总体来说,scan.mk用于扫描package和target目录, 生成用于menuconfig的Config.in文件和其他临时信息
Makefile
根据Mafile分析我们知道,Make最终的目标如下:
# SDK相关我们忽略
ifeq ($(SDK),1)
%::
@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq
@./scripts/config/conf --defconfig=.config Config.in
@+$(ULIMIT_FIX) $(SUBMAKE) -r $@
else
%::
@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq, #通过这一行行我们知道我们需要先执行prereq目标对应的依赖和命令, preqre定义在在topdir.mk中
@( \
cp .config tmp/.config; \
./scripts/config/conf --defconfig=tmp/.config -w tmp/.config Config.in > /dev/null 2>&1; \
if ./scripts/kconfig.pl '>' .config tmp/.config | grep -q CONFIG; then \
printf "$(_R)WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!$(_N)\n" >&2; \
fi \
)
@+$(ULIMIT_FIX) $(SUBMAKE) -r $@ $(if $(WARN_PARALLEL_ERROR), || { \
printf "$(_R)Build failed - please re-run with -j1 to see the real error message$(_N)\n" >&2; \
false; \
} )
endif
Make preqreq
# 我们依赖与prepare-tmpinfo和.config文件,.config依赖script/config/conf程序,
# 通过defconfig或者menuconfig生成TOPDIR下的.config,我们重点分析prepare-tmpinfo命令
prereq:: prepare-tmpinfo .config 170
@+$(NO_TRACE_MAKE) -r -s $@
Make prepare-tmpinfo
prepare-tmpinfo: FORCE
@+$(MAKE) -r -s staging_dir/host/.prereq-build $(PREP_MK)
mkdir -p tmp/info
make -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPS="$(TOPDIR)/include/package*.mk $(TOPDIR)/overlay/*/*.mk" SCAN_DEPTH=5 SCAN_EXTRA=""
make -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" SCAN_DEPS="profiles/*.mk $(TOPDIR)/include/kernel*.mk $(TOPDIR)/include/target.mk" SCAN_DEPTH=2 SCAN_EXTRA="" SCAN_MAKEOPTS="TARGET_BUILD=1"
for type in package target; do \ #生成tmp/.config-package.in和tmp/.config-target.in用于menuconfig图形化配置
f=tmp/.$${type}info; t=tmp/.config-$${type}.in; \
[ "$$t" -nt "$$f" ] || ./scripts/metadata.pl $${type}_config "$$f" > "$$t" || { rm -f "$$t"; echo "Failed to build $$t"; false; break; }; \
done
[ tmp/.config-feeds.in -nt tmp/.packagefeeds ] || ./scripts/feeds feed_config > tmp/.config-feeds.in
./scripts/metadata.pl package_mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
./scripts/metadata.pl package_feeds tmp/.packageinfo > tmp/.packagefeeds || { rm -f tmp/.packagefeeds; false; }
touch $(TOPDIR)/tmp/.build
scan.mk
终于看到scan.mk被调用的地方,先看看scan.mk的源码
在分析之前我们可以知道,通过调用scan.mk传递的变量如下
1, SCAN_TARGET = "packageinfo"
2, SCAN_DIR = "package"
3, SCAN_NAME = "package"
4, SCAN_DEPENDS = "$(TOPDIR)/include/package*.mk $(TOPDIR)/overlay/*/*.mk"
5, SCAN_DEPETH = 5
6, SCAN_EXTRA = ""
include $(TOPDIR)/include/verbose.mk
TMP_DIR:=$(TOPDIR)/tmp
#替换一下; all: tmp/.packageinfo
all: $(TMP_DIR)/.$(SCAN_TARGET)
include $(TOPDIR)/include/host.mk
SCAN_TARGET ?= packageinfo
SCAN_NAME ?= package
SCAN_DIR ?= package
# TARGET_STAMP = tmp/info/.files-packgeinfo.stamp
# SCAN_COOKIE?=$(shell echo $$$$)表示当前make的进程号,FILELIST = tmp/info/.files-packageinfo-xxxx
# OVERRIDELIST = tmp/info/.overrides-packageinfo-xxxx
TARGET_STAMP:=$(TMP_DIR)/info/.files-$(SCAN_TARGET).stamp
FILELIST:=$(TMP_DIR)/info/.files-$(SCAN_TARGET)-$(SCAN_COOKIE)
OVERRIDELIST:=$(TMP_DIR)/info/.overrides-$(SCAN_TARGET)-$(SCAN_COOKIE) # OVER
ifeq ($(IS_TTY),1)
define progress
printf "\033[M\r$(1)" >&2;
endef
else
define progress
:;
endef
endif
define feedname
$(if $(patsubst feeds/%,,$(1)),,$(word 2,$(subst /, ,$(1))))
endef
# 以$(eval $(call PackageDir,base-files,base-files,))为例展开如下:
# tmp/.packageinfo : tmp/info/.packageinfo-base-files
# tmp/info/.packageinfo-base-files: package/base-files/Makefile ...产生依赖
# $(call progress, Collecting package info: package/base-files) \
# echo Source-Makefile: package/base-files/Makefile
# make -r DUMP=1 FEED= -C package/base-files $(SCAN_MAKEOPTS) 2>/dev/null > tmp/info/.packageinfo-base-files
# 如果发生错误则记录错误到logs/package/base-files/dump.txt中
# 生成的tmp/info/.packageinfo-base-files内容如下:
-------------------------------------------------------------------------
tmp/info/.packageinfo-base-files
1 Source-Makefile: package/base-files/Makefile
2 Package: base-files
3 Version: 157.2-unknown
4 Depends: +libc +SSP_SUPPORT:libssp +USE_GLIBC:librt +USE_GLIBC:libpthread +netifd +procd +jsonfilter +SIGNED_PACKAGES:usign
5 Conflicts:
6 Menu-Depends:
7 Provides:
8 Build-Depends: opkg/host usign/host
9 Section: base
10 Category: Base system
11 Title: Base filesystem for OpenWrt
12 Maintainer:
13 Source:
14 License: GPL-2.0
15 Type: ipkg
16 Description: This package contains a base filesystem and system scripts for OpenWrt.
17 http://openwrt.org/
18
19 @@
-------------------------------------------------------------------------
define PackageDir
$(TMP_DIR)/.$(SCAN_TARGET): $(TMP_DIR)/info/.$(SCAN_TARGET)-$(1)
$(TMP_DIR)/info/.$(SCAN_TARGET)-$(1): $(SCAN_DIR)/$(2)/Makefile $(SCAN_STAMP) $(foreach DEP,$(DEPS_$(SCAN_DIR)/$(2)/Makefile) $(SCAN_DEPS),$(wildcard $(if $(filter /%,$(DEP)),$(DEP),$(SCAN_DIR)/$(2)/$(DEP))))
{ \
$$(call progress,Collecting $(SCAN_NAME) info: $(SCAN_DIR)/$(2)) \
echo Source-Makefile: $(SCAN_DIR)/$(2)/Makefile; \
$(if $(3),echo Override: $(3),true); \
$(NO_TRACE_MAKE) --no-print-dir -r DUMP=1 FEED="$(call feedname,$(2))" -C $(SCAN_DIR)/$(2) $(SCAN_MAKEOPTS) 2>/dev/null || { \
mkdir -p "$(TOPDIR)/logs/$(SCAN_DIR)/$(2)"; \
$(NO_TRACE_MAKE) --no-print-dir -r DUMP=1 FEED="$(call feedname,$(2))" -C $(SCAN_DIR)/$(2) $(SCAN_MAKEOPTS) > $(TOPDIR)/logs/$(SCAN_DIR)/$(2)/dump.txt 2>&1; \
$$(call progress,ERROR: please fix $(SCAN_DIR)/$(2)/Makefile - see logs/$(SCAN_DIR)/$(2)/dump.txt for details\n) \
rm -f $$@; \
}; \
echo; \
} > $$@ || true
endef
$(OVERRIDELIST):
rm -f $(TMP_DIR)/info/.overrides-$(SCAN_TARGET)-*
touch $@
ifeq ($(SCAN_NAME),target)
GREP_STRING=BuildTarget
else
GREP_STRING=(Build/DefaultTargets|BuildPackage|.+Package)
endif
#FILELIST为tmp/info/.files-packageinfo-xxx
#FILELIST依赖与OVERRIDELIST, OVERRIDELIST如上,删除旧的/tmp/info/.overrides-packageinfo-*, 重建新的tmp/info/.overrides-packageinfo-xxxx
#依赖处理完成后,执行删除tmp/info/.file-packageinfo-*的所有文件,如/tmp/info/.files-packageinfo-59016
$(FILELIST): $(OVERRIDELIST)
rm -f $(TMP_DIR)/info/.files-$(SCAN_TARGET)-*
# 翻译一下下面的语句:
# find -L package -mindepth 1 -maxdepth 5 -name Makefile | xargs grep -aHE "(Build/DefaultTargets|BuildPackage|.+Package)" | \
# sed -e 's#^package/##' -e 's#/Makefile:.*##' | uniq | awk -v of=/tmp/gg -f include/scan.awk > tmp/info/.files-packageinfo-xxxx
# 生成的文件如下
-------------------------------------------------------------------------
utils/px5g-standalone
utils/robocfg
utils/spidev_test
utils/ubi-utils
utils/ugps
utils/usbmode
utils/usbreset
utils/usbutils
utils/util-linux
utils/xfsprogs
feeds/alljoyn/alljoyn
feeds/alljoyn/alljoyn-config
feeds/alljoyn/alljoyn-controlpanel
feeds/alljoyn/alljoyn-notification
feeds/alljoyn/alljoyn-onboarding
feeds/alljoyn/alljoyn-sample_apps
feeds/alljoyn/alljoyn-services_common
feeds/bluetopia/bluetopia
-------------------------------------------------------------------------
$(call FIND_L, $(SCAN_DIR)) $(SCAN_EXTRA) -mindepth 1 $(if $(SCAN_DEPTH),-maxdepth $(SCAN_DEPTH)) -name Makefile | \
xargs grep -aHE 'call $(GREP_STRING)' | sed -e 's#^$(SCAN_DIR)/##' -e 's#/Makefile:.*##' | uniq | awk -v of=$(OVERRIDELIST) -f include/scan.awk > $@
# tmp/info/.files-packageinfo.mk: tmp/info/.files-packageinfo-xxxx
# 通过脚本生成/tmp/info/.files-packageinfo.mk, 生成的文件内容如下:
-------------------------------------------------------------------------
1 DEPS_package/firmware/linux-firmware/Makefile=*.mk
2 DEPS_package/kernel/linux/Makefile=modules/*.mk $(TOPDIR)/target/linux/*/modules.mk $(TOPDIR)/include/netfilter.mk
3 $(eval $(call PackageDir,base-files,base-files,))
4 $(eval $(call PackageDir,boot_apex,boot/apex,))
-------------------------------------------------------------------------
$(TMP_DIR)/info/.files-$(SCAN_TARGET).mk: $(FILELIST)
( \
cat $< | awk '{print "$(SCAN_DIR)/" $$0 "/Makefile" }' | xargs grep -HE '^ *SCAN_DEPS *= *' | awk -F: '{ gsub(/^.*DEPS *= */, "", $$2); print "DEPS_" $$1 "=" $$2 }'; \
awk -F/ -v deps="$$DEPS" -v of="$(OVERRIDELIST)" ' \
BEGIN { \
while (getline < (of)) \
override[$$NF]=$$0; \
close(of) \
} \
{ \
info=$$0; \
gsub(/\//, "_", info); \
dir=$$0; \
pkg=""; \
if($$NF in override) \
pkg=override[$$NF]; \
print "$$(eval $$(call PackageDir," info "," dir "," pkg "))"; \
} ' < $<; \
true; \
) > $@
-include $(TMP_DIR)/info/.files-$(SCAN_TARGET).mk #include tmp/info/.files-packageinfo.mk
# 第一条命令重建FILELIST, FILELIST重建完成后的文件为tmp/info/.files-packageinfo-xxxx
# 然后将此文件进行md5sum计算,删除文件tmp/info/.files-packgeinfo.stamp*
# 重建建立文件tmp/info/.files-packageinfo.stamp和tmp/info/.files-packageinfo.stamp.$(md5sums FILELIST)文件
$(TARGET_STAMP)::
+( \
$(NO_TRACE_MAKE) $(FILELIST); \
MD5SUM=$$(cat $(FILELIST) $(OVERRIDELIST) | (md5sum || md5) 2>/dev/null | awk '{print $$1}'); \
[ -f "$@.$$MD5SUM" ] || { \
rm -f $@.*; \
touch $@.$$MD5SUM; \
touch $@; \
} \
)
# tmp/.packageinfo最终目标,依赖$(TARGET_STAMP) = tmp/info/.files-packgeinfo.stamp $(SCAN_STAMP)为空
# 合并tmp/info/.packageinfo-base-files ...等所有的软件包到/tmp/.packageinfo中形成最终的文件
# 内容如下:
-------------------------------------------------------------------------
1 Source-Makefile: package/base-files/Makefile
2 Package: base-files
3 Version: 157.2-unknown
4 Depends: +libc +SSP_SUPPORT:libssp +USE_GLIBC:librt +USE_GLIBC:libpthread +netifd +procd +jsonfilter +SIGNED_PACKAGES:usign
5 Conflicts:
6 Menu-Depends:
7 Provides:
8 Build-Depends: opkg/host usign/host
9 Section: base
10 Category: Base system
11 Title: Base filesystem for OpenWrt
12 Maintainer:
13 Source:
14 License: GPL-2.0
15 Type: ipkg
16 Description: This package contains a base filesystem and system scripts for OpenWrt.
17 http://openwrt.org/
18
19 @@
20
21
22 Source-Makefile: package/boot/apex/Makefile
23 Package: apex
24 Default: y
25 Version: 1.6.9-1
26 Depends: +libc +SSP_SUPPORT:libssp +USE_GLIBC:librt +USE_GLIBC:libpthread @TARGET_ixp4xx
27 Conflicts:
28 Menu-Depends:
29 Provides:
30 Section: boot
31 Category: Boot Loaders
32 Title: Boot loader for NSLU2, FSG3, NAS100D and others
33 Maintainer:
34 Source: apex-1.6.9.tar.gz
35 Type: bin
36 Description: Boot loader for NSLU2, FSG3, NAS100D and others
37 http://wiki.buici.com/wiki/Apex_Bootloader
38
39 @@
-------------------------------------------------------------------------
# SCAN_TARGET = packageinfo
# TARGET_STAMP = tmp/info/.files-packgeinfo.stamp
# SCAN_STAMP为空
$(TMP_DIR)/.$(SCAN_TARGET): $(TARGET_STAMP) $(SCAN_STAMP)
$(call progress,Collecting $(SCAN_NAME) info: merging...)
-cat $(FILELIST) | awk '{gsub(/\//, "_", $$0);print "$(TMP_DIR)/info/.$(SCAN_TARGET)-" $$0}' | xargs cat > $@ 2>/dev/null
$(call progress,Collecting $(SCAN_NAME) info: done)
echo
FORCE:
.PHONY: FORCE
.NOTPARALLEL:
总结:
1,当我们输入make命令时,Makefile进入第一个分支并执行make -r -s prereq进行准备
2,make -r -s prereq 会进行prepare-tmpinfo
目标执行和.config文件的准备
3,prepare-tmpinfo会传递参数并制定scan.mk进行工作(后面以package目录为例)
4,prepare-tmpinfo的最终目标是tmp/.packageinfo,其依赖tmp/info/.files-packageinfo.stamp(此文件为空文件,仅用于记录更新时间戳)
tmp/.packageinfo的内容为:包含了所有系统内的软件包信息,包括feeds,这些文件是有tmp/info/.packageinfo-base-files这些文件合成一个文件形成
1 Source-Makefile: package/base-files/Makefile 2 Package: base-files 3 Version: 157.2-unknown 4 Depends: +libc +SSP_SUPPORT:libssp +USE_GLIBC:librt +USE_GLIBC:libpthread +netifd +procd +jsonfilter +SIGNED_PACKAGES:usign 5 Conflicts: 6 Menu-Depends: 7 Provides: 8 Build-Depends: opkg/host usign/host 9 Section: base 10 Category: Base system 11 Title: Base filesystem for OpenWrt 12 Maintainer: 13 Source: 14 License: GPL-2.0 15 Type: ipkg 16 Description: This package contains a base filesystem and system scripts for OpenWrt. 17 http://openwrt.org/ 18 19 @@ 20 21 22 Source-Makefile: package/boot/apex/Makefile 23 Package: apex 24 Default: y 25 Version: 1.6.9-1 26 Depends: +libc +SSP_SUPPORT:libssp +USE_GLIBC:librt +USE_GLIBC:libpthread @TARGET_ixp4xx 27 Conflicts:
5, tmp/info/.files-packageinfo.stamp是一个双引号目标,会永远被执行,
这个文件主要生成FILELIST文件(tmp/info/.files-packageinfo-xxxx),tmp/info/.files-packageinfo.stamp,tmp/info/.files-packageinfo.stamp.$(md5sums FILELIST)
tmp/info/.files-packageinfo.stamp,tmp/info/.files-packageinfo.stamp.$(md5sums FILELIST)都没有实际内容,仅用于记录时间戳
FILELIST(tmp/info/.files-packageinfo-xxxx)的格式为,是系统所有软件包的列表:
utils/px5g-standalone utils/robocfg utils/spidev_test utils/ubi-utils utils/ugps utils/usbmode utils/usbreset utils/usbutils utils/util-linux utils/xfsprogs feeds/alljoyn/alljoyn feeds/alljoyn/alljoyn-config feeds/alljoyn/alljoyn-controlpanel feeds/alljoyn/alljoyn-notification feeds/alljoyn/alljoyn-onboarding feeds/alljoyn/alljoyn-sample_apps feeds/alljoyn/alljoyn-services_common feeds/bluetopia/bluetopi
6,目标tmp/info/.files-packageinfo.mk: tmp/info/.files-packageinfo-xxxx根据规则生成如下文件
1 DEPS_package/firmware/linux-firmware/Makefile=*.mk 2 DEPS_package/kernel/linux/Makefile=modules/*.mk $(TOPDIR)/target/linux/*/modules.mk $(TOPDIR)/include/netfilter.mk 3 $(eval $(call PackageDir,base-files,base-files,)) 4 $(eval $(call PackageDir,boot_apex,boot/apex,)) PackageDir展开如下 tmp/.packageinfo : tmp/info/.packageinfo-base-files tmp/info/.packageinfo-base-files: package/base-files/Makefile ...产生依赖 $(call progress, Collecting package info: package/base-files) \ echo Source-Makefile: package/base-files/Makefile make -r DUMP=1 FEED= -C package/base-files $(SCAN_MAKEOPTS) 2>/dev/null > tmp/info/.packageinfo-base-files
7,tmp/info/.packageinfo-base-files文件的格式为:
1 Source-Makefile: package/base-files/Makefile 2 Package: base-files 3 Version: 157.2-unknown 4 Depends: +libc +SSP_SUPPORT:libssp +USE_GLIBC:librt +USE_GLIBC:libpthread +netifd +procd +jsonfilter +SIGNED_PACKAGES:usign 5 Conflicts: 6 Menu-Depends: 7 Provides: 8 Build-Depends: opkg/host usign/host 9 Section: base
8,然后toplevel.mk的prepare-tmpinfo目标中使用scripts/metadata.pl生成tmp/.config-package.in和tmp/.config-target.in用于进行menuconfig的配置,并使用此脚本生成tmp/.config-feeds.in,tmp/.packagedeps,tmp/.packagefeeds
tmp/.packageinfo包含了所有软件信息
tmp/info/.files-packageinfo-xxxx 软件的简单列表文件
tmp/info/.files-packageinfo.stamp 空文件,仅用于记录时间戳
tmp/info/.files-packageinfo.stamp.$(md5sums tmp/info/.files-packageinfo-xxxx)用于记录软件是否发生变化
tmp/info/.packaginfo-base-files 单一软件的详细信息,有多少软件就有多少文件
tmp/info/.files-packageinfo.mk 临时Makefile主要用于产生tmp/info/.packaginfo-base-files的依赖
以base-files为例,其依赖关系为
world: prepare-tmpinfo
prepare-tmpinfo:FORCE
make -f include/scan.mk,scan.mk的终极目标为tmp/.packageinfo
tmp/.packageinfo: tmp/info/.files-packageinfo.stamp
tmp/info/.files-packageinfo.stamp::
tmp/info/.files-packageinfo-xxxx 一个简单的软件列表
touch tmp/info/.files-packageinfo.stamp
touch tmp/info/.files-packageinfo.stamp.$(md5sum tmp/info/.files-packageinfo-xxxx)
tmp/info/.files-packageinfo.mk: tmp/info/.files-packageinfo-xxxx
本文原创,转载请注明出处 !
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律