openwrt make defconfig 详解

对于 linux kernel,有几个常用 make 指令用于生成 .config 文件。

  • make oldconfig
  • make menuconfig
  • make defconfig
  • make config

那么这些指令具体执行了什么操作呢,针对 openwrt 来看下吧。

主 Makefile

在 buildroot 执行 make,首先会访问仓库根目录的主 Makefile,其中有个 ifneq 判断如下:

ifneq ($(OPENWRT_BUILD),1)
  _SINGLE=export MAKEFLAGS=$(space);

  override OPENWRT_BUILD=1
  export OPENWRT_BUILD
  GREP_OPTIONS=
  export GREP_OPTIONS
  CDPATH=
  export CDPATH
  include $(TOPDIR)/include/debug.mk
  include $(TOPDIR)/include/depends.mk
  include $(TOPDIR)/include/toplevel.mk
else
  include rules.mk
  include $(INCLUDE_DIR)/depends.mk
  include $(INCLUDE_DIR)/subdir.mk
  include target/Makefile
  include package/Makefile
  include tools/Makefile
  include toolchain/Makefile

make 时通常不会设置OPENWRT_BUILD,所以按照以上逻辑会 include 以下几个Makefile

  1. include/debug.mk
  2. include/depends.mk
  3. include/toplevel.mk

前两个先不管,主要来看下toplevel.mk.

toplevel.mk

在这个顶层 Makefile 中,定义了许多常用指令,其中就包含了 defconfig, oldconfig, menuconfig 等

config: scripts/config/conf prepare-tmpinfo FORCE
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< $(KCONF_FLAGS) Config.in

config-clean: FORCE
    $(_SINGLE)$(NO_TRACE_MAKE) -C scripts/config clean

defconfig: scripts/config/conf prepare-tmpinfo FORCE
    touch .config
    @if [ ! -s .config -a -e $(HOME)/.openwrt/defconfig ]; then cp $(HOME)/.openwrt/defconfig .config; fi
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< $(KCONF_FLAGS) --defconfig=.config Config.in

confdefault-y=allyes
confdefault-m=allmod
confdefault-n=allno
confdefault:=$(confdefault-$(CONFDEFAULT))

oldconfig: scripts/config/conf prepare-tmpinfo FORCE
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< $(KCONF_FLAGS) --$(if $(confdefault),$(confdefault),old)config Config.in

menuconfig: scripts/config/mconf prepare-tmpinfo FORCE
    if [ \! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then \
        cp $(HOME)/.openwrt/defconfig .config; \
    fi
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< Config.in

nconfig: scripts/config/nconf prepare-tmpinfo FORCE
    if [ \! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then \
        cp $(HOME)/.openwrt/defconfig .config; \
    fi
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< Config.in

xconfig: scripts/config/qconf prepare-tmpinfo FORCE
    if [ \! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then \
        cp $(HOME)/.openwrt/defconfig .config; \
    fi
    $< Config.in

其中的oldconfig如下:

oldconfig: scripts/config/conf prepare-tmpinfo FORCE
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< $(KCONF_FLAGS) --$(if $(confdefault),$(confdefault),old)config Config.in

KCONF_FLAGS 默认为空,confdefault 也默认为空,所以以上指令实际上就是

scripts/config/conf --oldconfig Config.in

make oldconfig

接下来来验证下是否是这个指令。使用make的 -n 参数可以打印执行过程,但并不执行具体指令,非常方便于调试。

$ make -n oldconfig
make -r -s staging_dir/host/.prereq-build OPENWRT_BUILD= QUIET=0
mkdir -p tmp/info
export MAKEFLAGS= ;make V=s -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPTH=5 SCAN_EXTRA=""
export MAKEFLAGS= ;make V=s -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" 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/${type}-metadata.pl  config "$f" > "$t" || { rm -f "$t"; echo "Failed to build $t"; false; break; }; \
done
[ tmp/.config-feeds.in -nt tmp/.packageauxvars ] || ./scripts/feeds feed_config > tmp/.config-feeds.in
./scripts/package-metadata.pl mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
./scripts/package-metadata.pl pkgaux tmp/.packageinfo > tmp/.packageauxvars || { rm -f tmp/.packageauxvars; false; }
./scripts/package-metadata.pl usergroup tmp/.packageinfo > tmp/.packageusergroup || { rm -f tmp/.packageusergroup; false; }
touch /home/litreily/openwrt/tmp/.build
[ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
    scripts/config/conf  --oldconfig Config.in

可以看到最后一行对应的就是我们推算出来的结果。同样可知其它相关config的指令是:

  • make defconfig: scripts/config/conf --defconfig=.config Config.in
  • make oldconfig: scripts/config/conf --oldconfig Config.in
  • make menuconfig: scripts/config/mconf Config.in

也就是说,make xxxconfig 最终执行的是 scripts/config 目录下的conf, mconf 指令,这两个指令也是需要编译的。在执行make xxxconfig时,conf, mconf 作为依赖文件同样会被编译。

make defconfig 详解

如果想要更加详细的 make 信息,可以使用 -d 参数,打印 debug 信息,根据 debug 信息可以看到编译过程中各种依赖嵌套的判断流程,对于学习 make 指令非常有用。

make defconfig 为例,执行 make -d V=s defconfig

GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile 'Makefile'...
Reading makefile '/home/litreily/openwrt/include/debug.mk' (search path) (no ~ expansion)...
Reading makefile '/home/litreily/openwrt/include/depends.mk' (search path) (no ~ expansion)...
Reading makefile '/home/litreily/openwrt/include/toplevel.mk' (search path) (no ~ expansion)...
Reading makefile '/home/litreily/openwrt/include/verbose.mk' (search path) (no ~ expansion)...
Updating makefiles....
 Considering target file '/home/litreily/openwrt/include/verbose.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/verbose.mk'.
  Trying pattern rule with stem 'verbose.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/verbose.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/verbose.mk'.
 No need to remake target '/home/litreily/openwrt/include/verbose.mk'.
 Considering target file '/home/litreily/openwrt/include/toplevel.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/toplevel.mk'.
  Trying pattern rule with stem 'toplevel.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/toplevel.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/toplevel.mk'.
 No need to remake target '/home/litreily/openwrt/include/toplevel.mk'.
 Considering target file '/home/litreily/openwrt/include/depends.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/depends.mk'.
  Trying pattern rule with stem 'depends.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/depends.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/depends.mk'.
 No need to remake target '/home/litreily/openwrt/include/depends.mk'.
 Considering target file '/home/litreily/openwrt/include/debug.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/debug.mk'.
  Trying pattern rule with stem 'debug.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/debug.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/debug.mk'.
 No need to remake target '/home/litreily/openwrt/include/debug.mk'.
 Considering target file 'Makefile'.
  Looking for an implicit rule for 'Makefile'.
  Trying pattern rule with stem 'Makefile'.
  Found an implicit rule for 'Makefile'.
  Finished prerequisites of target file 'Makefile'.
 No need to remake target 'Makefile'.
Updating goal targets....
Considering target file 'defconfig'.
 File 'defconfig' does not exist.
  Considering target file 'scripts/config/conf'.
   File 'scripts/config/conf' does not exist.
   Looking for an implicit rule for 'scripts/config/conf'.
   Trying pattern rule with stem 'c'.
   Found an implicit rule for 'scripts/config/conf'.
    Considering target file 'staging_dir/host/.prereq-build'.
     File 'staging_dir/host/.prereq-build' does not exist.
      Considering target file 'include/prereq-build.mk'.
       Looking for an implicit rule for 'include/prereq-build.mk'.
       Trying pattern rule with stem 'prereq-build.mk'.
       Found an implicit rule for 'include/prereq-build.mk'.
       Finished prerequisites of target file 'include/prereq-build.mk'.
      No need to remake target 'include/prereq-build.mk'.
     Finished prerequisites of target file 'staging_dir/host/.prereq-build'.
    Must remake target 'staging_dir/host/.prereq-build'.
Putting child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 15999 on the chain.
Live child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 15999 
Reaping winning child 0x7fffcb0a1800 PID 15999 
Live child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 16000 
Checking 'working-make'... ok.
Checking 'case-sensitive-fs'... ok.
Checking 'proper-umask'... ok.
Checking 'gcc'... ok.
Checking 'working-gcc'... ok.
Checking 'g++'... ok.
Checking 'working-g++'... ok.
Checking 'ncurses'... ok.
Checking 'perl-data-dumper'... ok.
Checking 'perl-thread-queue'... ok.
Checking 'tar'... ok.
Checking 'find'... ok.
Checking 'bash'... ok.
Checking 'xargs'... ok.
Checking 'patch'... ok.
Checking 'diff'... ok.
Checking 'cp'... ok.
Checking 'seq'... ok.
Checking 'awk'... ok.
Checking 'grep'... ok.
Checking 'egrep'... ok.
Checking 'getopt'... ok.
Checking 'stat'... ok.
Checking 'unzip'... ok.
Checking 'bzip2'... ok.
Checking 'wget'... ok.
Checking 'perl'... ok.
Checking 'python2-cleanup'... ok.
Checking 'python'... ok.
Checking 'python3'... ok.
Checking 'git'... ok.
Checking 'file'... ok.
Checking 'rsync'... ok.
Checking 'ldconfig-stub'... ok.
Reaping winning child 0x7fffcb0a1800 PID 16000 
Live child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 16418 
Reaping winning child 0x7fffcb0a1800 PID 16418 
Removing child 0x7fffcb0a1800 PID 16418 from chain.
    Successfully remade target file 'staging_dir/host/.prereq-build'.
   Finished prerequisites of target file 'scripts/config/conf'.
  Must remake target 'scripts/config/conf'.
Putting child 0x7fffcb0a1b70 (scripts/config/conf) PID 16422 on the chain.
Live child 0x7fffcb0a1b70 (scripts/config/conf) PID 16422 
make[1]: Entering directory '/home/litreily/openwrt/scripts/config'
cc -O2   -c -o conf.o conf.c
cc -O2   -c -o confdata.o confdata.c
cc -O2   -c -o expr.o expr.c
cc -O2 -I ./.   -c -o lexer.lex.o lexer.lex.c
cc -O2 -I ./.   -c -o parser.tab.o parser.tab.c
cc -O2   -c -o preprocess.o preprocess.c
cc -O2   -c -o symbol.o symbol.c
cc -O2   -c -o util.o util.c
cc   conf.o confdata.o expr.o lexer.lex.o parser.tab.o preprocess.o symbol.o util.o   -o conf
make[1]: Leaving directory '/home/litreily/openwrt/scripts/config'
Reaping winning child 0x7fffcb0a1b70 PID 16422 
Removing child 0x7fffcb0a1b70 PID 16422 from chain.
  Successfully remade target file 'scripts/config/conf'.
  Considering target file 'prepare-tmpinfo'.
   File 'prepare-tmpinfo' does not exist.
    Considering target file 'FORCE'.
     File 'FORCE' does not exist.
     Finished prerequisites of target file 'FORCE'.
    Must remake target 'FORCE'.
    Successfully remade target file 'FORCE'.
   Finished prerequisites of target file 'prepare-tmpinfo'.
  Must remake target 'prepare-tmpinfo'.
Putting child 0x7fffcb0a2010 (prepare-tmpinfo) PID 16454 on the chain.
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 16454 
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile 'Makefile'...
Reading makefile '/home/litreily/openwrt/include/debug.mk' (search path) (no ~ expansion)...
Reading makefile '/home/litreily/openwrt/include/depends.mk' (search path) (no ~ expansion)...
Reading makefile '/home/litreily/openwrt/include/toplevel.mk' (search path) (no ~ expansion)...
Reading makefile '/home/litreily/openwrt/include/verbose.mk' (search path) (no ~ expansion)...
Updating makefiles....
 Considering target file '/home/litreily/openwrt/include/verbose.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/verbose.mk'.
  Trying pattern rule with stem 'verbose.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/verbose.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/verbose.mk'.
 No need to remake target '/home/litreily/openwrt/include/verbose.mk'.
 Considering target file '/home/litreily/openwrt/include/toplevel.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/toplevel.mk'.
  Trying pattern rule with stem 'toplevel.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/toplevel.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/toplevel.mk'.
 No need to remake target '/home/litreily/openwrt/include/toplevel.mk'.
 Considering target file '/home/litreily/openwrt/include/depends.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/depends.mk'.
  Trying pattern rule with stem 'depends.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/depends.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/depends.mk'.
 No need to remake target '/home/litreily/openwrt/include/depends.mk'.
 Considering target file '/home/litreily/openwrt/include/debug.mk'.
  Looking for an implicit rule for '/home/litreily/openwrt/include/debug.mk'.
  Trying pattern rule with stem 'debug.mk'.
  Found an implicit rule for '/home/litreily/openwrt/include/debug.mk'.
  Finished prerequisites of target file '/home/litreily/openwrt/include/debug.mk'.
 No need to remake target '/home/litreily/openwrt/include/debug.mk'.
 Considering target file 'Makefile'.
  Looking for an implicit rule for 'Makefile'.
  Trying pattern rule with stem 'Makefile'.
  Found an implicit rule for 'Makefile'.
  Finished prerequisites of target file 'Makefile'.
 No need to remake target 'Makefile'.
Updating goal targets....
Considering target file 'staging_dir/host/.prereq-build'.
  Considering target file 'include/prereq-build.mk'.
   Looking for an implicit rule for 'include/prereq-build.mk'.
   Trying pattern rule with stem 'prereq-build.mk'.
   Found an implicit rule for 'include/prereq-build.mk'.
   Finished prerequisites of target file 'include/prereq-build.mk'.
  No need to remake target 'include/prereq-build.mk'.
 Finished prerequisites of target file 'staging_dir/host/.prereq-build'.
 Prerequisite 'include/prereq-build.mk' is older than target 'staging_dir/host/.prereq-build'.
No need to remake target 'staging_dir/host/.prereq-build'.
Reaping winning child 0x7fffcb0a2010 PID 16454 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 16505 
Reaping winning child 0x7fffcb0a2010 PID 16505 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 16506 

Collecting package info: package/base-files
Collecting package info: package/boot/arm-trusted-firmware-mvebu
Collecting package info: package/boot/arm-trusted-firmware-rockchip
Collecting package info: package/boot/arm-trusted-firmware-sunxi
Collecting package info: package/boot/at91bootstrap
Collecting package info: package/boot/fconfig
Collecting package info: package/boot/grub2
Collecting package info: package/boot/imx-bootlets
Collecting package info: package/boot/kexec-tools
Collecting package info: package/boot/kobs-ng
Collecting package info: package/boot/mt7623n-preloader
Collecting package info: package/boot/tfa-layerscape
Collecting package info: package/boot/uboot-at91
Collecting package info: package/boot/uboot-envtools
Collecting package info: package/boot/uboot-fritz4040
Collecting package info: package/boot/uboot-imx6
Collecting package info: package/boot/uboot-kirkwood
Collecting package info: package/boot/uboot-lantiq
Collecting package info: package/boot/uboot-layerscape
Collecting package info: package/boot/uboot-mediatek
Collecting package info: package/boot/uboot-mvebu
Collecting package info: package/boot/uboot-mxs
Collecting package info: package/boot/uboot-omap
Collecting package info: package/boot/uboot-oxnas
Collecting package info: package/boot/uboot-ramips
Collecting package info: package/boot/uboot-rockchip
Collecting package info: package/boot/uboot-sunxi
Collecting package info: package/boot/uboot-tegra
Collecting package info: package/boot/uboot-zynq
Collecting package info: package/devel/binutils
Collecting package info: package/devel/gdb
Collecting package info: package/devel/perf
Collecting package info: package/devel/strace
Collecting package info: package/devel/trace-cmd
Collecting package info: package/devel/valgrind
Collecting package info: package/firmware/amd64-microcode
Collecting package info: package/firmware/ath10k-ct-firmware
Collecting package info: package/firmware/b43legacy-firmware
Collecting package info: package/firmware/cypress-firmware
Collecting package info: package/firmware/cypress-nvram
Collecting package info: package/firmware/intel-microcode
Collecting package info: package/firmware/ipq-wifi
Collecting package info: package/firmware/lantiq/dsl-vrx200-firmware-xdsl
Collecting package info: package/firmware/layerscape/fman-ucode
Collecting package info: package/firmware/layerscape/ls-dpl
Collecting package info: package/firmware/layerscape/ls-mc
Collecting package info: package/firmware/layerscape/ls-rcw
Collecting package info: package/firmware/layerscape/ppfe-firmware
Collecting package info: package/firmware/linux-firmware
Collecting package info: package/firmware/prism54-firmware
Collecting package info: package/firmware/wireless-regdb
Collecting package info: package/kernel/acx-mac80211
Collecting package info: package/kernel/ath10k-ct
Collecting package info: package/kernel/bcm27xx-gpu-fw
Collecting package info: package/kernel/bcm63xx-cfe
Collecting package info: package/kernel/broadcom-wl
Collecting package info: package/kernel/button-hotplug
Collecting package info: package/kernel/cryptodev-linux
Collecting package info: package/kernel/exfat
Collecting package info: package/kernel/gpio-button-hotplug
Collecting package info: package/kernel/gpio-nct5104d
Collecting package info: package/kernel/hwmon-gsc
Collecting package info: package/kernel/lantiq/ltq-adsl
Collecting package info: package/kernel/lantiq/ltq-adsl-fw
Collecting package info: package/kernel/lantiq/ltq-adsl-mei
Collecting package info: package/kernel/lantiq/ltq-atm
Collecting package info: package/kernel/lantiq/ltq-deu
Collecting package info: package/kernel/lantiq/ltq-ifxos
Collecting package info: package/kernel/lantiq/ltq-ptm
Collecting package info: package/kernel/lantiq/ltq-tapi
Collecting package info: package/kernel/lantiq/ltq-vdsl
Collecting package info: package/kernel/lantiq/ltq-vdsl-fw
Collecting package info: package/kernel/lantiq/ltq-vdsl-mei
Collecting package info: package/kernel/lantiq/ltq-vmmc
Collecting package info: package/kernel/linux
Collecting package info: package/kernel/mac80211
Collecting package info: package/kernel/mt76
Collecting package info: package/kernel/mt7621-qtn-rgmii
Collecting package info: package/kernel/mwlwifi
Collecting package info: package/kernel/nat46
Collecting package info: package/kernel/om-watchdog
Collecting package info: package/kernel/rtc-rv5c386a
Collecting package info: package/kernel/rtl8812au-ct
Collecting package info: package/kernel/trelay
Collecting package info: package/libs/argp-standalone
Collecting package info: package/libs/elfutils
Collecting package info: package/libs/gettext
Collecting package info: package/libs/gettext-full
Collecting package info: package/libs/gmp
Collecting package info: package/libs/jansson
Collecting package info: package/libs/libaudit
Collecting package info: package/libs/libbsd
Collecting package info: package/libs/libevent2
Collecting package info: package/libs/libiconv
Collecting package info: package/libs/libiconv-full
Collecting package info: package/libs/libjson-c
Collecting package info: package/libs/libmnl
Collecting package info: package/libs/libnetfilter-conntrack
Collecting package info: package/libs/libnfnetlink
Collecting package info: package/libs/libnftnl
Collecting package info: package/libs/libnl
Collecting package info: package/libs/libnl-tiny
Collecting package info: package/libs/libpcap
Collecting package info: package/libs/libselinux
Collecting package info: package/libs/libsemanage
Collecting package info: package/libs/libsepol
Collecting package info: package/libs/libtool
Collecting package info: package/libs/libubox
Collecting package info: package/libs/libunwind
Collecting package info: package/libs/libusb
Collecting package info: package/libs/mbedtls
Collecting package info: package/libs/musl-fts
Collecting package info: package/libs/ncurses
Collecting package info: package/libs/nettle
Collecting package info: package/libs/openssl
Collecting package info: package/libs/pcre
Collecting package info: package/libs/popt
Collecting package info: package/libs/readline
Collecting package info: package/libs/sysfsutils
Collecting package info: package/libs/toolchain
Collecting package info: package/libs/uclibc++
Collecting package info: package/libs/uclient
Collecting package info: package/libs/ustream-ssl
Collecting package info: package/libs/wolfssl
Collecting package info: package/libs/zlib
Collecting package info: package/network/config/firewall
Collecting package info: package/network/config/gre
Collecting package info: package/network/config/ipip
Collecting package info: package/network/config/ltq-adsl-app
Collecting package info: package/network/config/ltq-vdsl-app
Collecting package info: package/network/config/netifd
Collecting package info: package/network/config/qos-scripts
Collecting package info: package/network/config/soloscli
Collecting package info: package/network/config/swconfig
Collecting package info: package/network/config/vti
Collecting package info: package/network/config/vxlan
Collecting package info: package/network/config/xfrm
Collecting package info: package/network/ipv6/464xlat
Collecting package info: package/network/ipv6/6in4
Collecting package info: package/network/ipv6/6rd
Collecting package info: package/network/ipv6/6to4
Collecting package info: package/network/ipv6/ds-lite
Collecting package info: package/network/ipv6/map
Collecting package info: package/network/ipv6/odhcp6c
Collecting package info: package/network/ipv6/thc-ipv6
Collecting package info: package/network/services/dnsmasq
Collecting package info: package/network/services/dropbear
Collecting package info: package/network/services/ead
Collecting package info: package/network/services/hostapd
Collecting package info: package/network/services/igmpproxy
Collecting package info: package/network/services/ipset-dns
Collecting package info: package/network/services/lldpd
Collecting package info: package/network/services/odhcpd
Collecting package info: package/network/services/omcproxy
Collecting package info: package/network/services/ppp
Collecting package info: package/network/services/relayd
Collecting package info: package/network/services/uhttpd
Collecting package info: package/network/services/umdns
Collecting package info: package/network/services/wireguard
Collecting package info: package/network/utils/adb-enablemodem
Collecting package info: package/network/utils/arptables
Collecting package info: package/network/utils/bpftools
Collecting package info: package/network/utils/comgt
Collecting package info: package/network/utils/dante
Collecting package info: package/network/utils/ebtables
Collecting package info: package/network/utils/ethtool
Collecting package info: package/network/utils/iperf
Collecting package info: package/network/utils/iperf3
Collecting package info: package/network/utils/iproute2
Collecting package info: package/network/utils/ipset
Collecting package info: package/network/utils/iptables
Collecting package info: package/network/utils/iw
Collecting package info: package/network/utils/iwcap
Collecting package info: package/network/utils/iwinfo
Collecting package info: package/network/utils/layerscape/restool
Collecting package info: package/network/utils/linux-atm
Collecting package info: package/network/utils/ltq-dsl-base
Collecting package info: package/network/utils/maccalc
Collecting package info: package/network/utils/nftables
Collecting package info: package/network/utils/owipcalc
Collecting package info: package/network/utils/resolveip
Collecting package info: package/network/utils/rssileds
Collecting package info: package/network/utils/tcpdump
Collecting package info: package/network/utils/umbim
Collecting package info: package/network/utils/uqmi
Collecting package info: package/network/utils/wireguard-tools
Collecting package info: package/network/utils/wireless-tools
Collecting package info: package/network/utils/wpan-tools
Collecting package info: package/network/utils/wwan
Collecting package info: package/system/ca-certificates
Collecting package info: package/system/fstools
Collecting package info: package/system/fwtool
Collecting package info: package/system/iucode-tool
Collecting package info: package/system/mtd
Collecting package info: package/system/openwrt-keyring
Collecting package info: package/system/opkg
Collecting package info: package/system/procd
Collecting package info: package/system/refpolicy
Collecting package info: package/system/rpcd
Collecting package info: package/system/selinux-policy
Collecting package info: package/system/ubox
Collecting package info: package/system/ubus
Collecting package info: package/system/ucert
Collecting package info: package/system/uci
Collecting package info: package/system/urandom-seed
Collecting package info: package/system/urngd
Collecting package info: package/system/usign
Collecting package info: package/system/zram-swap
Collecting package info: package/utils/adb
Collecting package info: package/utils/bcm27xx-userland
Collecting package info: package/utils/bsdiff
Collecting package info: package/utils/busybox
Collecting package info: package/utils/bzip2
Collecting package info: package/utils/checkpolicy
Collecting package info: package/utils/ct-bugcheck
Collecting package info: package/utils/e2fsprogs
Collecting package info: package/utils/f2fs-tools
Collecting package info: package/utils/fbtest
Collecting package info: package/utils/fritz-tools
Collecting package info: package/utils/jboot-tools
Collecting package info: package/utils/jsonfilter
Collecting package info: package/utils/lua
Collecting package info: package/utils/lua5.3
Collecting package info: package/utils/mdadm
Collecting package info: package/utils/mtd-utils
Collecting package info: package/utils/nvram
Collecting package info: package/utils/osafeloader
Collecting package info: package/utils/oseama
Collecting package info: package/utils/otrx
Collecting package info: package/utils/policycoreutils
Collecting package info: package/utils/px5g-mbedtls
Collecting package info: package/utils/px5g-wolfssl
Collecting package info: package/utils/ravpower-mcu
Collecting package info: package/utils/secilc
Collecting package info: package/utils/spidev_test
Collecting package info: package/utils/ugps
Collecting package info: package/utils/usbmode
Collecting package info: package/utils/usbreset
Collecting package info: package/utils/usbutils
Collecting package info: package/utils/util-linux
Collecting package info: merging...
Collecting package info: done
Reaping winning child 0x7fffcb0a2010 PID 16506 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 18058 

Collecting target info: target/linux/apm821xx
Collecting target info: target/linux/arc770
Collecting target info: target/linux/archs38
Collecting target info: target/linux/armvirt
Collecting target info: target/linux/at91
Collecting target info: target/linux/ath25
Collecting target info: target/linux/ath79
Collecting target info: target/linux/bcm27xx
Collecting target info: target/linux/bcm47xx
Collecting target info: target/linux/bcm53xx
Collecting target info: target/linux/bcm63xx
Collecting target info: target/linux/gemini
Collecting target info: target/linux/imx6
Collecting target info: target/linux/ipq40xx
Collecting target info: target/linux/ipq806x
Collecting target info: target/linux/ipq807x
Collecting target info: target/linux/kirkwood
Collecting target info: target/linux/lantiq
Collecting target info: target/linux/layerscape
Collecting target info: target/linux/malta
Collecting target info: target/linux/mediatek
Collecting target info: target/linux/mpc85xx
Collecting target info: target/linux/mvebu
Collecting target info: target/linux/mxs
Collecting target info: target/linux/octeon
Collecting target info: target/linux/octeontx
Collecting target info: target/linux/omap
Collecting target info: target/linux/oxnas
Collecting target info: target/linux/pistachio
Collecting target info: target/linux/ramips
Collecting target info: target/linux/realtek
Collecting target info: target/linux/rockchip
Collecting target info: target/linux/sunxi
Collecting target info: target/linux/tegra
Collecting target info: target/linux/uml
Collecting target info: target/linux/x86
Collecting target info: target/linux/zynq
Collecting target info: merging...
Collecting target info: done
Reaping winning child 0x7fffcb0a2010 PID 18058 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 20209 
Reaping winning child 0x7fffcb0a2010 PID 20209 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 20212 
Reaping winning child 0x7fffcb0a2010 PID 20212 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 20217 
WARNING: Makefile 'package/utils/busybox/Makefile' has a dependency on 'libpam', which does not exist
WARNING: Makefile 'package/utils/busybox/Makefile' has a dependency on 'libpam', which does not exist
WARNING: Makefile 'package/utils/busybox/Makefile' has a build dependency on 'libpam', which does not exist
WARNING: Makefile 'package/boot/kexec-tools/Makefile' has a dependency on 'liblzma', which does not exist
WARNING: Makefile 'package/network/services/lldpd/Makefile' has a dependency on 'libnetsnmp', which does not exist
WARNING: Makefile 'package/utils/policycoreutils/Makefile' has a dependency on 'libpam', which does not exist
WARNING: Makefile 'package/utils/policycoreutils/Makefile' has a dependency on 'libpam', which does not exist
WARNING: Makefile 'package/utils/policycoreutils/Makefile' has a build dependency on 'libpam', which does not exist
Reaping winning child 0x7fffcb0a2010 PID 20217 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 20219 
Reaping winning child 0x7fffcb0a2010 PID 20219 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 20221 
Reaping winning child 0x7fffcb0a2010 PID 20221 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 20223 
Reaping winning child 0x7fffcb0a2010 PID 20223 
Removing child 0x7fffcb0a2010 PID 20223 from chain.
  Successfully remade target file 'prepare-tmpinfo'.
  Pruning file 'FORCE'.
 Finished prerequisites of target file 'defconfig'.
Must remake target 'defconfig'.
touch .config
Putting child 0x7fffcb096b50 (defconfig) PID 20227 on the chain.
Live child 0x7fffcb096b50 (defconfig) PID 20227 
Reaping winning child 0x7fffcb096b50 PID 20227 
Live child 0x7fffcb096b50 (defconfig) PID 20228 
Reaping winning child 0x7fffcb096b50 PID 20228 
[ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
    scripts/config/conf  --defconfig=.config Config.in
Live child 0x7fffcb096b50 (defconfig) PID 20229 
#
# configuration written to .config
#
Reaping winning child 0x7fffcb096b50 PID 20229 
Removing child 0x7fffcb096b50 PID 20229 from chain.
Successfully remade target file 'defconfig'.

从以上 log 信息中可以非常完整清楚的看到 make 指令的执行流程,其中包含了每个目标文件及其依赖文件的规则查找和执行。下面我们结合 log 以及 Makefile 来详细追踪一下 make defconfig 的执行流程。

首先要知道 make 的目标文件是defconfig, 对应 toplevel.mk 中的

defconfig: scripts/config/conf prepare-tmpinfo FORCE
    touch .config
    @if [ ! -s .config -a -e $(HOME)/.openwrt/defconfig ]; then cp $(HOME)/.openwrt/defconfig .config; fi
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< $(KCONF_FLAGS) --defconfig=.config Config.in

可以知道其依赖项包含3个:

  1. scripts/config/conf
  2. prepare-tmpinfo
  3. FORCE

script/config/conf

对于依赖文件 scripts/config/conf ,make 执行log如下:

Considering target file 'defconfig'.
 File 'defconfig' does not exist.
  Considering target file 'scripts/config/conf'.
   File 'scripts/config/conf' does not exist.
   Looking for an implicit rule for 'scripts/config/conf'.
   Trying pattern rule with stem 'c'.
   Found an implicit rule for 'scripts/config/conf'.
    Considering target file 'staging_dir/host/.prereq-build'.
     File 'staging_dir/host/.prereq-build' does not exist.
      Considering target file 'include/prereq-build.mk'.
       Looking for an implicit rule for 'include/prereq-build.mk'.
       Trying pattern rule with stem 'prereq-build.mk'.
       Found an implicit rule for 'include/prereq-build.mk'.
       Finished prerequisites of target file 'include/prereq-build.mk'.
      No need to remake target 'include/prereq-build.mk'.
     Finished prerequisites of target file 'staging_dir/host/.prereq-build'.
    Must remake target 'staging_dir/host/.prereq-build'.

make 首先查找 defconfig 是否需要更新,发现不存在,因为本身就不是文件。然后查找第一个依赖 scripts/config/conf ,发现也不存在,然后去查找生成这个文件的规则,在 toplevel.mk 可以找到其规则如下:

ifeq ($(FORCE),)
  .config scripts/config/conf scripts/config/mconf: staging_dir/host/.prereq-build
endif

其中 $(FORCE) 变量默认是个空值,所以条件满足,make 发现 conf 又依赖于 staging_dir/host/.prereq-build. 于是把 .prereq-build 当做新的目标,查找其规则,在 toplevel.mk 中如下:

staging_dir/host/.prereq-build: include/prereq-build.mk
    mkdir -p tmp
    @$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prereq-build.mk prereq 2>/dev/null || { \
        echo "Prerequisite check failed. Use FORCE=1 to override."; \
        false; \
    }
  ifneq ($(realpath $(TOPDIR)/include/prepare.mk),)
    @$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prepare.mk prepare 2>/dev/null || { \
        echo "Preparation failed."; \
        false; \
    }
  endif
    touch $@

这里发现需要依赖 include/prereq-build.mk ,于是将该文件导入,并结束了对 .prereq-build 的依赖查找,同时标记需要重新生成目标 staging_dir/host/.prereq-build.

     Finished prerequisites of target file 'staging_dir/host/.prereq-build'.
    Must remake target 'staging_dir/host/.prereq-build'.

生成目标时,根据 Makefile 中 .prereq-build 规则,会执行以下指令:

    mkdir -p tmp
    @$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prereq-build.mk prereq 2>/dev/null || { \
        echo "Prerequisite check failed. Use FORCE=1 to override."; \
        false; \
    }
    touch $@

include 目录不包含文件 prepare.mk, 所以原先的的判断可以忽略。

使用 make -n defconfig 可以看到以上指令解析后是这样的

mkdir -p tmp
export MAKEFLAGS= ;make V=s -j1 -r -s -f /home/litreily/openwrt/include/prereq-build.mk prereq 2>/dev/null || { \
    echo "Prerequisite check failed. Use FORCE=1 to override."; \
    false; \
}
touch staging_dir/host/.prereq-build

以上 make 指令会根据 prereq-build.mkprereq.mk 两个 Makefile 安装一些依赖工具。

# Required for the toolchain
$(eval $(call TestHostCommand,working-make, \
    Please install GNU make v3.82 or later. (This version has bugs), \
    $(MAKE) -v | grep -E 'Make (3\.8[2-9]|3\.9[0-9]|[4-9]\.)'))

$(eval $(call TestHostCommand,case-sensitive-fs, \
    OpenWrt can only be built on a case-sensitive filesystem, \
    rm -f $(TMP_DIR)/test.*; touch $(TMP_DIR)/test.fs; \
        test ! -f $(TMP_DIR)/test.FS))

$(eval $(call TestHostCommand,proper-umask, \
    Please build with umask 022 - other values produce broken packages, \
    umask | grep -xE 0?0[012][012]))

# ...

其中的 TestHostCommand 定义于 prereq.mk. 对应的log如下,完整log参考前文。

Putting child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 15999 on the chain.
Live child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 15999 
Reaping winning child 0x7fffcb0a1800 PID 15999 
Live child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 16000 
Checking 'working-make'... ok.
Checking 'case-sensitive-fs'... ok.
Checking 'proper-umask'... ok.
Checking 'gcc'... ok.
Checking 'working-gcc'... ok.
Checking 'g++'... ok.
Checking 'working-g++'... ok.
...
Checking 'file'... ok.
Checking 'rsync'... ok.
Checking 'ldconfig-stub'... ok.
Reaping winning child 0x7fffcb0a1800 PID 16000 
Live child 0x7fffcb0a1800 (staging_dir/host/.prereq-build) PID 16418 
Reaping winning child 0x7fffcb0a1800 PID 16418 
Removing child 0x7fffcb0a1800 PID 16418 from chain.
    Successfully remade target file 'staging_dir/host/.prereq-build'.
   Finished prerequisites of target file 'scripts/config/conf'.
  Must remake target 'scripts/config/conf'.

执行完 prereq-build.mk 之后,就完成了 scripts/config/conf 依赖文件的编译生成,接下来就是正式编译 conf 文件了。

Putting child 0x7fffcb0a1b70 (scripts/config/conf) PID 16422 on the chain.
Live child 0x7fffcb0a1b70 (scripts/config/conf) PID 16422 
make[1]: Entering directory '/home/litreily/openwrt/scripts/config'
cc -O2   -c -o conf.o conf.c
cc -O2   -c -o confdata.o confdata.c
cc -O2   -c -o expr.o expr.c
cc -O2 -I ./.   -c -o lexer.lex.o lexer.lex.c
cc -O2 -I ./.   -c -o parser.tab.o parser.tab.c
cc -O2   -c -o preprocess.o preprocess.c
cc -O2   -c -o symbol.o symbol.c
cc -O2   -c -o util.o util.c
cc   conf.o confdata.o expr.o lexer.lex.o parser.tab.o preprocess.o symbol.o util.o   -o conf
make[1]: Leaving directory '/home/litreily/openwrt/scripts/config'
Reaping winning child 0x7fffcb0a1b70 PID 16422 
Removing child 0x7fffcb0a1b70 PID 16422 from chain.

可以看出来,编译 conf 文件时,会在子进程中先进入对应的目录 scripts/config , 然后使用该目录的Makefile进行编译。编译结束后离开该目录并退出子进程。

至此,defconfig 的依赖文件 scripts/config/conf 就编译完成了。流程简述如下:

make defconfig
    check prerequisites of defconfig : 
        scripts/config/conf, prepare-tmpinfo, FORCE
        check prerequisites of scripts/config/conf:
            staging_dir/host/.prereq-build
            check prerequisites of staging_dir/host/.prereq-build
                include/prereq-build.mk
            finished prerequisites of staging_dir/host/.prereq-build
            running commands in include/prereq-build.mk
        finished prerequisites of scripts/config/conf
        compiling scripts/config/conf
        finished compile scripts/config/conf
        ...

prepare-tmpinfo

scripts/config/conf 编译完成后,接下来就是defconfig 的第二个依赖 prepare-tmpinfo 了。

  Successfully remade target file 'scripts/config/conf'.
  Considering target file 'prepare-tmpinfo'.
   File 'prepare-tmpinfo' does not exist.
    Considering target file 'FORCE'.
     File 'FORCE' does not exist.
     Finished prerequisites of target file 'FORCE'.
    Must remake target 'FORCE'.
    Successfully remade target file 'FORCE'.
   Finished prerequisites of target file 'prepare-tmpinfo'.
  Must remake target 'prepare-tmpinfo'.

同样,查找 prepare-tmpinfo 目录不存在,查找其规则如下:

prepare-tmpinfo: FORCE
    @+$(MAKE) -r -s staging_dir/host/.prereq-build $(PREP_MK)
    mkdir -p tmp/info
    $(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPTH=5 SCAN_EXTRA=""
    $(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" 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/$${type}-metadata.pl $(_ignore) config "$$f" > "$$t" || { rm -f "$$t"; echo "Failed to build $$t"; false; break; }; \
    done
    [ tmp/.config-feeds.in -nt tmp/.packageauxvars ] || ./scripts/feeds feed_config > tmp/.config-feeds.in
    ./scripts/package-metadata.pl mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
    ./scripts/package-metadata.pl pkgaux tmp/.packageinfo > tmp/.packageauxvars || { rm -f tmp/.packageauxvars; false; }
    ./scripts/package-metadata.pl usergroup tmp/.packageinfo > tmp/.packageusergroup || { rm -f tmp/.packageusergroup; false; }
    touch $(TOPDIR)/tmp/.build

其依赖 FORCE 不存在,log提示remade target file FORCE, 实际上应该啥也没做,我尝试 echo ${FORCE} 也是个空值。

按照以上指令,同样,通过 make -n defconfig 可以知晓对应指令如下:

make -r -s staging_dir/host/.prereq-build OPENWRT_BUILD= QUIET=0
mkdir -p tmp
export MAKEFLAGS= ;make V=s -j1 -r -s -f /home/litreily/openwrt/include/prereq-build.mk prereq 2>/dev/null || { \
        echo "Prerequisite check failed. Use FORCE=1 to override."; \
        false; \
}
touch staging_dir/host/.prereq-build
mkdir -p tmp/info
export MAKEFLAGS= ;make V=s -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPTH=5 SCAN_EXTRA=""
export MAKEFLAGS= ;make V=s -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" 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/${type}-metadata.pl config "$f" > "$t" || { rm -f "$t"; echo "Failed to build $t"; false; break; }; \
done
[ tmp/.config-feeds.in -nt tmp/.packageauxvars ] || ./scripts/feeds feed_config > tmp/.config-feeds.in
./scripts/package-metadata.pl mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
./scripts/package-metadata.pl pkgaux tmp/.packageinfo > tmp/.packageauxvars || { rm -f tmp/.packageauxvars; false; }
./scripts/package-metadata.pl usergroup tmp/.packageinfo > tmp/.packageusergroup || { rm -f tmp/.packageusergroup; false; }
touch /home/litreily/openwrt/tmp/.build

prepare-tmpinfo, 顾名思义,就是准备一些临时信息,包括

  1. package
  2. target/linux

这两个部分,通过 include/scan.mk 扫描以上两个目录,将所有的 package 以及 target 信息存到临时目录 tmp 下, 然后通过对应的perl脚本 scripts/${type}-metadata.pl 生成 tmp/.config-${type}.in 文件。

  1. tmp/.packageinfo : tmp/.config-package.in
  2. tmp/.targetinfo : tmp/config-target.in

此外,通过scripts的其它脚本生成feed, package 相关的信息文件并存放于 tmp 目录。

prepare-tmpinfo 生成过程对应的log如下:

Considering target file 'staging_dir/host/.prereq-build'.
  Considering target file 'include/prereq-build.mk'.
   Looking for an implicit rule for 'include/prereq-build.mk'.
   Trying pattern rule with stem 'prereq-build.mk'.
   Found an implicit rule for 'include/prereq-build.mk'.
   Finished prerequisites of target file 'include/prereq-build.mk'.
  No need to remake target 'include/prereq-build.mk'.
 Finished prerequisites of target file 'staging_dir/host/.prereq-build'.
 Prerequisite 'include/prereq-build.mk' is older than target 'staging_dir/host/.prereq-build'.
No need to remake target 'staging_dir/host/.prereq-build'.
Reaping winning child 0x7fffcb0a2010 PID 16454 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 16505 
Reaping winning child 0x7fffcb0a2010 PID 16505 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 16506 

Collecting package info: package/base-files
Collecting package info: package/boot/arm-trusted-firmware-mvebu
Collecting package info: package/boot/arm-trusted-firmware-rockchip
...
Collecting package info: package/utils/usbreset
Collecting package info: package/utils/usbutils
Collecting package info: package/utils/util-linux
Collecting package info: merging...
Collecting package info: done
Reaping winning child 0x7fffcb0a2010 PID 16506 
Live child 0x7fffcb0a2010 (prepare-tmpinfo) PID 18058 

Collecting target info: target/linux/apm821xx
Collecting target info: target/linux/arc770
Collecting target info: target/linux/archs38
...
Collecting target info: target/linux/uml
Collecting target info: target/linux/x86
Collecting target info: target/linux/zynq
Collecting target info: merging...
Collecting target info: done
Reaping winning child 0x7fffcb0a2010 PID 18058 
...

以上所有搜集信息相关的log都是 scan.mk 打印的。还有值得注意的是,prepare-tmpinfo 首条指令

make -r -s staging_dir/host/.prereq-build OPENWRT_BUILD= QUIET=0

实际上在编译 scripts/config/conf 之前已经按照依赖规则执行过了,所以在这里会检测 .prereq-build 的依赖没有更新,所以不重新生成。

No need to remake target 'staging_dir/host/.prereq-build'.

ok, 到此为止,defconfig 的两个依赖项都已编译完毕。只剩下一个 FORCE.

defconfig

FORCE 实际上是个伪目标,其作用是强制执行依赖它的目标指令,这里对应的是执行 defconfig 相关指令。

defconfig: scripts/config/conf prepare-tmpinfo FORCE
    touch .config
    @if [ ! -s .config -a -e $(HOME)/.openwrt/defconfig ]; then cp $(HOME)/.openwrt/defconfig .config; fi
    [ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
        $< $(KCONF_FLAGS) --defconfig=.config Config.in

这个指令前面已经解析过了,主体部分就是 scripts/config/conf --defconfig=.config Config.in, 详细log如下:

  Successfully remade target file 'prepare-tmpinfo'.
  Pruning file 'FORCE'.
 Finished prerequisites of target file 'defconfig'.
Must remake target 'defconfig'.
touch .config
Putting child 0x7fffcb096b50 (defconfig) PID 20227 on the chain.
Live child 0x7fffcb096b50 (defconfig) PID 20227 
Reaping winning child 0x7fffcb096b50 PID 20227 
Live child 0x7fffcb096b50 (defconfig) PID 20228 
Reaping winning child 0x7fffcb096b50 PID 20228 
[ -L .config ] && export KCONFIG_OVERWRITECONFIG=1; \
    scripts/config/conf  --defconfig=.config Config.in
Live child 0x7fffcb096b50 (defconfig) PID 20229 
#
# configuration written to .config
#
Reaping winning child 0x7fffcb096b50 PID 20229 
Removing child 0x7fffcb096b50 PID 20229 from chain.
Successfully remade target file 'defconfig'. 

执行不带参数的 make defconfig 通常只会看到以下部分的log

#
# configuration written to .config
#

到此,make defconfig 整个流程就结束了,中间会调用到很多其它 Makefile,比如 scan.mk, verbose.mk 等,这些就不细讲了。

小结

本文主要目的是熟悉 openwrt Makefile 的执行流程,以便日后需要修改或调试某些相关问题时能够得心应手。Makefile 框架是 openwrt 非常重要的一部分,本文只是讲述了 make config 系列流程,实际上主 Makefile 有个条件分支判断 OPENWRT_BUILD, 当编译 kernel 或者 firmware 时,会先执行第一条分支进行初始化,然后通过 toplevel.mk 重新执行 make, 第二次调用时会进入第二个分支。那又将是另外一番风景,这个以后再说啦。

参考