• 【转】openwrt make menuconfig过程(提取menuconfig)


    转自:https://www.cnblogs.com/tfanalysis/p/3625430.html

    参考网站:http://wiki.openwrt.org/doc/howto/buildroot.exigence

    需要下载必要的库文件,编译器等。。。

    1 首先要获得openwrt的源码,参考openwrt.org官方网站的内容 https://dev.openwrt.org/wiki/GetSource

    其中trunk为开发版本,最新的稳定版为12.09 branch (Attitude Adjustment)。

    使用git获得:git clone git://git.openwrt.org/12.09/openwrt.git

    如果要更新源码则运行git pull即可。

    使用svn获得:svn co svn://svn.openwrt.org/openwrt/branches/attitude_adjustment

    2 下载完源码之后

    获取包列表:

    ./scripts/feeds update -a

    将包选项加到menuconfig中去:

    ./scripts/feeds install -a

    3 make menuconfig

    在此菜单中选择要编译的模块并生成依赖

    3.1

    我们打开openwrt根目录下的Makefile文件,发现并没有找到menuconfig这个目标,这个目标是在

    include $(TOPDIR)/include/toplevel.mk

    所指的toplevel.mk中定义的,如下图:

    它的依赖是scripts/config/mconf和prepare-tmpinfo FORCE

    • scripts/config/mconf是一个已经存在的可执行文件;
    • prepare-tmpinfo是本文件中的一个目标,等会再阐述;
    • FORCE尚还不清楚它的作用和来源;

    我们先看看menuconfig中的命令

        if [ ! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then 
            cp $(HOME)/.openwrt/defconfig .config; 
        fi
        $< Config.in

    这是一句shell脚本,意思是:如果不存在.config而且存在$(HOME)/.openwrt/defconfig,则拷贝$(HOME)/.openwrt/defconfig为.config

     $<是什么?The automatic variable ‘$<’ is just the first prerequisite,即是指scripts/config/mconf。
    把这两个字符串连起来看就知道什么意思啦:scripts/config/mconf Config.in

    你也可以直接到openwrt目录下去试运行一下这个指令,如下图,正是我们运行make menuconfig时出现的画面(下图我已经关闭了menuconfig):

    3.2

     好!现在我们回头去理prepare-tmpinfo的帐,并且看看能不能把Config.in这个文件搞懂是怎么回事。

    复制代码
    prepare-tmpinfo: FORCE
        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_DEPS="$(TOPDIR)/include/package*.mk $(TOPDIR)/overlay/*/*.mk" 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_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_mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
        touch $(TOPDIR)/tmp/.build
    复制代码

    3.2.1

    两个变量

    _SINGLE在顶层Makefile中定义:

    _SINGLE=export MAKEFLAGS=$(space);

    NO_TRACE_MAKE的-/include/verbose.mk中定义:

    ifeq ($(NO_TRACE_MAKE),)
    NO_TRACE_MAKE := $(MAKE) V=s$(OPENWRT_VERBOSE)
    export NO_TRACE_MAKE
    endif

     这里的命令先是去make V=xx -j1 -r -s -f include/scan.mk(分别Verbose,单线程,没有内建规则,指定Makefile文件)。所以我们再打开include/scan.mk文件看看怎么回事。最终目标是:

    all: $(TMP_DIR)/.$(SCAN_TARGET)

    3.2.2

    这时scan.mk先定义了一个叫做PackageDir的“函数”(命令序列,后面将会使用):

    复制代码
    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)/$(1)/Makefile) $(SCAN_DEPS),$(wildcard $(if $(filter /%,$(DEP)),$(DEP),$(SCAN_DIR)/$(1)/$(DEP))))
        { 
            $$(call progress,Collecting $(SCAN_NAME) info: $(SCAN_DIR)/$(2)) 
            echo Source-Makefile: $(SCAN_DIR)/$(2)/Makefile; 
            $(NO_TRACE_MAKE) --no-print-dir -r DUMP=1 -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 -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
    ) 
                rm -f $$@; 
            }; 
            echo; 
        } > $$@ || true
    endef
    复制代码

    3.2.3

    这个命令系列的用法可以看下面的$(call progress, Colleting....),progress也正是scan.mk文件中定义的一个命令序列:

    $(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

     具体progress的定义是这样的:

    复制代码
    ifeq ($(IS_TTY),1)
      define progress
        printf "33[M
    $(1)" >&2;
      endef
    else
      define progress
        :;
      endef
    endif
    复制代码

    所以,调用它之后会输出“<[M Collecting package info : merging... ”"....info: done"类似这样的信息(重定义到2,标准错误输出),$(1)表示第一个参数的意思

    中间则输出awk信息,来研究下这个语句

    -cat $(FILELIST) | awk '{gsub(///, "_", $$0);print "$(TMP_DIR)/info/.$(SCAN_TARGET)-" $$0}' | xargs cat > $@ 2>/dev/null

     处理过程:

    1. -cat $(FILELIST),-cat最头的-表示如果出错也不提示如意思;
    2. cat得的数据输出通过awk的解析
      awk '{gsub(///, "_", $$0);print "$(TMP_DIR)/info/.$(SCAN_TARGET)-" $$0}'
    3. awk得的数据输出通过xargs cat(分小段输出给@@,也就是(TMP_DIR)/.$(SCAN_TARGET)自己!),而错误输出的定义到null

    看上面的过程,这部分主要问题是要搞清楚$(FILELIST)和awk的用法:

    先上$(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 | xargs grep -HE 'call (Build/DefaultTargets|Build(Package|Target)|.+Package)' | sed -e 's#^$(SCAN_DIR)/##' -e 's#/Makefile:.*##' | uniq > $@

    这儿的FIND_L命令序列实在x/tmp/.host.mk中定义的(该mk文件由x/include/host.mk生成)

    FIND_L=/usr/bin/find -L $(1)

    因而这个命令就演变成了系统指令find/xarg&grep/sed/uniq的用法了。

    1 find查找$(SCAN_DIR)中的叫做Makefile的文件(搜索深度1~5);

    2 xargs grep会展开各个Makefile文件,-H为显示时makefile名字,-E为启用后面跟着的正则表达式;

    这儿call (Build/DefaultTargets|Build(Package|Target)|.+Package)会匹配到call Build/DefaultTargets或者BuildPackage或BuildTarget或者_任意多个字符_Package等三种情况的字符串(以行为结束);

    3 sed

    4 uniq

    最后获得的文件写到了FILELIST := $(TMP_DIR)/info/.files-$(SCAN_TARGET)-$(SCAN_COOKIE)中;

    复制代码
    spidev_test
    hostapd
    opkg
    fuse
    hotplug2
    ppp
    ...
    feeds/xwrt/webif-iw-lua-openssl
    feeds/xwrt/webif-netsukuku
    feeds/xwrt/webif-mesh
    feeds/xwrt/webif-fonheartbeat
    robocfg
    comgt
    rssileds
    madwifi
    grub
    libjson-c
    odhcp6c
    rotary-gpio-custom
    ead
    rtc-rv5c386a
    sierra-directip
    button-hotplug
    grub2
    kexec-tools
    linux-atm
    util-linux
    xfsprogs
    pjsip
    ltq-tapidemo
    owsip
    fbtest
    gpioctl
    uboot-omap4
    i2c-gpio-custom
    ltq-tapi
    ltq-vmmc
    uboot-lantiq
    swconfig
    uhttpd
    trelay
    iptables
    switch
    owipcalc
    ltq-kpi2udp
    复制代码

     3.2.4

    (TMPDIR)/.(TMPDIR)/.(SCAN_TARGET)的信赖,条件

    • $(TARGET_STAMP)
    • $(SCAN_STAMP)

    4 编译得的bin文件在bin目录中。

    使用make menuconfig --debug -w --just-print命令,不执行操作仅调试,结果为:

    复制代码
     1 GNU Make 3.81
     2 Copyright (C) 2006  Free Software Foundation, Inc.
     3 This is free software; see the source for copying conditions.
     4 There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
     5 PARTICULAR PURPOSE.
     6 
     7 This program built for x86_64-pc-linux-gnu
     8 Reading makefiles...
     9 Updating goal targets....
    10  File `menuconfig' does not exist.
    11     Target `scripts/config/mconf_check' is double-colon and has no prerequisites.
    12     Must remake target `scripts/config/mconf_check'.
    13 make: Entering directory `/home/tf/projects/openwrt'
    14 { [ -f "scripts/config/mconf_check.1" ] && mv "scripts/config/mconf_check.1"; /home/tf/projects/openwrt/scripts/timestamp.pl -x "*/.svn*" -x ".*" -x "*:*" -x "*!*" -x "* *" -x "*#*" -x "*/.*_check" -x "*/.*.swp"  -n scripts/config/mconf scripts/config && {  touch -r "scripts/config/mconf" "scripts/config/mconf_check"; } } || {  touch "scripts/config/mconf_check"; }
    15     Successfully remade target file `scripts/config/mconf_check'.
    16    Prerequisite `scripts/config/mconf_check' is newer than target `scripts/config/mconf'.
    17   Must remake target `scripts/config/mconf'.
    18 export MAKEFLAGS= ;umask 022; cmd() { >/dev/null 2>&1 make -s $* < /dev/null || { echo "make $*: build failed. Please re-run make with V=s to see what's going on"; false; } } 8>&1 9>&2; cmd -s -C scripts/config all CC="gcc"
    19   Successfully remade target file `scripts/config/mconf'.
    20    File `prepare-tmpinfo' does not exist.
    21      File `FORCE' does not exist.
    22     Must remake target `FORCE'.
    23     Successfully remade target file `FORCE'.
    24   Must remake target `prepare-tmpinfo'.
    25 mkdir -p tmp/info
    26 export MAKEFLAGS= ;make V=s -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPS="/home/tf/projects/openwrt/include/package*.mk /home/tf/projects/openwrt/overlay/*/*.mk" SCAN_DEPTH=5 SCAN_EXTRA=""
    27 export MAKEFLAGS= ;make V=s -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" SCAN_DEPS="profiles/*.mk /home/tf/projects/openwrt/include/kernel*.mk /home/tf/projects/openwrt/include/target.mk" SCAN_DEPTH=2 SCAN_EXTRA="" SCAN_MAKEOPTS="TARGET_BUILD=1"
    28 for type in package target; do 
    29         f=tmp/.${type}info; t=tmp/.config-${type}.in; 
    30         [ "$t" -nt "$f" ] || ./scripts/metadata.pl ${type}_config "$f" > "$t" || { rm -f "$t"; echo "Failed to build $t"; false; break; }; 
    31     done
    32 ./scripts/metadata.pl package_mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
    33 touch /home/tf/projects/openwrt/tmp/.build
    34   Successfully remade target file `prepare-tmpinfo'.
    35 Must remake target `menuconfig'.
    36 if [ ! -e .config -a -e /home/tf/.openwrt/defconfig ]; then 
    37         cp /home/tf/.openwrt/defconfig .config; 
    38     fi
    39 scripts/config/mconf Config.in
    40 Successfully remade target file `menuconfig'.
    41 make: Leaving directory `/home/tf/projects/openwrt'
    复制代码
  • 相关阅读:
    Eclipse
    JAVA
    .Net Core下使用WCF—— Consuming WCF Services in .NET Core – Best Practices
    xml转class ——xsd实现
    从已有container中生成新的image&打标签——Creating a Docker Image from an Existing Container
    How to install xfs and create xfs file system on Debian/Ubuntu Linux
    Ubuntu系统安装软件包(其他软件包的安装 思路类似)—— Steps to Install XFS Package in Ubuntu
    postgresql——SQL update fields of one table from fields of another one(列的批量更新)
    skype邮件撤回——步骤
    单元测试 _ Unit testing best practices with .NET Core and .NET Standard
  • 原文地址:https://www.cnblogs.com/cxt-janson/p/11995850.html
Copyright © 2020-2023  润新知