Uboot top-level Makefile analysis

1. Options and parameter configuration

1.1, version number
VERSION = 2016 // Major version number
PATCHLEVEL = 03 //Patch version number
SUBLEVEL = // minor version number
EXTRAVERSION = // Additional information
NAME = //uboot name
1.2, MAKEFLAGS

MAKEFLAGS is passed to the sub-make during the execution of make, and is used to specify options and flags when the make command is executed. The -r option is used to prohibit the use of built-in implicit rules, -R option is used to prohibit the use of built-in variable definitions, the --include-dir option specifies the search path, and $(CURDIR) represents the current directory.

MAKEFLAGS + = -rR --include-dir=$(CURDIR)
1.3. Display detailed compilation information

Adding the V=1 option when executing make can display more detailed compilation information.

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q=@
endif

After adding this option, both quiet and Q are empty. When the command shown in the figure below is executed, information can be output. Otherwise, if the Q value is @, no compilation information will be output:

1.4, silent compilation

When compiling, use make -s to achieve silent compilation. The essence is quiet=silent_:

# If the user is running make -s (silent mode), suppress echoing of
#commands

ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
  quiet=silent_
endif
else #make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
  quiet=silent_
endif
endif
1.5. Set the compilation result output path

This option is rarely used. When compiling make O=filepath, you can specify the output path KBUILD_OUTPUT variable to save filepath and use it for makefile

ifeq ($(KBUILD_SRC),)

# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?
ifeq ("$(origin O)", "command line")
  KBUILD_OUTPUT := $(O)
endif

# That's our default target when none is given on the command line
PHONY := _all
_all:
# Cancel implicit rules on top Makefile
$(CURDIR)/Makefile Makefile: ;

ifneq ($(KBUILD_OUTPUT),)
# Invoke a second make in the output directory, passing relevant variables
# check that the output directory actually exists
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) & amp; & amp; cd $(KBUILD_OUTPUT) \
& amp; & amp; /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
     $(error failed to create output directory "$(saved-output)"))

PHONY + = $(MAKECMDGOALS) sub-make

$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
@:

sub-make: FORCE
$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))

# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)
1.6, Source file check

This option is rarely used. When compiling, make C=1, or C=2. 1 means checking files that need to be recompiled, 2 means checking all files. This value will be assigned to the variable KBUILD_CHECKSRC. The variable is exported KBUILD_CHECKSRC in the top-level makefile. Export to other files for use

ifeq ("$(origin C)", "command line")
  KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
  KBUILD_CHECKSRC = 0
endif
1.7, module compilation

This option is rarely used. When compiling, make M=modle; the KBUILD_EXTMOD variable is assigned the value module, _all depends on modules, and the makefile will execute the corresponding command to generate the module:

ifdef SUBDIRS
  KBUILD_EXTMOD ?= $(SUBDIRS)
endif

ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif

# If building an external module we do not care about the all: rule
# but instead _all depend on modules
PHONY + = all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif
1.8. Obtain compilation platform information

Get the HOSTARCH HOSTOS export by executing a shell command and processing it through a pipe:

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/)

HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')

export HOSTARCH HOSTOS

You can print out the information to view:

1.9, setting compilation tools, etc.

If HOSTARCH and ARCH are consistent, set the CROSS_COMPILE variable to empty. If the KCONFIG_CONFIG variable is not specified, specify it as .config. Determine whether bash or /bin/bash exists. If it exists, assign it to the variable CONFIG_SHELL.

# set default to nothing for native builds
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif

KCONFIG_CONFIG ?= .config
export KCONFIG_CONFIG

# SHELL used by kbuild
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)

HOSTCC=cc
HOSTCXX=c++
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2

ifeq ($(HOSTOS),cygwin)
HOSTCFLAGS + = -ansi
endif

When executing make, you usually need to specify ARCH and CROSS_COMPILE. You can assign values directly here. You only need to execute make afterwards:

ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-

2. Make xxx_defconfig execution process

2.1, Purpose

Execute the command to view detailed information. The ultimate purpose of make xxx_defconfig is to write the configuration into .config:

2.2, Rule Analysis

Use the following command to output make rule information to makedata.log:

make mx6ull_14x14_ddr256_nand_defconfig V=1 -p > makedata.log

Find mx6ull_14x14_ddr256_nand_defconfig, which depends on scripts/kconfig/conf. The rules come from line 114 of scripts/kconfig/Makefile:

mx6ull_14x14_ddr256_nand_defconfig: scripts/kconfig/conf
# recipe to execute (from 'scripts/kconfig/Makefile', line 114):
        $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

Continue to find the dependencies of the scripts/kconfig/conf tool:

scripts/kconfig/conf: FORCE scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o

Further searching reveals that these .o files originate from some .c files.

scripts/kconfig/conf.o: scripts/kconfig/conf.c FORCE
scripts/kconfig/zconf.tab.o: scripts/kconfig/zconf.tab.c FORCE scripts/kconfig/zconf.lex.c scripts/kconfig/zconf.hash.c

Therefore, the whole process is generated through some .c files. The final .o file is linked into scripts/kconfig/conf. Use this tool to execute $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/ The configs/$@ $(Kconfig) command is the function of make xxxdefconfig. In the command, $(Q) indicates whether to compile and output, no need to pay attention; $< indicates the first dependency, which is scripts/kconfig/conf; silent is not set. No need to pay attention; SRCARCH is ".."; $@ is the first target, which is mx6ull_14x14_ddr256_nand_defconfig; $(Kconfig) is Kconfig, and the final executed command is:

scripts/kconfig/conf --defconfig=configs/mx6ull_14x14_ddr256_nand_defconfig Kconfig
2.3. Tool code analysis

To analyze the specific implementation details of the above commands, you need to view the source code of the conf tool, that is, several dependent .c files were analyzed in 2.2. The main function of the tool is located in scripts/kconfig/conf.c.

First, the input parameters are processed through the getopt_long function to realize the assignment of input_mode and defconfig_file, in which input_mode is assigned defconfig and defconfig_file is assigned configs/mx6ull_14x14_ddr256_nand_defconfig.

 while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
if (opt == 's') {
conf_set_message_callback(NULL);
continue;
}
input_mode = (enum input_mode)opt;
switch (opt) {
case silentoldconfig:
sync_kconfig = 1;
break;
case defconfig:
case savedefconfig:
defconfig_file = optarg;
break;
        …
        …
        …
case '?':
conf_usage(progname);
exit(1);
break;
}
}

A few lines of printing information are added to the source code to facilitate checking the assignment. When executing if (ac == optind), we will have a subsequent parameter Kconfig, so if the judgment is not established, it will not be executed. If we do not add the kconfig parameter when calling the tool, it will be printed. error message:

 printf("defconfig_file : %s\\
",defconfig_file);

if (ac == optind) {
printf(_("%s: Kconfig file missing\\
"), av[0]);
conf_usage(progname);
exit(1);
}
name = av[optind];

printf("name = %s\\
", name);
conf_parse(name);

Subsequent name is assigned to Kconfig, and then conf_parse is called for parsing processing. After processing Kconfig, call conf_read to process the default configuration file we specified.

After processing Kconfiug and xxx_defconfig, call conf_write to write the processing results into the .config file:

Perform the complete process to view the added printing information:

3. make execution process

Execute make directly in the top directory, and the first target will be found in the Makefile to generate. The first target is _all, which depends on all:

ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules

all depends on $(ALL-y):

all: $(ALL-y)

The value of $(ALL-y) is as follows. For the statement ALL-$(CONFIG_ONENAND_U_BOOT) + = u-boot-onenand.bin, if CONFIG_ONENAND_U_BOOT is configured in .config, there will be a setting of CONFIG_ONENAND_U_BOOT=y. This When it is ALL-y + = u-boot-onenand.bin.

ALL-y + = u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check

ALL-$(CONFIG_ONENAND_U_BOOT) + = u-boot-onenand.bin
ifeq ($(CONFIG_SPL_FSL_PBL),y)
ALL-$(CONFIG_RAMBOOT_PBL) + = u-boot-with-spl-pbl.bin
else
ifneq ($(CONFIG_SECURE_BOOT), y)
# For Secure Boot The Image needs to be signed and Header must also
# be included. So The image has to be built explicitly
ALL-$(CONFIG_RAMBOOT_PBL) + = u-boot.pbl
endif
endif
ALL-$(CONFIG_SPL) + = spl/u-boot-spl.bin
…………
…………
…………

# Add optional build target if defined in board/cpu/soc headers
ifneq ($(CONFIG_BUILD_TARGET),)
ALL-y + = $(CONFIG_BUILD_TARGET:"%"=%)
endif

Take u-boot.bin as an example. In the first line, $(ALL-y) is added to u-boot.bin to find the dependencies of u-boot.bin:

ifeq ($(CONFIG_OF_SEPARATE),y)
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
$(call if_changed,cat)

u-boot.bin: u-boot-dtb.bin FORCE
$(call if_changed,copy)
else
u-boot.bin: u-boot-nodtb.bin FORCE
$(call if_changed,copy)
endif

u-boot.bin depends on u-boot-nodtb.bin, continue to search:

u-boot-nodtb.bin: u-boot FORCE

u-boot-nodtb.bin depends on u-boot, continue to search:

u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE

Three of the dependencies are as follows, which roughly means linking the header and multiple libraries through the connection script to generate u-boot-nodtb.bin:

u-boot-init := $(head-y)
u-boot-main := $(libs-y)
u-boot.lds: $(LDSCRIPT) prepare FORCE

//For $(head-y) specified in arch/arm/Makefile:
head-y := arch/arm/cpu/$(CPU)/start.o
//After replacement:
head-y := arch/arm/cpu/armv7/start.o

//For $(libs-y) specified in the top-level Makefile:
libs-y + = lib/
libs-$(HAVE_VENDOR_COMMON_LIB) + = board/$(VENDOR)/common/
libs-$(CONFIG_OF_EMBED) + = dts/
libs-y + = fs/
libs-y + = net/
libs-y + = disk/
libs-y + = drivers/
libs-y + = drivers/dma/
libs-y + = drivers/gpio/
libs-y + = drivers/i2c/
libs-y + = drivers/mmc/
…………
…………
…………

libs-y := $(patsubst %/, %/built-in.o, $(libs-y))

Other dependencies of ALL-y can be analyzed in turn.

4. Summary

This article briefly introduces the uboot top-level makefile to provide some reference for beginners.

Article reference:

Leader of Zhengdian Atomic Left Alliance: "I.MX6U Embedded Linux Driver Development Guide"

Baiwen.com teacher Wei Dongshan’s course: "Complete Analysis and Transplantation of u-boot"

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. CS entry skill treeLinux introductionFirst introduction to Linux37537 people are learning the system

syntaxbug.com © 2021 All Rights Reserved.