makefile在内核中编译(一)

编译进内核的模块:

如果需要将一个模块配置进内核,需要在makefile中进行配置:                                                

obj-y += disp.o

 将disp.o编译进内核,根据make的自动推导原则,make将会自动将disp.c编译成disp.o。该方法为编译单独模块。  当编译整个内核时,在top makefile中这样写:

obj-$(CONFIG_DISP2_SUNXI) += disp.o

 .config文件中将CONFIG_DISP2_SUNXI变量配置为y,要修改模块编译行为时,可在配置文件中修改,而不用到makefile去找。

在一个目录下,obj-y所列出的文件,将被编译成built-in.o文件。而lib-y或lib-m所列出的文件,将在当前目录下生成lib.a文件。 (注意:一般lib-y或lib-m只用在lib/和arch/*/lib这两个目录中)。

$(CONFIG_DISP2_SUNXI) 是一个整体,$(CONFIG_DISP2_SUNXI)表示引用变量 CONFIG_DISP2_SUNXI。比如定义 CONFIG_DISP2_SUNXI=y;$(CONFIG_DISP2_SUNXI)就是y;obj-$(CONFIG_DISP2_SUNXI) 就是 obj-y。

编译可加载的模块:

配置文件中标记为-m的模块将被编译成可加载模块.ko文件。

如果需要将一个模块配置为可加载模块,需要在makefile中进行配置:

obj-m += disp.o

同样的,通常可以写成这样的形式:

obj-$(CONFIG_DISP2_SUNXI) += disp.o

在.config文件中将CONFIG_DISP2_SUNXI变量配置成m,在配置文件中统一控制,编译完成时将会在当前文件夹中生成disp.ko文件,在内核运行时使用insmod或者是modprobe指令加载到内核。

模块编译依赖多个文件

单独编译自己开发的驱动模块,当一个驱动模块依赖多个源文件时,需要通过以下方式来指定依赖的文件:

obj-m += disp.o
disp-y := a.o b.o c.o

disp.o 由a.o,b.o,c.o生成,然后调用$(LD) -r 将a.o,b.o,c.o链接成disp.o文件。

同样地,makefile支持以变量的形式来指定是否生成disp.o,我们可以这样:

obj-$(CONFIG_DISP2_SUNXI) += disp.o
disp-$(CONFIG_EINK_PANEL_USED) += de/disp_eink_manager.o de/eink_pipeline_manager.o

根据CONFIG_FOO_XATTR的配置属性来决定是否生成disp.o,然后根据CONFIG_DISP2_SUNXI属性来决定将disp.o模块编入内核还是作为模块。

objs用法:
obj-y = disp.o
disp-objs := dev_disp.o dev_disp_debugfs.o

将dev_disp.c dev_disp_debugfs.c两个文件编译后链接生成disp.o

makefile目录层次关系的处理

一个原则就是:一个makefile只负责处理本目录中的编译关系,自然地,其他目录中的文件编译由其他目录的makefile负责,整个linux内核的makefile组成一个树状结构,对于上层makefile的子目录而言,只需要让kbuild知道它应该怎样进行递归地进入目录即可。

kbuild利用目录指定的方式来进行目录指定操作,举个例子:

obj-$(CONFIG_DISP2_SUNXI) += de/

当CONFIG_DISP2_SUNXI被配置成y或者m时,kbuild就会进入到de/目录中,但是需要注意的是,这个信息仅仅是告诉kbuild应该进入到哪个目录,而不对其目录中的编译做任何指导。kbuild系统会在de目录中调用make命令(即de目录中的Makefile)

参考如下:

obj-$(CONFIG_DISP2_SUNXI) += disp.o

disp-objs	:= dev_disp.o disp_sys_intf.o
disp-objs	+= de/disp_display.o de/disp_features.o de/disp_device.o de/disp_lcd.o de/disp_manager.o de/disp_private.o \
			   de/disp_smart_backlight.o de/disp_enhance.o de/disp_capture.o de/disp_hdmi.o de/disp_tv.o  de/disp_vga.o de/disp_vdevice.o \
			   de/disp_edp.o

disp-$(CONFIG_EINK_PANEL_USED) += de/disp_eink_manager.o de/eink_pipeline_manager.o

disp-objs += lcd/panels.o lcd/lcd_source.o lcd/default_panel.o


disp-$(CONFIG_LCD_SUPPORT_HE0801A068) += lcd/he0801a068.o
disp-$(CONFIG_EINK_PANEL_USED) += lcd/default_eink.o
disp-$(CONFIG_LCD_SUPPORT_LT070ME05000) += lcd/lt070me05000.o
  CHK     include/config.h
  CFG     u-boot.cfg
  CHK     include/generated/version_autogenerated.h
  CHK     include/generated/generic-asm-offsets.h
  CHK     include/generated/asm-offsets.h
  HOSTCC  tools/mkenvimage.o
  HOSTCC  tools/fit_image.o
  HOSTCC  tools/image-host.o
  HOSTCC  tools/dumpimage.o
  HOSTCC  tools/mkimage.o
  HOSTCC  tools/sunxi-spl-image-builder.o
  HOSTLD  tools/mkenvimage
  HOSTLD  tools/sunxi-spl-image-builder
  HOSTLD  tools/dumpimage
  HOSTLD  tools/mkimage
  CC      board/sunxi/sunxi_bootargs.o
  CC      cmd/version.o
  CC      common/main.o
  LD      cmd/built-in.o
  LD      common/built-in.o
  LD      board/sunxi/built-in.o
  CC      drivers/video/sunxi/disp2/disp/lcd/panels.o
  CC      drivers/video/sunxi/disp2/disp/lcd/lcd_source.o
  CC      drivers/video/sunxi/disp2/disp/lcd/default_panel.o
  CC      drivers/video/sunxi/disp2/disp/lcd/he0801a068.o
  CC      drivers/video/sunxi/disp2/disp/lcd/bp101wx1-206.o
  LD      drivers/video/sunxi/disp2/disp/disp.o
  LD      drivers/video/sunxi/disp2/disp/built-in.o
  LD      drivers/video/sunxi/disp2/built-in.o
  LD      drivers/video/sunxi/built-in.o
  LD      drivers/video/built-in.o
  LD      drivers/built-in.o
  CC      lib/display_options.o
  LD      lib/built-in.o
  LD      u-boot
  OBJCOPY u-boot.srec
  OBJCOPY u-boot-nodtb.bin

在Linux内核里,每个子目录都有一个makefile,它被称作Kbuilt-makefile,它将当前目录的文件编译成built-in.o、以及库文件、模块文件。然后顶层Makefile里指定这些built-in.o的路径,将它们连接在一起。

Linux 内核Makefile 分类

内核makefile.txt中将makefile分为 5部分,Kernel Makefile、ARCH Makefile、KBuild Makefile、.config文件以及scripts/Makefile.*

1.Kernel Makefile

Kernel Makefile位于Linux内核源代码的顶层目录,也叫Top Makefile 。它主要用于指定编译Linux Kernel 目标文件(vmlinux)和模块(module)路径。它根据.config文件决定了内核根目录下那些文件、子目录被编译进内核。对于内核或驱动开发人员来说,这个文件几乎不用任何修改。

2.ARCH Makefile

ARCH Makefile位于ARCH/$(ARCH)/Makefile,是系统对应平台的Makefile 。Kernel Top Makefile 会包含这个文件来指定平台相关信息。ARCH Makefile同样根据.config文件,决定了ARCH/$(ARCH) 目录下 那些文件、子目录被编译进内核 只有平台开发人员会关心这个文件。

3.Kbuild Makefile

从Linux内核2.6开始,Linux内核的编译采用Kbuild系统 ,这同过去的编译系统有很大的不同,Kbuild 系统使用Kbuild Makefile 来编译内核或模块。当Kernel Makefile 被解析完成后,Kbuild 会读取相关的Kbuild Makefile 进行内核或模块的编译。Kbuild Makefile 有特定的语法指定哪些编译进内核中、哪些编译为模块、及对应的源文件是什么等。内核及驱动开发人员需要编写这个Kbuild Makefile 文件。

4.scripts/Makefile.*通用规则

Makefile.build

被顶层Makefile所调用,与各级子目录的Makefile合起来构成一个完整的Makefile文件,定义built-in.o、.lib以及目标文件.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

5.  .config

来自配置过程,生成 auto.conf 以及 autoconf.h,被顶层Makefile所包含

Kbuild Makefile

内核虽然有自己的构建系统Kbuild,但是kbuild 并不是什么新的东西,我们可以把kbuild 看作利用GNU Make组织的一套复杂的构建系统,虽然kbuild 也在Make 基础上做了适当的扩展,但是因为内核的复杂性,所以kbuild 要比一般的项目的Makefile 的组织要复杂的多。为了方便Linux开发者能够编写Makefile,kbuild考虑得不可谓不周到,比如,kbuild将所有与编译过程相关的共用规则和变量都提取到scripts 目录下的Makefile.build中,而具体的子目录下的 Makefile 文件则可以编写的非常简单与直接。

大多的Kbuild 文件的名字都是Makefile 。为了与其他Makefile 文件相区别,你也可以指定Kbuild Makefile 的名字为 Kbuild 。而且如果“Makefile ”和“Kbuild ”文件同时存在,则Kbuild 系统会使用“Kbuild ”文件。Kbuild Makefile 就是各个子目录的Makefile ,它的作用就是指定当前目录下的文件,哪些被编译进当前目录的built-in.o、那些被编译成模块、那些不编译。

Kbuild Makefile 的一个最主要功能就是指定编译什么,这个功能是通过下面两个对象指定的obj-? 和xxx-objs

例如:

obj-y += foo.o
             obj-m += abc.o

大多数情况下是这样:

obj-$(CONFIG_DM9000) += dm9000.o

具体的 CONFIG_DM9000 是y 还是m取决于配置过程,配置过程产生.config文件,.config又产生auto.conf以及autoconf.h文件,包含在makefile文件里。

如果内核模块是通过几个源文件编译而成的,您可以使用和上面同样的方法指定您想要编译的模块.然而此时Kbuild需要知道编译模块时是基于那些目标文件的,因此您需要设置一个$(<module_name>-objs)变量来告诉编译器.

例如:#drivers/isdn/i4l/Makefile
              obj-$(CONFIG_ISDN) += isdn.o
              isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

用 obj-* 连接的Objects 在指明的文件夹中被用作模块或者综合进built-in.o 。也又可能被列出的objects 将会被包含进一个库,lib.a 。所有用lib-y 列出的objects 在那个文件夹中被综合进单独的一个库。列在obj-y 且 附加列在lib-y 中的Objects 将不会被包含在库中,因为他们将会被任意的存取。对于被连接在lib-m 中,连续的objects 将会被包含在lib.a 中。值得注意的是kbuild makefile 可能列出文件用作built-in ,并且作为库的一部分。因此,同一个文件夹可能包含一个built-in.o 和lib.a 文件

例如:

lib-y    := checksum.o delay.o

这里讲会创建一个基于checksum.o 和delay.o 的库文件。对于kbuild ,识别一个lib.a 正在被构建,这个文件夹应该被列在 libs-y 中。 lib-y 的使用方法通常被限制在lib/ 和arc/*/lib 中。

Kernel Makefile

/* 指定 平台、编译器 */
        ARCH        ?= arm

        CROSS_COMPILE    ?= arm-linux-

/* 设置 6 类文件编译路径 */
        init-y        := init/

        drivers-y    := drivers/ sound/ firmware/

        net-y        := net/

        libs-y        := lib/

        core-y        := usr/

        core-y        += kernel/ mm/ fs/ ipc/ security/ crypto/ block/


/* 包含 ARCH Makefile 在通用编译路径基础上增加 架构相关的路径 */
        include $(srctree)/arch/$(SRCARCH)/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                += $(machdirs) $(platdirs)

        core-$(CONFIG_FPE_NWFPE)    += arch/arm/nwfpe/

        core-$(CONFIG_FPE_FASTFPE)    += $(FASTFPE_OBJ)

        core-$(CONFIG_VFP)        += arch/arm/vfp/

        drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/

        libs-y                := arch/arm/lib/ $(libs-y)

/* 指定路径下的built-in.o 文件 */

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

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

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

        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)

$(patsubst A, AB, C) 会将AB中的A替换为C
例如:

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

        $(net-y) == net/

        将 %/built-in.o中的%/替换为net/

结果为:net/built-in.o

/* 最终链接成vmlinux-all */

        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/$(SRCARCH)/kernel/vmlinux.lds

        export KBUILD_VMLINUX_OBJS := $(vmlinux-all)

根据 vmlinux-all 我们可以得出文件的排放顺序,

                head-y        路径下的built-in.o

                init-y            路径下的built-in.o

                core-y         路径下的built-in.o

                libs-y           路径下的built-in.o

                drivers-y     路径下的built-in.o

                net-y           路径下的built-in.o
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值