Openwrt
使用make meunconfig命令,发现menuconfig目标在include/toplevel.mk文件中,如下:
menuconfig:scripts/config/mconf prepare-tmpinfo FORCE
if [ \! -e .config -a -e$(HOME)/.openwrt/defconfig ]; then \
cp $(HOME)/.openwrt/defconfig.config; \
fi
$< Config.in
可以看出menuconfig依赖于scripts/config/mconf和prepare-tmpinfo、FORCE
接下来的命令:
if[ \! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then \
cp $(HOME)/.openwrt/defconfig.config; \
fi
表示如果.config文件存在且$(HOME)/.openwrt/defconfig文件存在,就cp $(HOME)/.openwrt/defconfig .config;
最后一句命令行:$< Config.in
$<表示所有依赖目标的第一个目标,这里即为scripts/config/mconf,故这里的命令行翻译过来即为:scripts/config/mconfConfig.in,通过在命令窗口执行该句命令,可以看到该命令的执行效果即为make menuconfig出来的配置窗口,如下图:
接下来来看一下另外一个依赖目标prepare-tmpinfo
该目标prepare-tmpinfo就在toplevel.mk中,如下:
prepare-tmpinfo:FORCE
mkdir -p tmp/info
$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -finclude/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=""
$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -finclude/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 \
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
./scripts/metadata.pl package_mktmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
touch $(TOPDIR)/tmp/.build
首先看一下2个变量:$(_SINGLE)和$(NO_TRACE_MAKE),$(_SINGLE)定义在主Makefile中,在第一次进入到主Makefile中定义,如下:
empty:=
space:= $(empty) $(empty)
_SINGLE=export MAKEFLAGS=$(space);
empty和space合起来定义出space变量的值为一个空格。
_SINGLE的作用就是export MAKEFLAGS,以便后面的Makefile引用;
$(NO_TRACE_MAKE)定义在include/verbose.mk文件中,定义如下:
ifeq($(NO_TRACE_MAKE),)
NO_TRACE_MAKE:= $(MAKE) V=s$(OPENWRT_VERBOSE)
exportNO_TRACE_MAKE
endif
翻译过来就来是NO_TRACE_MAKE=makeV=s$(OPENWRT_VERBOSE)
再来看目标prepare-tmpinfo,有一个依赖目标FORCE,接下来是命令行
第一句话mkdir -p tmp/info,首先创建一个tm/info文件夹;
接下来的命令行翻译过来如下:
makeV=sX -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=""
选项-j1为一次同时运行一个命令;
选项-r为禁止使用任何隐含规则;
选项-s为在命令运行时不输出命令的结果;
选项-f include/scan.mk为指定需要执行的makefile为include/scan.mk;
后面SCAN_TARGET、SCAN_DIR、SCAN_NAME、SCAN_DEPS、SCAN_DEPTH、SCAN_EXTRA为include/scan.mk的参数选项;
让我们来看一下include/scan.mk,它的最终生成目标为all: $(TMP_DIR)/.$(SCAN_TARGET),该目标定义如下:
$(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
可以看到目标$(TMP_DIR)/.$(SCAN_TARGET)有2个依赖目标:$(TARGET_STAMP)和$(SCAN_STAMP),好吧,让我们看一下这2个依赖目标的实现:
$(TARGET_STAMP):$(FILELIST)
+( \
MD5SUM=$$( (md5sum || md5) <$(FILELIST) 2>/dev/null | awk '{print $$1}'); \
[ -f "$@.$$MD5SUM" ] ||{ \
rm -f $@.*; \
touch $@.$$MD5SUM; \
touch $@; \
} \
)
依赖目标$(TARGET_STAMP),它有一个依赖目标$(FILELIST),来,看一下该目标实现,如下:
$(FILELIST):
rm -f$(TMP_DIR)/info/.files-$(SCAN_TARGET)-*
$(call FIND_L, $(SCAN_DIR)) $(SCAN_EXTRA)-mindepth 1 $(if $(SCAN_DEPTH),-maxdepth $(SCAN_DEPTH)) -name Makefile | xargsgrep -HE 'call (Build/DefaultTargets|Build(Package|Target)|.+Package)' | se