概述
资料来源:正点原子嵌入式linux
目录
版本号
MAKEFLAGS变量
命令输出 V
静默输出 S
编译输出目录设置 O
代码检查 C
指定模块编译 M
获取主机架构和系统
设置目标架构、交叉编译器和配置文件
调用 scripts/Kbuild.include中的一些必要变量
交叉编译工具变量设置
导出其他变量
make xxx_defconfig ,生成.config
1.scripts_basic 目标对应的命令
2.%config目标对应的命令
make xxx_defconfig 命令总结
make过程
MakeFile中的函数
filter
firstword
wildcard
patsubst
版本号
VERSION = 2016
PATCHLEVEL = 03
SUBLEVEL =
EXTRAVERSION =
NAME =
MAKEFLAGS变量
MAKEFLAGS如果不做unexport声明,默认传给子make
命令输出 V
ifeq ("$(origin V)", "command line") #origin用于返回V的来源,command line表示命令行,如果命令行中输入V,则ifeq成立
KBUILD_VERBOSE = $(V) # KBUILD_VERBOSE==V的数值
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
ifeq ($(KBUILD_VERBOSE),1) #如果KBUILD_VERBOSE==1
quiet =
Q =
else
quiet=quiet_ #
Q = @ #Q==@,Q变量定义是否省略输出完整编译信息
endif
Makefile 中会用到变量 Q 来控制编译的时候是否在终端输出完整的命令,通过命令行输入V的值便可控制是否输出编译过程。quiet用来控制输出命令长短。
静默输出 S
make -s 实现静默输出,就是不打印编译过程
ifneq ($(filter 4.%,$(MAKE_VERSION)),) # MAKE_VERSION表示编译器版本号,filter表示过滤匹配单词,匹配到版本4.%,则ifneq中第一个变量非空1,与空0不相等,条件成立
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),) #firstword用于取出text中第一个单词,MAKEFLAGS表示make后的指令序号,“make -s” -s就会作为函数返回(这里暂时哟点问题)
quiet=silent_ #quiet表示命令输出格式,quiet 为空的话,整个命令都会输出。quiet 为“quiet_”的话,仅输出短版本。 quiet 为“silent_”的话,整个命令都不会输出。
endif
else # make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
quiet=silent_
endif
endif
export quiet Q KBUILD_VERBOSE #导出变量quiet Q KBUILD_VERBOSE
编译输出目录设置 O
“make O=out”就是设置目标文件输出到 out 目录
ifeq ("$(origin O)", "command line") #如果O来自命令行
KBUILD_OUTPUT := $(O) #比如:make O=outfile ,KBUILD_OUTPUT=输出目录
endif
代码检查 C
命令“make C=1”使能代码检查,检查那些需要重新编译的文件。
“make C=2”用于检查所有的源码文件
#KBUILD_CHECKSRC代码检查
#KBUILD_CHECKSRC=1检查需要重新编译的文件
#KBUILD_CHECKSRC=2检查所有源码文件
ifeq ("$(origin C)", "command line")
KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
指定模块编译 M
uboot 中允许单独编译某个模块,使用命令“make M=dir”
#单独编译某个模块
ifdef SUBDIRS #兼容老语法make SUBIDRS=dir
KBUILD_EXTMOD ?= $(SUBDIRS)
endif
ifeq ("$(origin M)", "command line") # 新语法 make M=dir ,判断命令行是否有M
KBUILD_EXTMOD := $(M) #KBUILD_EXTMOD=M的值
endif
获取主机架构和系统
#获取主机架构与系统名
# | 表示管道,管道前的输出作为管道后的输入
#sed -e表示替换 ,uname —m表示获取主机架构x86_64,uname -s表示获取系统名称linux
HOSTARCH := $(shell uname -m |
sed -e s/i.86/x86/
-e s/sun4u/sparc64/
-e s/arm.*/arm/
-e s/sa110/arm/
-e s/ppc64/powerpc/
-e s/ppc/powerpc/
-e s/macppc/powerpc/
-e s/sh.*/sh/)
# uname -s 获取主机OS tr '[:upper:]' '[:lower:]' 表示将大写字母替换小写字母
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' |
sed -e 's/(cygwin).*/cygwin/')
export HOSTARCH HOSTOS
设置目标架构、交叉编译器和配置文件
#编 译 uboot 的 时 候 需 要 设 置 目 标 板 架 构 和 交 叉 编 译 器 ,“ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-”就是用于设置 ARCH 和 CROSS_COMPILE
# set default to nothing for native builds
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
#配置默认编译工具可以省去每次都要在make后面设置HOSTARCH与ARCH
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
KCONFIG_CONFIG ?= .config
export KCONFIG_CONFIG
调用 scripts/Kbuild.include中的一些必要变量
交叉编译工具变量设置
AS = $(CROSS_COMPILE)as
# Always use GNU ld
ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),)
LD = $(CROSS_COMPILE)ld.bfd
else
LD = $(CROSS_COMPILE)ld
endif
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
LDR = $(CROSS_COMPILE)ldr
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
前面已经设置CROSS_COMPILE ?= arm-linux-gnueabihf- 所以这里可以用LD代替arm-linux-gnueabihf-ld.bfd
导出其他变量
export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION
export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
export MAKE AWK PERL PYTHON
export HOSTCXX HOSTCXXFLAGS DTC CHECK CHECKFLAGS
export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS KBUILD_AFLAGS
make xxx_defconfig ,生成.config
在编译 uboot 之前要使用“make xxx_defconfig”命令来配置 uboot
编译脚本中有如下命令:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
其中ARCH与CROSS_COMPILE用于设置目标架构、交叉编译器和配置文件,而后面的mx6ull_14x14_ddr512_emmc_defconfig就是配置config
Makefile中有代码段:
%config: scripts_basic outputmakefile FORCE #FORCE强制执行
$(Q)$(MAKE) $(build)=scripts/kconfig $@
make mx6ull_14x14_ddr512_emmc_defconfig匹配到该段,%config共有三个依赖,scripts_basic, outputmakefile, FORCE
1. 首先看FORCE:
PHONY += FORCE
FORCE:
FORCE总为新,所以%config总是重新生成,FORCE的作用就是强制执行本句代码
2. outputmakefile
outputmakefile:
ifneq ($(KBUILD_SRC),) #KBUILD_SRC为空,所以outputmakefile无依赖命令,outputmakefile无效
$(Q)ln -fsn $(srctree) source
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif
KBUILD_SRC在前面代码段没有定义,那么outputmakefile相当于无效
3.scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
scripts_basic依赖共两句代码,其中build变量的值定义在 scripts/Kbuild.include
build=-f ./scripts/Makefile.build obj
所以执行后scripts_basic变为
@make -f ./scripts/Makefile.build obj=scripts/basic //也可以没有@,视配置而定
@rm -f . tmp_quiet_recordmcount //也可以没有@
所以%config可以看作是代码段:
@make -f ./scripts/Makefile.build obj=scripts/basic //也可以没有@,视配置而定
@rm -f . tmp_quiet_recordmcount //也可以没有@ #删除指令
@make -f ./scripts/Makefile.build obj=scripts/kconfig %config
所以在编译脚本中的make mx6ull_14x14_ddr512_emmc_defconfig会执行代码:
@make -f ./scripts/Makefile.build obj=scripts/basic #scripts_basic 目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/kconfig %config # %config 目标对应的命令
1.scripts_basic 目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/basic #scripts_basic 目标对应的命令
命令中引用了./scripts/Makefile.build,在该文件中,有定义:
#默认目标
PHONY := __build
__build:
定义了默认目标__build,依赖代码为:
#@make -f ./scripts/Makefile.build obj=scripts/basic 没有指认目标,所以使用默认目标__build,
#在顶层 Makefile 中,KBUILD_BUILTIN 为 1,KBUILD_MODULES 为 0,
#__build展开后__build:$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
# @:
#__build五个依赖可以利用echo输出,输出后只有always有效,因此__build最后结果==always的值
#__build: scripts/basic/fixdep
# @:
#所以scripts_basic 目标的作用就是编译出 scripts/basic/fixdep,编译所需要的makefile在前面kbuild-file包含
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y))
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target))
$(subdir-ym) $(always)
@:
编译所需makefile由以下代码段包含:
#src=scripts/basic srctree=. kbuild-dir展开后=$(if $(filter /%, scripts/basic), scripts/basic, ./scripts/basic)
#filter匹配筛选,无 / 开头的单词,$(filter /%, scripts/basic)为空,if 空,所以kbuild-dir=./scripts/basic
#kbuild-file展开后=$(if $(wildcard ./scripts/basic/Kbuild), ./scripts/basic/Kbuild, ./scripts/basic/Makefile)
# $(wildcard ./scripts/basic/Kbuild)中wildcard获取文件列表,由于./scripts/basic中没有Kbulid文件,所以值为空,那么if 空,kbuild-file=./scripts/basic/Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file) #include ./scripts/basic/Makefile
所以scripts_basic 目标的作用就是编译出 scripts/basic/fixdep。
其中生成的变量值:
src= scripts/kconfig
kbuild-dir = ./scripts/kconfig
kbuild-file = ./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile
2.%config目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/kconfig %config # %config 目标对应的命令
可以看出在Makefile.build中会读取/scripts/kconfig/Makefile的内容。而在该makefile中,有如下:
#make mx6ull_14x14_ddr512_emmc_defconfig匹配这句
%_defconfig: $(obj)/conf # scripts/kconfig/conf conf是主机生成软件,不必纠结如何来的
#slient=-s或者空 SRCARCH=.. Kconfig=Kconfig
#展开后@ scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
make mx6ull_14x14_ddr512_emmc_defconfig匹配这句代码,寻找依赖 scripts/kconfig/conf,以来不存在,则使用下面的代码生成依赖,代码展开后:
scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
上述命令用到了 xxx_defconfig 文件,比如 mx6ull_alientek_emmc_defconfig。这里会将
mx6ull_alientek_emmc_defconfig 中的配置输出到.config 文件中,最终生成 uboot 根目录下
的.config 文件。
make xxx_defconfig 命令总结
make过程
默认目标
PHONY := _all
_all:
_all: all
all: $(ALL-y)
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
u-boot.bin: u-boot-nodtb.bin FORCE
$(call if_changed,copy)
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
$(call if_changed,u-boot__)
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
head-y= arch/arm/cpu/armv7/start.o
libs-y=保存源码的目录
例:libs-y += lib/ 替换-》 lib/built-in.o
相当于libs-y保存大量的built-in.o
这个规则就相当于将以 u-boot.lds 为链接脚本,将 arch/arm/cpu/armv7/start.o 和各个子目录下的 built-in.o 链接在一起生成 u-boot。
u-boot就是将start.o 和大量的built-in.o链接在一起。
关于 uboot 的顶层 Makefile 就分析到这里,重点是“make xxx_defconfig”和“make”这两个命令的执行流程:
make xxx_defconfig :用于配置 uboot,这个命令最主要的目的就是生成.config 文件。
make:用于编译 uboot,这个命令的主要工作就是生成二进制的 u-boot.bin 文件和其他的一些与 uboot 有关的文件,比如 u-boot.imx 等等。
总结
make xxx_defconfig: 用于配置 uboot,这个命令最主要的目的就是生成.config 文件。
make:用于编译 uboot,这个命令的主要工作就是生成二进制的 u-boot.bin 文件和其他的一
些与 uboot 有关的文件,比如 u-boot.imx 等等
MakeFile中的函数
filter
$(filter <pattern...>,<text>)
filter 函数表示以 pattern 模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,可以有多个模式。函数返回值就是符合 pattern 的字符串。
firstword
$(firstword <text>)
firstword 函数用于取出 text 字符串中的第一个单词,函数的返回值就是获取到的单词。
wildcard
$(wildcard PATTERN…)
获取当前目录下所有格式文件,比如$(wildcard *.c),获取当前目录下的所有的.c 文件,类似“%”。
patsubst
$(patsubst <pattern>,<replacement>,<text>)
此函数用于在 text 中查找符合 pattern 的部分,如果匹配的话就用 replacement 替换掉。pattenr 是可以包含通配符“%”,如果 replacement 中也包含通配符“%”,那么 replacement 中的这个“%”将是 pattern 中的那个“%”所代表的字符串。
最后
以上就是爱撒娇火为你收集整理的(系统移植)3 U-boot顶层Makefile版本号MAKEFLAGS变量命令输出 V静默输出 S编译输出目录设置 O代码检查 C指定模块编译 M获取主机架构和系统设置目标架构、交叉编译器和配置文件调用 scripts/Kbuild.include中的一些必要变量交叉编译工具变量设置导出其他变量make xxx_defconfig ,生成.configmake过程总结MakeFile中的函数 的全部内容,希望文章能够帮你解决(系统移植)3 U-boot顶层Makefile版本号MAKEFLAGS变量命令输出 V静默输出 S编译输出目录设置 O代码检查 C指定模块编译 M获取主机架构和系统设置目标架构、交叉编译器和配置文件调用 scripts/Kbuild.include中的一些必要变量交叉编译工具变量设置导出其他变量make xxx_defconfig ,生成.configmake过程总结MakeFile中的函数 所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复