zoukankan      html  css  js  c++  java
  • Linux Makefile分析

    目的:

      分析Makefile在内核中的作用

    Makefile的作用总结:

      1)决定编译哪些文件?

      2)怎样编译这些文件?

      3)怎样连接这些文件,最重要的是他们的顺序如何?

    1、linux内核中Makefile体系

    顶层Makefile

    所以Makefile的核心,根据不同平台,对各类target分类并调用相应的规则Makefile生成目标

    .config

    配置文件,配置内核是生成。所有Makefile都是根据 .config 来决定使用哪些文件

    arch/$(ARCH)/Makefile

    具体平台相关的Makefile,相关决定哪些体系结构相关的文件参与内核的生成

    scripts/Makefile.*

    通用规则文件,面向所有的Kbuild Makefiles

    各子目录下的Makefile 文件

    由其上层目录的Makefile调用,执行其上层传递下来的命令

      根据Makefile的3大作用分析这5类文件。

      (1)决定编译哪些文件

        linux内核的编译是从顶层的Makefile开始的,然后递归地进入各级子目录调用各自的Makefile,分为3个步骤:

        a、顶层Makefile决定内核目录下哪些子目录将被编进内核

        b、arch/$(ARCH)/Makefile 决定所在目录下哪些文件、目录编入内核

        c、各级子目录下的Makefile决定所在目录下哪些文件编入内核,哪些文件编成模块(即驱动程序),进入哪些子目录继续调用他们的Makefile。

        先看步骤A,在顶层Makefile可看到:

    # Objects we will link into vmlinux / subdirs we need to visit
    init-y          := init/
    drivers-y       := drivers/ sound/
    net-y           := net/
    libs-y          := lib/
    core-y          := usr/
    ......
    core-y          += kernel/ mm/ fs/ ipc/ security/ crypto/ block/

        可知,顶层Makefile将内核下的目录分为5类,

        init-y :   drivers-y :   net-y :    libs-y :core-y 

        (arch目录会在arch/$(ARCH)/Makefile 中被包含入内核)

        可以在顶层目录的Makefile修改ARCH变量,如下

    //修改前
    ARCH           ?= $(SUBARCH)
    ARCH            ?= ?
    
    //修改后
    ARCH            ?= arm
    CROSS_COMPILE   ?= arm-linux-

       对于步骤B的arch/$(ARCH)/Makefile,以ARM体系为例,在arch/arm/Makefile中可看到:

    ......
    core-y                += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
    core-y                += $(MACHINE)
    ...
    core-$(CONFIG_ARCH_S3C2410)    += arch/arm/mach-s3c2440/
    core-$(CONFIG_ARCH_S3C2410)    += arch/arm/mach-s3c2442/
    ...
    core-$(CONFIG_FPE_NWFPE)    += arch/arm/nwfpe/
    core-$(CONFIG_FPE_FASTFPE)    += $(FASTFPE_OBJ)
    core-$(CONFIG_VFP)        += arch/arm/vfp/
    ......

      可以看到Makefile对core-y的内容进行了进一步的扩展,在这个Makefile中,出现了另一类:head-y,不过它是直接以文件名出现的。

    #Default value
    head-y        := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o

      编译内核时,将依次进入init-y :   drivers-y :   net-y :    libs-y :core-y 所列出的目录中执行各自的Makefile,每个子目录都会生成一个build-in.o ,最后head-y所表示的文件将和这些build-in.o一起连接成内核印象文件 vmlinux。

      最后,看看步骤C怎么进行的:

      步骤3的作用:“各级子目录下的Makefile决定所在目录下哪些文件编入内核,哪些文件编成模块(即驱动程序),进入哪些子目录继续调用他们的Makefile“”

      在配置内核时,会生成.config ,在顶层Makefile中会有以下语句间接包含.config文件,以后就根据.config中定义的各变量决定编译时用哪些文件(实际包含的是与.config等效的auto,conf)

    # Read in config
    -include include/config/auto.conf

      auto.conf内容如下:

    # Automatically generated make config: don't edit
    # Linux kernel version: 2.6.22.6
    # Wed Feb 19 07:48:42 2020
    CONFIG_CPU_S3C244X=y
    CONFIG_CPU_COPY_V4WB=y
    CONFIG_DEBUG_USER=y
    CONFIG_FLATMEM=y
    ...

       这些变量的值主要有两类,"y" , "m"。各级子目录的Makefile使用这些变量决定哪些文件编进内核,哪些文件编成模块,要进入哪些子目录继续决定编译。具体通过以下方法确定:

      1)obj-y 用来决定哪些文件编进内核

      2)obj-m 用来定义哪些文件编成可加载模块

      3)lib-y 用来定义哪些文件编成库文件

      4)obj-y , obj-m 还可以用来指定要进入的下一层目录

    (2)怎样编译这些文件。

      即编译选项、连接选项是什么。这些选项分为3类:全局的(适用于整个南海代码树);局部的(仅适用某个Makefile中的文件);个体的(仅适用某个文件)

      全局选项在顶层Makefile和arch/$(ARCH)/Makefile 中定义,局部选项在各个子目录的Makefile中。

    (3) 怎样连接这些文件,它们的顺序如何

      在前面分析哪些文件会编进内核时,知道顶层Makefile和 arch/$(ARCH)/Makefile 定义了6类目录(或文件):

      head-y ,  init-y , drivers-y ,  net-y , libs-y , core-y 。以ARM体系为例,它们的初始值如下:

      在arch/arm/Makefile 中:

    head-y        := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
     
    core-y                += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
    core-y                += $(MACHINE)
    ...
    core-$(CONFIG_ARCH_S3C2410)    += arch/arm/mach-s3c2440/
    core-$(CONFIG_ARCH_S3C2410)    += arch/arm/mach-s3c2442/
    ...
    libs-y                := arch/arm/lib/   $(libs-y)

      在顶层Makefile中:

    443 - 556行
    init-y := init/ drivers-y := drivers/ sound/ net-y := net/ libs-y := lib/ core-y := usr/ ...... core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/

     可见,除了head-y之外,其余的init-y , drivers-y等都是目录名。在顶层Makefile中,这些目录名的后面直接加上build-in.o 或 lib.a ,表示要链接进内核的文件,如下所示:

    567 - 573行                                       等价于箭头后的表达
    init-y        := $(patsubst %/, %/built-in.o, $(init-y)) ---> init/build-in.o
    core-y        := $(patsubst %/, %/built-in.o, $(core-y)) ---> core/build-in.o
    drivers-y    := $(patsubst %/, %/built-in.o, $(drivers-y))--> drievrs/build-in.o
    net-y        := $(patsubst %/, %/built-in.o, $(net-y))
    libs-y1        := $(patsubst %/, %/lib.a, $(libs-y))
    libs-y2        := $(patsubst %/, %/built-in.o, $(libs-y))
    libs-y        := $(libs-y1) $(libs-y2)

      在顶层Makefile中,再往下看:

    602 - 605 行
    vmlinux-init := $(head-y) $(init-y) vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) vmlinux-all := $(vmlinux-init) $(vmlinux-main) vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds export KBUILD_VMLINUX_OBJS := $(vmlinux-all)

      vmlinux-all 表示所有构成内核印象文件vmlinux的目标文件,带入后等价于以下:

    vmlinux-all  := $(head-y) $(init-y)  $(core-y) $(libs-y) $(drivers-y) $(net-y)

      已知上面的这些文件init-y等会生成对应的文件init/build-in.o文件被编译进内核。

      vmlinux-lds表示连接脚本。顶层Makefile会按照一定的顺序组织文件,根据此链接脚本生成内核映像文件。

    vmlinux
    #   ^
    #   |
    #   +-< $(vmlinux-init)
    #   |   +--< init/version.o + more
    #   |
    #   +--< $(vmlinux-main)
    #   |    +--< driver/built-in.o mm/built-in.o + more
    #   |
    #   +-< kallsyms.o (see description in CONFIG_KALLSYMS section)

    参考:

    《linux应用开发完全手册》 --韦东山

    https://www.cnblogs.com/lifexy/p/7348534.html
  • 相关阅读:
    Curl Get请求&漏参数
    【Java基础】日期操作(返回当前日期&日期比较)
    【Java基础】生产者消费者模式
    [Groovy] 在Groovy中优雅的实现do while
    【转载】时间复杂度的度量
    [转载]Spring Cloud初探
    [Maven] 使用Maven管理多模块项目
    JS基础三
    JS基础部分(二)
    笔记不详细记录了,学完css之后做出下面分布的导航页
  • 原文地址:https://www.cnblogs.com/y4247464/p/12334193.html
Copyright © 2011-2022 走看看