参考网站: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 "