小马同志( ̄^ ̄)ゞ

小马同志( ̄^ ̄)ゞ

Makefile学习笔记16|u-boot顶层Makefile02

  希望看到这篇文章的朋友能在评论区留下宝贵的建议来让我们共同成长,谢谢。

  这里是目录

设置输出文件路径

# kbuild supports saving output files in a separate directory.
# To locate output files in a separate directory two syntaxes are supported.
# In both cases the working directory must be the root of the kernel src.
# 1) O=
# Use "make O=dir/to/store/output/files/"
#
# 2) Set KBUILD_OUTPUT
# Set the environment variable KBUILD_OUTPUT to point to the directory
# where the output files shall be placed.
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable.

# KBUILD_SRC is set on invocation of make in OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
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

  这段代码解释了 KBUILD 系统如何支持在与源代码树分离的目录中保存输出文件。基本上,这种功能允许你在构建内核时保持源码目录的干净,所有编译生成的文件(对象文件、配置文件和最终的内核镜像等)都将被放置在一个单独的目录。这被称为"out-of-tree"构建。这段代码涉及的两个主要概念:

  1. O= 指令。在命令行中使用 O= 选项与 make 命令一起,指定输出文件的存储目录。例如:
make O=dir/to/store/output/files/

这会告诉 make 将所有的输出文件(如 .o 对象文件和编译后的内核映像)放在指定的目录中。

  1. KBUILD_OUTPUT 环境变量。设置 KBUILD_OUTPUT 环境变量也可以达到同样的目的,但是不需要每次都在 make 命令中指定:
export KBUILD_OUTPUT=dir/to/store/output/files/

设置 KBUILD_OUTPUT 后,所有后续的 make 调用都将自动使用这个环境变量中指定的目录来存储输出文件。

  以上就是支持 out-of-tree 构建的 kbuild 系统一部分的逻辑,这让内核编译变得更加灵活和整洁。通过使用这个功能,多个构建可以共存而不会互相干扰,并且清理构建产物也变得更加容易。

设置默认Target

# That's our default target when none is given on the command line
PHONY := _all
_all:

  在这段特定代码中,没有指定 _all 目标实际应该执行的命令或依赖的其他目标。通常,在完整的 Makefile 中,_all 目标会作为一个入口点,依赖实际的构建目标。

  在定义 .PHONY 的时候,通常会把所有不会生成同名输出文件的目标都定义为 .PHONY,这样可以防止 Make 错误地跳过这些目标,因为 Make 的默认行为是只构建那些比它们的依赖文件更新的目标。设置 .PHONY 可以确保无论环境如何改变,指定的目标总是被执行。

取消隐式规则

# Cancel implicit rules on top Makefile
$(CURDIR)/Makefile Makefile: ;

  在 Makefile 中,这行代码用于取消指定文件(在这种情况下是 Makefile 文件本身)的隐式规则。

  $(CURDIR)/Makefile Makefile: ; 和 MAKEFLAGS += -rR 是用来影响 make 行为的两种不同的方法,并且它们有着不同的目的。虽然两者都与禁用某些隐含行为有关,但它们的作用并不完全重复。

  这条规则是专门针对 Makefile(或任何其他特定文件)的,它定义了一个空规则,避免 make 根据任何内置的隐含规则尝试去重新生成 Makefile 文件。这在确保 Makefile 不被自动更新时很有用,如避免在存在预处理步骤(例如模式规则或自动生成 Makefile)的情况下意外地重建它。

  通常,你可以根据需要选择合适的方法或者两者结合使用。如果你只是想防止某个或某些特定文件被隐含规则所更新(如 Makefile),那么使用空规则是合适的。如果你想全面地提高构建的确定性和性能,并且防止任何潜在的隐含规则或变量干扰你的构建过程,那么 MAKEFLAGS += -rR 更适合。两者一起使用可以确保 Makefile 的稳定性,并为整个构建过程提供可靠和一致的输出,特别是在复杂或具有高度自定义性的构建系统中,这种严格控制可能是必要的。

创建输出文件目录

  我们以make TQM823L_defconfig为例,由于我们没有指定输出文件目录,以下代码将不会执行!!!

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) && cd $(KBUILD_OUTPUT) \
								&& /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
     $(error failed to create output directory "$(saved-output)"))

  整个逻辑确保了在再次调用 make 之前,输出目录已存在且可以使用。如果创建目录失败,构建过程将不会继续,用户会收到明确的错误信息。通过在 Makefile 中进行目录检查和创建,这段代码简化了外部构建流程,并为用户提供了一致和可靠的行为。

构建 sub-make 依赖

  我们以make TQM823L_defconfig为例,由于我们没有指定输出文件目录,以下代码将不会执行!!!

MAKEFLAGS += --include-dir=$(CURDIR)

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

  .PHONY 目标定义了 sub-make 规则,它强制每次都执行,即使是 up-to-date 的情况下(由于依赖了 .PHONY 的 FORCE 目标)。

  这里定义了一个函数,其作用是当执行命令行目标时,先过滤掉 _all 和 sub-make,如果目标不是 $(CURDIR)/Makefile,则将它们作为依赖关系加入到 sub-make 目标。如果我像u-boot的readme中一样输入了make TQM823L_defconfig,则 TQM823L_defconfig 会成为sub-make的依赖。

  这段脚本设计为从内核源代码的根目录执行,并通过 sub-make 目标将实际构建工作移动到 KBUILD_OUTPUT 指定的外部目录中去。这种方法使内核源代码保持干净,避免了中间对象和二进制文件污染源代码树,同时也提供了灵活性,比如能够同时进行多个构建过程。

  都看到这里了,可以给个点赞或者评论吗?达瓦里希( ̄^ ̄)ゞ

05-25 06:21