Makefile --- linux 驱动 makefile 逐行解析

 

 linux 驱动所用 Makefile 介绍

1、目标定义:目标定义就是用来定义哪些内容作为模块编译,哪些要编译并链接进内核。

obj-y += foo.o

  表示要由foo.c或者foo.s文件编译得到foo.o并链接进内核(无“条件编译”,所以不需要Kconfig配置),而obj-m则表示该文件要作为模块编译、obj-n形式的目标不会被编译。

  更常见的做法根据make menuconfig后生成的.config文件的CONFIG_变量来决定文件的编译方式,如:

  obj-$(CONFIG_ISDN) += isdn.o

  obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

  除了具有obj-形式的目标以外,还有lib-y library库、hostprogs-y主机程序等目标,但是这两类基本都应用在特定的目录和场合下。

2、多文件模块的定义

  最简单的Makefile仅需一行代码就够了。如果一个模块由多个文件组成,会稍微复杂一点,这时候应采用模块名加-y或-objs后缀的形式来定义模块的组成文件,如下:

  obj-$(CONFIG_EX2_FS) += ext2.o

  ext2-y := balloc.o dir.o file.o fsync.o ialloc.o inode.o \

      ioctl.o namei.o super.o symlink.o

  ext2-$(CONFIG_EXT2_FS_XATTR)        += xttr.o xttr_usr.o xattr_trusted.o

  ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o

  ext2-$(CONFIG_EXT2_FS_SECURITY)   += xattr_security.o

  ext2-$(CONFIG_EXT2_XIP)                  += xip.o

  模块的名字为ext2,由balloc.o、dir.o、file.o等多个目标文件最终链接生成ext2.o直至ext2.ko文件,并且是否包括xattr.o、acl.o等则取决于内核配置文件的配置情况,例如,如果CONFIG_EXT2_FS_POSIX_ACL被选择,则编译acl.c得到acl.o并最终链接进ext2。

3、目录层次的迭代

  如下例:

  obj-$(CONFIG_EXT2_FS) += ext2/

  当CONFIG_EXT2_FS的值为y或则m时,Kbuild将会把ext2目录列入向下迭代的目标中。

 

 

note: Makefile中的M是大写

For example:

obj-m:=HelloWorld.o
KDIR:=/home/god/Desktop/raspberry/linux    # path of kernel file
PWD:=$(shell pwd)  # path of current file
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules @rm -rf *.mod.* @rm -rf *.o @rm -rf Module.* @rm -rf modules.* clean: $(MAKE) -C $(KDIR) M=$(PWD) clean

注:all 和 clean 的后面几行前面都是Tab,不是4个空格!

obj-m:=HelloWorld.o: HelloWorld 是c源文件的文件名,根据 HelloWorld.c 生成 HelloWorld.o,HelloWorld.o 是中间文件

$(MAKE):等价于make,all 和 clean 都是 make 的参数,如果 make 没有带参数,默认执行 Makefile 第一个出现的参数对应的内容,上面的例子是 all。执行 make 命令会寻找Makefile

KDIR:是linux内核文件根目录

PWD:是源文件目录,即 .c 文件和 Makefile 所在文件目录

-C $(KDIR): 表示先跳转到内核源码根目录再执行那里的Makefile,M=$(PWD) 表示把源文件目录赋值给 M,M的值作为变量再传递到内核源码根目录的 Makefile 里面

modules:modules是内核源码根目录下 Makefile 的目标,make M=dir 和 make M=dir modules 一样,所以此处也可以不加 modules

@rm -rf *.o:@表示这个指令不打印到 shell 窗口上

 

 如果内核根目录下的 Makefile 需要添加环境变量,可以先在shell执行如下语句:

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

 

 

 

# Makefile2.6
ifneq ($(KERNELRELEASE),)
#kbuild syntax. dependency relationshsip of files and target modules are listed here.
mymodule-objs := hello.o
obj-m := hello.o  
else
PWD  := $(shell pwd)
KVER ?= $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
       $(MAKE) -C $(KDIR) M=$(PWD)
clean:
       rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions
endif
KERNELRELEASE 是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义,所以make将读取执行else之后的内容。
当make的目标为all时,-C $(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD)指在试图建立模块目标前,回到模块源码目录
当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句, 指明模块源码中各文件的依赖关系,以及要生成的目标模块名。
每个内核的名字都包含了它的版本号,这也是 uname -r 命令显示的值。

 

 

 

note:

make modules是编译模块,很多驱动还有功能在选的时候选成M的都是modules,不过直接make,不加任何参数,就是make all,包含make modules。不用额外加此make,但是在安装的时候make install只是安装bzimage,Systemmap。没有把modules安装好,还要额外的make modules_install,把模块放到/lib/modules文件夹一个和内核名一样的文件夹下,并且运行depmod生成模块依赖关系文件,系统启动时加载模块就是从dep里面读取信息加载模块。

 




posted @ 2016-12-13 22:47  流水灯  阅读(46)  评论(0编辑  收藏  举报