海思hi3520dv400 kernel分析(0)——Kbuild原理分析

(一)前言

    kbuild,即 kernel build,用于编译 Linux 内核文件。 kbuild 对 makefile 进行了功能上的扩充,使其在编译内核文件时更加高效,简洁。大部分内核中的 Makefile 都是使用 Kbuild 组织结构的 kbuild Makefile。
Kbuild 执行的几个步骤(大致):

  1. 根据内核配置生成文件 .config
  2. 将内核的版本号存储在 include/linux/version.h
  3. 生成指向 include/asm-$(ARCH) 的符号链接
  4. 更新所有编译所需的文件: 附加的文件由 arch/$(ARCH)/Makefile 指定。
  5. 递归向下访问所有在下列变量中列出的目录: init-* core* drivers-* net-* libs-*,并编译生成目标文件。这些变量的值可以在 arch/$(ARCH)/Makefile 中扩充。
  6. 连接所有的目标文件,在源代码树顶层目录中生成 vmlinux。最先联接是在 head-y 中列出的文件,该变量由 arch/$(ARCH)/Makefile 赋值。
  7. 最后完成具体架构的特殊要求,并生成最终的启动镜像。(包含生成启动指令,准备 initrd 镜像或类似文件)

(二)Linux内核Makefile文件组成

    Linux 内核的 Makefile 分为 5 个部分 :

名称 描述
顶层 Makefile 它是所有Makefile文件的核心,从总体上控制着内核的编译、连接
arch/$(ARCH)/Makefile 对应体系结构的Makefile,它用来决定哪些体系结构相关的文件参与内核的生成,并提供一些规则来生成特定格式的内核映像
scripts/Makefile.* Makefile公用的通用规则、脚本等
子目录kbuild Makefiles 各级子目录的Makefile相对简单,被上一层Makefile.build调用来编译当前目录的文件。
顶层.config     配置文件,配置内核时生成。所有的Makefile文件(包括顶层目录和各级子目录)都是根据.config来决定使用哪些文件的

    顶层 Makefile 阅读的.config 文件,而该文件是由内核配置程序生成的。顶层 Makefile 负责制作: vmlinux(内核文件)与模块(任何模块文件)。制作的过程主要是通过递归向下访问子目录的形式完成。并根据内核配置文件确定访问哪些子目录。顶层 Makefile 要原封不动的包含一具体架构的Makefile,其名字类似于 arch/$(ARCH)/Makefile。该架构 Makefile 向顶层 Makefile 提供其架构的特别信息。
    每一个子目录都有一个 Kbuild Makefile 文件,用来执行从其上层目录传递下来的命令。Kbuild Makefile 从.config 文件中提取信息,生成 Kbuild 完成内核编译所需的文件列表。
    scripts/Makefile.*包含了所有的定义、规则等信息。这些文件被用来编译基于 kbuild Makefile的内核 。 

Makefile.build 被顶层Makefile所调用,与各级子目录的Makefile合起来构成一个完整的Makefile文件,定义.lib、built-in.o以及目标文件.o的生成规则。这个Makefile文件生成了子目录的.lib、built-in.o以及目标文件.o
Makefile.clean 被顶层Makefile所调用,用来删除目标文件等
Makefile.lib 被Makefile.build所调用,主要是对一些变量的处理,比如说在obj-y前边加上obj目录
Kbuild.include 被Makefile.build所调用,定义了一些函数,如if_changed、if_changed_rule、echo-cmd 

总结:

  1. Linux内核Makefile体系核心的Makefile文件就两个:顶层Makefile、scripts/Makefile.build。
  2. 子目录中的Makefile、kbuild不是Makefile文件(完整的Makefile文件),只能算作是Makefile的包含文件。
  3. 顶层Makefile文件负责将各个目录生成的*.built-in.o、lib.a等文件连接到一起。而scripts/Makefile.build 包含子目录中的Makefile文件来生成这些*.built-in.o、lib.a、*.o等文件。

(三)编译过程分析

本文的实验源码是对“linux-3.10.y”进行移植后的运行在HI3520DV400开发板上的源码包

1.顶层Makefile编译

    内核配置完成后,在顶层目录中执行“#make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux- uImage”便开始编译内核。但是,uImage却不是在顶层Makefile中定义,而是在arch/$(ARCH)/Makefile中定义。

linux-3.10.y/Makefile
 496 # ===========================================================================
 497 # *config targets only - make sure prerequisites are updated, and descend
 498 # in scripts/kconfig to make the *config target
 499 
 500 # Read arch specific Makefile to set KBUILD_DEFCONFIG as needed.
 501 # KBUILD_DEFCONFIG may point out an alternative default configuration
 502 # used for 'make defconfig'
 503 include $(srctree)/arch/$(SRCARCH)/Makefile  

    其中srctree为源码绝对路径,以我的环境为例,它的值等于/home/biao/test/kernel/linux-3.10.y;而SRCARCH := $(ARCH),即该变量等于架构名称,我们以arm为例进行说明。

arch/arm/Makefile 
 301 zImage Image xipImage bootpImage uImage: vmlinux

    可见uImage依赖于vmlinux,要先生成vmlinux,然后执行下边这条指令完成编译

arch/arm/Makefile 
 302     $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

<1> Q的定义:选择静态编译与否(是否打印编译信息)

linux-3.10.y/Makefile
 309 ifeq ($(KBUILD_VERBOSE),1)
 310   quiet =
 311   Q =
 312 else
 313   quiet=quiet_
 314   Q = @
 315 endif

<2> MAKE: 系统环境变量,值为make

<3> build: 值为“-f scripts/Makefile.build obj=”实际上就是调用子Makefile--scripts/Makefile.build,然后传递参数目标文件夹。

 160 ###
 161 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
 162 # Usage:
 163 # $(Q)$(MAKE) $(build)=dir
 164 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj

Kbuild.include被顶层Makefile所包含

linux-3.10.y/Makefile
 330 # We need some generic definitions (do not try to remake the file).
 331 $(srctree)/scripts/Kbuild.include: ;
 332 include $(srctree)/scripts/Kbuild.include

2.vmlinux的生成

linux-3.10.y/Makefile
 576 # The all: target is the default when no target is given on the                                                               
 577 # command line.
 578 # This allow a user to issue only 'make' to build a kernel including modules
 579 # Defaults to vmlinux, but the arch makefile usually adds further targets
 580 all: vmlinux

顶层Makefile生成的目标文件就是vmlinux,它是默认编译目标文件

linux-3.10.y/Makefile
 778 # Include targets which we want to
 779 # execute if the rest of the kernel build went well.
 780 vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE

    linux-3.10.y/Makefile
 764 # Externally visible symbols (used by link-vmlinux.sh)
 765 export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
 766 export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y)
 767 export KBUILD_LDS          := arch/$(SRCARCH)/kernel/vmlinux.lds
 768 export LDFLAGS_vmlinux
 769 # used by scripts/pacmage/Makefile
 770 export KBUILD_ALLDIRS := $(sort $(filter-out arch/%,$(vmlinux-alldirs)) arch Documentation include samples scripts tools virt)
 771 
 772 vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

    vmlinux的依赖是vmlinux-deps,vmlinux-deps又依赖于KBUILD_LDS,KBUILD_VMLINUX_INIT,KBUILD_VMLINUX_MAIN,要想生成vmlinux必须要先把这些原材料准备好。

<1> KBUILD_LDS

在编译之前要把连接脚本先生成,最后的连接阶段会用的着。

linux-3.10.y/Makefile
 767 export KBUILD_LDS          := arch/$(SRCARCH)/kernel/vmlinux.lds

<2>KBUILD_VMLINUX_INIT

linux-3.10.y/Makefile
 765 export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)

①head-y

linux-3.10.y/arch/arm/Makefile
 133 head-y      := arch/arm/kernel/head$(MMUEXT).o 

②init-y

linux-3.10.y/Makefile 
 530 init-y      := init/ 
 756 init-y      := $(patsubst %/, %/built-in.o, $(init-y))

init-y最终等于init/built-in.o

<3>KBUILD_VMLINUX_MAIN

linux-3.10.y/Makefile
 766 export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y)

① core-y

linux-3.10.y/arch/arm/Makefile
 267 # If we have a machine-specific directory, then include it in the build.
 268 core-y              += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/                                                          
 269 core-y              += arch/arm/net/
 270 core-y              += arch/arm/crypto/
 271 core-y              += $(machdirs) $(platdirs)

linux-3.10.y/Makefile
 534 core-y      := usr/ 
 745 core-y      += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
 757 core-y      := $(patsubst %/, %/built-in.o, $(core-y))  

core-y最终等于:

    core-y := usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o

② libs-y

linux-3.10.y/arch/arm/Makefile
 275 libs-y              := arch/arm/lib/ $(libs-y)
 libs-y最终等于arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o

linux-3.10.y/Makefile 
 533 libs-y      := lib/  
 760 libs-y1     := $(patsubst %/, %/lib.a, $(libs-y))                                                                             
 761 libs-y2     := $(patsubst %/, %/built-in.o, $(libs-y))
 762 libs-y      := $(libs-y1) $(libs-y2) 

③drivers-y

linux-3.10.y/Makefile 
 531 drivers-y   := drivers/ sound/ firmware/
 758 drivers-y   := $(patsubst %/, %/built-in.o, $(drivers-y))

drivers-y值最终等于rivers/built-in.o sound/built-in.o firmware/built-in.o

④net-y

linux-3.10.y/Makefile
 532 net-y       := net/ 
 759 net-y       := $(patsubst %/, %/built-in.o, $(net-y))

net-y最终等于net/built-in.o

<4> FORCE

    它的目的是强迫重建vmlinux(无论上边的原材料是否已经构建,无论上边的原材料是否比已经生成的目标新,都要重建),这种用法在Linux Makefile体系中经常见到。 

linux-3.10.y/scripts/Makefile.build 
 461 # Add FORCE to the prequisites of a target to force it to be always rebuilt.
 462 # ---------------------------------------------------------------------------
 463 
 464 PHONY += FORCE
 465 
 466 FORCE:

    可以看到FORCE为一个伪目标,所以无论如何都要重建vmlinux。

<5> 通过编译查看最终的依赖文件

[18:36:20]biao@ubuntu:~test/linux-3.18.y$ sudo make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux- uImage V=1 -n
arm-hisiv500-linux-ld -EL -p --no-undefined -X --build-id -o vmlinux -T ./arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o init/built-in.o --start-group usr/built-in.o arch/arm/vfp/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/net/built-in.o arch/arm/crypto/built-in.o arch/arm/firmware/built-in.o arch/arm/mach-hisi/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o 

    命令中的参数V=1的含义是“顶层Makefile # Use 'make V=1' to see the full commands”。

3.uImage镜像文件的生成

(1)编译目标文件

arch/arm/Makefile
 302 boot := arch/arm/boot
 303 
 304 archprepare:
 305     $(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h
 306 
 307 # Convert bzImage to zImage
 308 bzImage: zImage
 309 
 310 BOOT_TARGETS    = zImage Image xipImage bootpImage uImage
 311 INSTALL_TARGETS = zinstall uinstall install
 312 
 313 PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS)
 314 
 315 $(BOOT_TARGETS): vmlinux
 316     $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

用户输入:make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux- uImag
实际执行的命令是:make -f ./scripts/Makefile.build obj=arch/arm/boot MACHINE= arch/arm/boot/uImage
会进入到arch/arm/boot/的Makefile执行。

(2)目标依赖

①uImage:

arch/arm/boot/Makefile
 92 $(obj)/uImage:  $(obj)/zImage-dtb FORCE                                                                                        
 93     @$(check_for_multiple_loadaddr)
 94     $(call if_changed,uimage)
 95     @$(kecho) '  Image $@ is ready'

②zImage-dtb:

arch/arm/boot/Makefile
 68 $(obj)/zImage-dtb:  $(obj)/zImage $(DTB_OBJS) FORCE
 69     $(call if_changed,cat)
 70     @echo '  Kernel: $@ is ready'

③zImage:

arch/arm/boot/Makefile
 64 $(obj)/zImage:  $(obj)/compressed/vmlinux FORCE
 65     $(call if_changed,objcopy)
 66     @$(kecho) '  Kernel: $@ is ready'

④compressed/vmlinux:

arch/arm/boot/Makefile
 61 $(obj)/compressed/vmlinux: $(obj)/Image FORCE
 62     $(Q)$(MAKE) $(build)=$(obj)/compressed $@

⑤Image:

arch/arm/boot/Makefile
 57 $(obj)/Image: vmlinux FORCE
 58     $(call if_changed,objcopy)
 59     @$(kecho) '  Kernel: $@ is ready'

⑥vmlinux

linux-3.18.y/Makefile
 604 # The all: target is the default when no target is given on the
 605 # command line.
 606 # This allow a user to issue only 'make' to build a kernel including modules
 607 # Defaults to vmlinux, but the arch makefile usually adds further targets                                                     
 608 all: vmlinux

    依赖关系为:uImage->zImage-dtb->zImage->compressed/vmlinux->Image->vmlinux,要生成uImage文件,必须先把它的依赖文件全部生成了。

(3)规则:

上面各个目标的规则基本相同,
①自动化变量

  • $@ 表示规则中的目标文件集
  • $< 依赖目标中的第一个目标名字,如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
  • $(@F) 表示"$@"的文件部分
  • $^所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
  • filter-out 反过滤函数。

(4)Kbuild 自定义命令

如果要为自定义命令使用这一功能,需要设置 2 个变量:

quiet_cmd_<command> - 要显示的命令
cmd_<command> - 要执行的命令

 if_changed:

scripts/Kbuild.include
 236 # Execute command if command has changed or prerequisite(s) are updated.
 237 #
 238 if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \                                                 
 239     @set -e;                                                             \
 240     $(echo-cmd) $(cmd_$(1));                                             \
 241     printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
 208 # if_changed      - execute command if any prerequisite is newer than                                                          
 209 #                   target, or command line has changed

②objcopy:

scripts/Makefile.lib
 240 # Objcopy
 241 # ---------------------------------------------------------------------------
 242 
 243 quiet_cmd_objcopy = OBJCOPY $@
 244 cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@   

linux-3.18.y/Makefile
 362 OBJCOPY     = $(CROSS_COMPILE)objcopy  

arch/arm/Makefile
 22 OBJCOPYFLAGS    :=-O binary -R .comment -S     

实例:arm-hisiv500-linux-objcopy -O binary -R .comment -S vmlinux Image

  • #使用 -O binary (或--out-target=binary) 输出为原始的二进制文件
  • #使用 -R .note  (或--remove-section)    输出文件中不要.note这个section,缩小了文件尺寸
  • #使用 -R .comment(或--remove-section)   输出文件中不要.comment这个section,缩小了文件尺寸
  • #使用 -S (或 --strip-all)输出文件中不要重定位信息和符号信息,缩小了文件尺寸 

③cat

scripts/Makefile.lib
 286 # cat
 287 # ---------------------------------------------------------------------------
 288 # Concatentate multiple files together
 289 quiet_cmd_cat = CAT     $@
 290 cmd_cat = (cat $(filter-out FORCE,$^) > $@) || (rm -f $@; false)

$@ 目标文件, $^ 依赖文件,(filter-out FORCE,$^)方向过滤,将FORCE从依赖文件中去除
(cat arch/arm/boot/zImage arch/arm/boot/dts/hi3520dv400-demb.dtb > arch/arm/boot/zImage-dtb) || (rm -f arch/arm/boot/zImage-dtb; false); 实际上这是一个文件的拼接。

④uimage

scripts/Makefile.lib
 352 quiet_cmd_uimage = UIMAGE  $(UIMAGE_OUT)
 353       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \                                                     
 354             -C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \
 355             -T $(UIMAGE_TYPE) \
 356             -a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \
 357             -n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT)

linux-3.18.y/Makefile
 294 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \                                                               
 295       else if [ -x /bin/bash ]; then echo /bin/bash; \
 296       else echo sh; fi ; fi)

scripts/Makefile.lib
338 MKIMAGE := $(srctree)/scripts/mkuboot.sh  

scripts/Makefile.lib
 342 UIMAGE_ARCH ?= $(SRCARCH) 

linux-3.18.y/Makefile
 256 SRCARCH     := $(ARCH)

scripts/Makefile.lib
 340 # SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces
 341 # the number of overrides in arch makefiles
 342 UIMAGE_ARCH ?= $(SRCARCH)                                                                                                      
 343 UIMAGE_COMPRESSION ?= $(if $(2),$(2),none)
 344 UIMAGE_OPTS-y ?=
 345 UIMAGE_TYPE ?= kernel
 346 UIMAGE_LOADADDR ?= arch_must_set_this
 347 UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
 348 UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)'
 349 UIMAGE_IN ?= $<
 350 UIMAGE_OUT ?= $@

    最终的uimge执行的命令是:/bin/sh ./scripts/mkuboot.sh -A arm -O linux -C none  -T kernel -a 0x80008000 -e 0x80008000 -n '\''Linux-3.18.20'\'' -d arch/arm/boot/zImage-dtb arch/arm/boot/uImage

4.生成镜像文件

    与上面的依赖反过来就是编译生成文件的顺序:
vmlinux : 由顶层Makefile编译生成,在目录linux-3.18.y下 

-rwxr-xr-x 1 root root 8349832 Dec  9 16:14 vmlinux*

Image:由vmlinux压缩得到,文件信息:

-rwxr-xr-x 1 root root 6236864 Dec  9 16:14 Image*

compressed/vmlinux:由Image进一步压缩得到  文件信息:

-rwxr-xr-x 1 root root 3266708 Dec  9 16:14 vmlinux*

zImage:    由compressed/vmlinux压缩的到

-rwxr-xr-x 1 root root 3192168 Dec  9 16:14 zImage*

zImage-dtb: 由zImage和设备树hi3520dv400-demb.dtb拼接而来:

-rw-r--r-- 1 root root 3202016 Dec  6 15:45 zImage-dtb

uImage:由zImage-dtb 添加了64字节头信息得到    

-rw-r--r-- 1 root root 3202080 Dec  6 15:45 uImage

uImage的产生过程已经看完了,但是读者可能会被这有点复杂的关系绕晕了,所以现在可以结合一下的流程图简单地总结一下,下图是zImage的生成过程示意图:

    首先顶层vmlinux是ELF格式的可执行文件,必须将其二进制化生成Image后才可以被bootloader引导。为了实现压缩的内核映像,arch/arm/boot/compressed/Makefile又将这个非压缩映像Image做gzip压缩,生成了piggy.gzip。但要实现在启动时自解压,必须将这个piggy.gzip转化为.o文件,并同初始化程序head.o和自解压程序misc.o一同链接,生成arch/arm/boot/compressed/vmlinux。最后arch/arm/boot/Makefile将这个ELF格式的arch/arm/boot/compressed/vmlinux二进制化得到可被bootloader引导的映像文件zImage。

(四)Linux内核整体编译过程

1、生成准备文件
①控制C程序的头文件

include/linux/version.h include/linux/utsrelease.h、include/linux/autoconf.h

②控制编译连接的文件

arch/arm/kernel/vmlinux.lds、include/config/auto.conf等文件。

2、由C程序源码和汇编语言源码生成目标文件(*.o)
3、将目标文件连接成*.built-in.o、*/lib.a等文件
4、将紧接着顶层目录的子目录中的*.built-in.o以及部分重要的*.o文件连接生成vmlinux
5、根据arch/arm/Makefile的规则生成zImage、uImage等

(五)Linux内核编译构成元素

1.Makefile的目标

(1)总目标

  总目标实际上是在arch/arm/Makefile中定义了,比方说zImage、uImage,顶层Makefile紧接着定义了这些终极目标直接的依赖目标vmlinux。

(2)各级子目标

  各级子目标是在scripts/Makefile.build中的__build中定义的,例如传递参数obj=drivers后的目标是drivers/built-in.o。
  这些目标的依赖其实又成为了新的目标,例如drivers/net/built-in.o、drivers/net/dm9000.o。

2.Makefile的依赖

(1)总目标的依赖

  KBUILD_LDS、KBUILD_VMLINUX_INIT、KBUILD_VMLINUX_MAIN

(2)各级子目标的依赖

  各级子目标的依赖是由子目录中的Makefile(实际是scripts/Makefile.build的包含文件)和scripts/Makefile.lib共同完成确定的。
  子目录中的Makefile负责选材,而scripts/Makefile.lib负责加工。

3.Makefile的规则

(1)总目标的连接规则

  总目标vmlinux的连接规则就是在顶层Makefile中定义的,至于zImage、uImage则是在arch/arm/Makefile中定义的。

(2)子目标的编译连接规则

  主要是在scripts/Makefile.build、scripts/Kbuild.include中定义的,其中scripts/Kbuild.include定义了许多诸如if_changed的函数。

(六)Linux内核Makefile特点

1.两个Makefile

 顶层Makefile文件负责将各个目录生成的*.built-in.o、lib.a等文件连接到一起生成vmlinux。而scripts/Makefile.build 包含子目录中的Makefile文件以及scripts/中的众多脚本来生成这些*.built-in.o、lib.a、*.o等文件。
  通过“make -f scripts/Makefile.build obj=”的方法完成了顶层Makefile到scripts/Makefile.build的调用生成*/built-in.o,以及scripts/Makefile.build的自调用生成更低一级子目录的*/built-in.o。

2.编译的目录始终是顶层目录

  “make -C”命令会先切换工作目录,然后执行该目录中的Makefile,u-boot就是采用这种方法。而linux则是利用“make -f”的方法,所以编译的目录始终是顶层目录。

3.通用规则

  Linux内核Makefile的通用子Makefile是scripts/Makefile.build,而通用的其他规则则是scripts中的其他文件。

(七)引用与致谢:

发布了164 篇原创文章 · 获赞 229 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/li_wen01/article/details/103466337