我是靠谱客的博主 爱撒娇火,最近开发中收集的这篇文章主要介绍(系统移植)3 U-boot顶层Makefile版本号MAKEFLAGS变量命令输出 V静默输出 S编译输出目录设置 O代码检查 C指定模块编译 M获取主机架构和系统设置目标架构、交叉编译器和配置文件调用 scripts/Kbuild.include中的一些必要变量交叉编译工具变量设置导出其他变量make xxx_defconfig ,生成.configmake过程总结MakeFile中的函数 ,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

资料来源:正点原子嵌入式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中的函数 所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部