參考網站: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\n) \
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 "\033[M\r$(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
處理過程:
- -cat $(FILELIST),-cat最頭的-表示如果出錯也不提示如意思;
- cat得的數據輸出通過awk的解析
awk '{gsub(/\//, "_", $$0);print "$(TMP_DIR)/info/.$(SCAN_TARGET)-" $$0}'
- 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)中;
這兒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命令,不執行操作僅調試,結果爲:
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
Reading makefiles...
Updating goal targets....
File `menuconfig' does not exist.
Target `scripts/config/mconf_check' is double-colon and has no prerequisites.
Must remake target `scripts/config/mconf_check'.
make: Entering directory `/home/tf/projects/openwrt'
{ [ -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"; }
Successfully remade target file `scripts/config/mconf_check'.
Prerequisite `scripts/config/mconf_check' is newer than target `scripts/config/mconf'.
Must remake target `scripts/config/mconf'.
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"
Successfully remade target file `scripts/config/mconf'.
File `prepare-tmpinfo' does not exist.
File `FORCE' does not exist.
Must remake target `FORCE'.
Successfully remade target file `FORCE'.
Must remake target `prepare-tmpinfo'.
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_DEPS="/home/tf/projects/openwrt/include/package*.mk /home/tf/projects/openwrt/overlay/*/*.mk" 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_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"
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 /home/tf/projects/openwrt/tmp/.build
Successfully remade target file `prepare-tmpinfo'.
Must remake target `menuconfig'.
if [ \! -e .config -a -e /home/tf/.openwrt/defconfig ]; then \
cp /home/tf/.openwrt/defconfig .config; \
fi
scripts/config/mconf Config.in
Successfully remade target file `menuconfig'.
make: Leaving directory `/home/tf/projects/openwrt'