转自:
摘要:本篇通过分析Makefile,了解Openwrt编译过程,包括(1)Openwrt目录结构(2)主Makefile的解析过程,各子目录的目标生成。(3)kernel编译过程(4)firmware的生成过程(5)软件包的编译过程
从github上clone了openwrt的代码仓库。
git clone https://github.com/openwrt-mirror/openwrt.git
Openwrt目录结构
上图是openwrt目录结构,其中第一行是原始目录,第二行是编译过程中生成的目录。各目录的作用是:
tools - 编译时需要一些工具, tools里包含了获取和编译这些工具的命令。里面是一些Makefile,有的可能还有patch。每个Makefile里都有一句:$(eval $(call HostBuild)),表示编译这个工具是为了在主机上使用的。
toolchain - 包含一些命令去获取kernel headers, C library, bin-utils, compiler, debugger target - 各平台在这个目录里定义了firmware和kernel的编译过程。 package - 包含针对各个软件包的Makefile。openwrt定义了一套Makefile模板,各软件包参照这个模板定义了自己的信息,如软件包的版本、下载地址、编译方式、安装地址等。 include - openwrt的Makefile都存放在这里。
scripts - 一些perl脚本,用于软件包管理。
dl - 软件包下载后都放到这个目录里
build_dir - 软件包都解压到build_dir/里,然后在此编译
staging_dir - 最终安装目录。tools, toolchain被安装到这里,rootfs也会放到这里。
feeds - feeds.conf订阅的软件下载目录。
bin - 编译完成之后,firmware和各ipk会放到此目录下。
Openwrt编译过程
main Makefile
openwrt根目录下的Makefile是执行make命令时的入口。从这里开始分析。
world:
ifndef ($(OPENWRT_BUILD),1) # 第一个逻辑 ... else # 第二个逻辑 ... endif
上面这段是主Makefile的结构,可以得知:
执行make时,若无任何目标指定,则默认目标是world
执行make时,无参数指定,则会进入第一个逻辑。如果执行命令make OPENWRT_BUILD=1,则直接进入第二个逻辑。
编译时一般直接使用make V=s -j 5这样的命令,不会指定OPENWRT_BUILD变量,显然这里OPENWRT_BUILD用于标记当前openwrt BSP是否已经编译过,因此第一次编译当然应该执行第一个逻辑,同时令OPENWRT_BUILD为1,标示openwrt BSP已经编译过了。
第一个逻辑
override OPENWRT_BUILD=1 export OPENWRT_BUILD
更改了OPENWRT_BUILD变量的值。这里起到的作用是下次执行make时,因为已经编译过,会进入到第二逻辑中。
第一个逻辑中会include toplevel.mk,该文件中的 “%::” 用于解释world目标的规则:
prereq:: prepare-tmpinfo .config @+$(MAKE) -r -s tmp/.prereq-build $(PREP_MK) @+$(NO_TRACE_MAKE) -r -s $@ %:: @+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq @( \
cp .config tmp/.config; \
./scripts/config/conf --defconfig=tmp/.config -w tmp/.config Config.in > /dev/null 2>&1; \ if ./scripts/kconfig.pl '>' .config tmp/.config | grep -q CONFIG; then \
printf "$(_R)WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!$(_N)\n" >&2; \
fi \
) @+$(ULIMIT_FIX) $(SUBMAKE) -r $@
执行 make V=s 时,上面这段规则简化为:
prereq:: prepare-tmpinfo .config @make -r -s tmp/.prereq-build @make V=ss -r -s prereq
%:: @make V=s -r -s prereq @make -w -r world
可见其中最终又执行了prereq和world目标,这两个目标都会进入到第二逻辑中。
第二逻辑
首先就引入了target, package, tools, toolchain这四个关键目录里的Makefile文件
include target/Makefile include package/Makefile include tools/Makefile include toolchain/Makefile
这些子目录里的Makefile使用include/subdir.mk里定义的两个函数来动态生成规则,这两个函数是subdir和stampfile
stampfile