linux驱动编译系统
来源:互联网 发布:python 有序字典 编辑:程序博客网 时间:2024/06/06 10:41
前言
从Linux内核2.6开始,Linux内核的编译采用Kbuild系统,这同过去的编译系统有很大的不同,尤其对于Linux内核模块的编译。在新的系统下,Linux编译系统会多次扫描Linux的Makefile。
范列
下面我们通过一个简单的驱动示例,来熟悉linux的编译系统,驱动代码如下:
/** test.c -- the example of printf "hello world!" in the screen of driver program*/#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("Dual BSD/GPL");/* declare the license of the module ,it is necessary */static int hello_init(void){ printk(KERN_EMERG "Hello World enter!\n"); return 0;}static void hello_exit(void){ printk(KERN_EMERG "Hello world exit!\n");}module_init(hello_init); /* load the module */module_exit(hello_exit); /* unload the module *//* before is some decription of the model,not necessary */MODULE_AUTHOR("Jalon Xiao");MODULE_DESCRIPTION("This is an example of programming driver!");
Makefile源码如下:
ifneq ($(KERNELRELEASE),) $(warning A top-level warning)obj-m := test.o else$(warning A Bottom-level waring).PHONY: modules cleanKERNELDIR =/usr/src/linux-headers-3.2.0-24-genericPWD := $(shell pwd)modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versionsendif
将上面的源码保存在同一目录下,在命令终端运行make可以编译test模块,linux编译系统会编译生成test.ko内核模块。
从上面的编译截图可以看出内核编译系统会两次读取编译模块makefile。后面的打印A top-level warning都为内核编译系统的读取,第一次为make读取。make在执行读取并执行Makefile时,由于没有定义KERNELRELEASE.会执行else后面的目标,第一个目标modules为默认目标。
Kbuild的编译目标
obj-m和obj-y都是Kbuild编译系统的目标。
列如obj-y += foo.o,它告诉kbuild在当前目录下,有一个叫做foo.o的目标文件,它将从foo.c或则foo.S编译得到。
或者obj-m += foo.o,同样告诉kbuild在当前目录下,有一个叫做foo.o的目标文件,它将从foo.c或则foo.S编译得到。
不同的是Kbuild编译完所有的
最简单的kbuild Makefile可以仅包含:
obj-$(CONFIG_FOO) += foo.o
其中CONFIG_FOO可以等于y或m,它的值由.config文件给出。如果$(CONFIG_FOO)既不是y也不是m,那么该文件不会被编译和链接.
如果一个驱动模块不是由一个源文件编写时,makefile应按照如下规则进行,否则会出现
/work/mtkv1.33/kernel/drivers/net/wireless/DPO_RT5572_LinuxSTA_2.6.0.1_20120629/common/crypt_sha2.c:549:1: fatal error: opening dependency file drivers/net/wireless/DPO_RT5572_LinuxSTA_2.6.0.1_20120629/common/.crypt_sha2.o.d: No such file or directorycompilation terminated.
类似的错误!
所以当某个目标由多个源文件编译得到时,可以通过$(<module_name>-objs)或$(<module_name>-y)
把这些源文件告诉kbuild。Kbuild能够识别后缀-objs和-y/-m,例如:
#drivers/isdn/i4l/Makefile obj-$(CONFIG_ISDN) += isdn.o isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
Kbuild会编译所有$(isdn-objs)中的对象,并调用"$(LD) -r"
把它们链接成isdn.o文件。
Kbuild编译选项变量
Makefile里常用的编译选项,参见内核目录:Document/kbuild/modules.txt和Document/kbuild/makefiles.txt。
ccflags-y、asflags-y和ldflags-y分别对应EXTRA_CFLAGS、EXTRA_AFLAGS和EXTRA_LDFLAGS三个,分别用于$(CC)、$(AS)、$(LD)
。这三个变量只在当前Makefile中有效。
为驱动模块添加外部头文件的方法:在文件Kbuild里通过内核关键字EXTRA_CFLAGS来指定。具体为:
EXTRA_CFLAGS += -I$(EXTERNAL_INC) -I$(LOCAL_INC)
# file dev_var_def.mkPWD := $(shell pwd)EXTRERNAL_INC := $(PWD)/../includeLOCAL_INC := $(PWD)
另外还有subdir-ccflags-y、subdir-asflags-y
这两个变量作用于当前Makefile及其所有子目录。
这里只介绍了常用的编译选项,其他的参考内核文档。
Kbuild调用子目录Makefile
Makefile只负责编译当前目录中的对象。子目录中的对象,由子目录中的Makefile负责。如何让make调用子目录中的Makefile?答案是把子目录包含到obj-y或obj-m中。例如:
#fs/Makefile obj-$(CONFIG_EXT2_FS) += ext2/
Kbuild lib库对象
在一个目录下,obj-y所列出的文件,将被编译成built-in.o文件,而lib-y或lib-m所列出的文件,将在当前目录下生成lib.a文件。
注意:一般lib-y或lib-m只用在lib/和arch/*/lib这两个目录中。
较全面的makefile模板
MODULE_NAME=test#####################in order to unify with the make menuconfig,should define to CONFIG_$(MODULE_NAME)MODULE_CONFIG=CONFIG_TEST #############IF not config by make menuconfig,should define MODULE_CONFIG#define m to compile MODULE_NAME.ko#CONFIG_TEST=m CROSS_CONFIG=nDEBUG = yifneq ($(KERNELRELEASE),) #########################kbuild system start to compile$(warning A top-level warning)# Add your debugging flag (or not) to CFLAGSifeq ($(DEBUG),y) DEBFLAGS = -O -g -DDEBUG # "-O" is needed to expand inlineselse DEBFLAGS = -O2endifEXTRA_LDFLAGS += $(DEBFLAGS) #ccflags-y#obj-$($(MODULE_CONFIG)) := $(MODULE_NAME).o #why no ok?????obj-m := $(MODULE_NAME).o#for Multi-files module#$(MODULE_NAME)-objs += else########################first read this makefile$(warning A Bottom-level waring)#######################define the compile toolsifeq ($(CROSS_CONFIG), y)#for Cross-compileKERNELDIR =/home/xiaojingling/work/mtkv1.33/kernelARCH = arm#FIXME:maybe we need absolute path for different user. eg root#CROSS_COMPILE = arm-none-linux-gnueabi-CROSS_COMPILE = INSTALLDIR := $(shell pwd)else#for Local compileKERNELDIR = /usr/src/linux-headers-3.2.0-24-genericARCH = x86#only need the prefix of the tools,similar to arm compiling toolsCROSS_COMPILE = INSTALLDIR := ./endif########################end of defining the toolsPWD := $(shell pwd).PHONY: modules cleanmodules: $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modulesclean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versionsendif
问题:
#obj-$($(MODULE_CONFIG)) := $(MODULE_NAME).o #why no ok?????这样定义的时候居然不能编译目标,不知道哪里出了问题。若这样定义成功可以方便集成到kernel内部。obj-m := $(MODULE_NAME).o
需要编译其他的模块时,更具实际情况修改如下值就可以了:
MODULE_NAME=test #目标名CROSS_CONFIG=n #交叉编译时为yDEBUG = y #调试选项
关于上面的makefile更详细的请参考Linux内核模块LKM编译-自制Makefile模板
参考文档:
Linux 2.6内核Makefile浅析
Linux内核模块LKM编译-自制Makefile模板
Makefile编译选项
Android 驱动之旅
- linux驱动编译系统
- Linux系统驱动编译与运行
- Linux编译声卡驱动
- linux 驱动 编译 Makefile
- linux本地驱动编译
- 编译Linux驱动相关
- linux 驱动模块编译
- Linux-驱动编译流程
- linux编译驱动环境
- 初学Linux驱动编译
- Linux驱动编译
- linux内核驱动编译
- Linux系统驱动开发
- Linux系统驱动开发
- Linux系统按键驱动
- Linux系统PWM驱动
- Linux系统PWM驱动
- Linux驱动编译进内核-GPIO驱动
- NFS
- Sicily 1843. Pyramid
- 如何使用firefox适用于javascript的debugger命令
- Could not create JarEntryRevision
- [Yum]Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again
- linux驱动编译系统
- hadoop2 单机搭建
- Python错误: SyntaxError: Non-ASCII character
- Android 关于inflate
- linq to xml
- Sicily 1841. Atom Transit
- HBuilder下的HTML5 Plus
- NYOJ 525--一道水题【水题(strtok)】
- 我排第几个