none
分类: LINUX
2010-11-24 14:38:01
网上有好多关于驱动的Makefile怎么写,驱动程序怎么运行,为什么驱动会没有main等等问题的问题的问题。下面我也给出我的驱动Makefile模板,这些东东都是在书籍和人家的研究成果上改进而来的,至于如何使用、怎么修改成自己的,大家就随意好了。
驱动测试有两种方式,一为内核树之内,一为内核树以外,前者有点复杂,涉及到将驱动放到合适的内核树目录,修改相应的Makefile以及Kconfig文件,不过,天下无难易之事,为之,难亦不难了;后者所做的劳动就不用那么多了,网上很多是使用这种方法,鄙人也随大流了。这个Makfile只适合于后者,特此说明。此外,内核的Makefile跟一般的应用程序的Makefile不太一样,就像驱动程序跟应用程序,内核头文件跟应用程序头文件等等,没必然关系,或者说是两码事,两者不能混为一谈。再有一点,驱动是跟内核打交道的,你的系统中必须有一个内核源代码,因为驱动的编译过程需要内核代码(或者只是头文件?未调查)。
闲话不多说,下面列出的Makefile在ldd3的基础上添加如下东东:样式输出,各种不同提示信息颜色不同,可自由修改;将模块名称独立出来,可用于单独一个驱动源代码文件,也可用于多个驱动源代码文件;增加另外几个伪目标。下面逐一说明。
#################################################################
# file name: Makefile
# A simple Makefile for driver
# by Late Lee
# based on LDD3 and other guys works
# copyleft @ 2010
#
#################################################################
############样式输出
### nothing, just for fun
OFFSET=\x1b[
COLOR1=\x1b[0;
COLOR2=\x1b[1;
COLOR3=\x1b[1;
RESET=\x1b[
CLEAN_BEGIN=@echo -e "$(OFFSET)$(COLOR2)Cleaning up ...$(RESET)"
CLEAN_END=@echo -e "$(OFFSET)$(COLOR2)[Done.]$(RESET)"
MAKE_BEGIN=@echo -ne "$(OFFSET)$(COLOR1)Compiling ...$(RESET)"
MAKE_DONE="$(OFFSET)$(COLOR1)[Job done!]$(RESET)";
MAKE_ERR="$(OFFSET)$(COLOR3)[Oops! Error occurred]$(RESET)";
### nothing end here
CROSS_COMPILE=arm-linux-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
######### DEBUG部分
#DEBUG = y
ifeq ($(DEBUG), y)
DEBFLAGS = -O -g
else
DEBFLAGS = -O1
endif
# sth wrong here, don’t know why
#EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINCDIR)
#########驱动模块名称以及源文件部分
# module name here
MODULE = GotoHell
# obj-m = module
# obj-y = into kernel
# foo.o -> foo.ko
ifneq ($(KERNELRELEASE), )
obj-m := $(MODULE).o
# 驱动源代码文件,.o形式
# your obj file(s) here
$(MODULE)-objs := foo.o bar.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
##########真正编译部分,添加了if语句
all:
$(MAKE_BEGIN)
@echo
@if \
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules;\
then echo -e $(MAKE_DONE)\
else \
echo -e $(MAKE_ERR)\
exit 1; \
fi
endif
#####这个clean把生成的杂七杂八文件都删除,可用ls –al查看
clean:
$(CLEAN_BEGIN)
rm -rf *.cmd *.o *.ko *.mod.c *.symvers *.order *.markers \
.tmp_versions .*.cmd *~
$(CLEAN_END)
########伪目标部分
install:
@echo -e "$(COLOR3) Note:"
@echo -e "To install or not install,that is a question.$(RESET)"
modules:
@echo -e "$(COLOR3)Do not need to do this.$(RESET)"
modules_install:
@echo -e "$(COLOR3)Do not need to do this.$(RESET)"
.PHONY: all clean install modules modules_install
############# Makefile end here
1、样式输出:
OFFSET指定了那些提示信息的偏移,本想用个什么方法让它居中的,没找到,就直接指定到第21列了。
COLOR那几个是指提示信息的颜色,这个可以百度一下SHELL颜色,至于前景色,背景色怎么搭配才好看,那是阁下的事情了。
RESET将前面已经设置好的颜色统统还原到系统默认的。
再下来的几个提示信息,也是根据个人喜爱来修改。
本部分完全是optional,如果觉得占太多行不好看,完全可以去掉,省得看得眼花。
2、debug部分
一开始是用CFLAGS,结果不行,提示要使用EXTRA_CFLAGS,结果出了很多看不懂的错误信息,就不理它了,等以后真正用到调试再说,可能要重新配置内核才行。
3、驱动模块名称
网上好多都是obj-m:=hello.o这个形式,我一直想改掉,结果找到方法了。obj-m:=$(MODULE).o中的m是说要将这个驱动做成模块,使用insmod加载、rmmod删除。而在内核很多目录中的Makefile还可以看到另一种形式obj-y,意思是说将这个驱动搞到内核中去,跟着内核一起混,系统启动时它就加载了。关于:=就直接百度了,顺便可以把$@、$<、$^这几个给一起学习了。注意,$(MODULE).o是.o文件,不是.ko文件,内核会帮你从hello.o创建一个hello.ko模块的。$(MODULE)-objs := foo.o bar.o是说这个模块由两个文件组成,这里也是.o文件。实际使用中需要修改模块名称以及模块源文件(其实算是目标文件)名称。
后面的不用说了,大家都知道的。
在PC平台下编写驱动,需要修改的地方是该Makefile模板中红色黑体部分。如果在ARM平台,需要修改的是蓝色黑体部分。网上有资料显示,交叉编译命令为
$make ARCH=arm CROSS_COMPILE=arm-linux-
在实际测试过程,发现只要内核源代码正确指向在开发板中使用的内核源代码目录(当然,该内核的Makefile要修改才能编译出适合开发板的内核),直接输入make就可以了。谁对谁错,大家实地去考察一下便知结果。
关于Makefile是如何进行编译的,我在CSDN上找到一篇文章,来自sumsky的专栏,文章地址是http://blog.csdn.net/abc19842008/archive/2008/02/14/2095836.aspx。大家可以去看一下。下面这话是文章精华部分,现录于此。
当我们敲下make时,我们进入了这个权威的makefile二次。第一次进入makefile,发现KERNELRELEASE没有被设置时,于是她根据build这个符号链接定位内核源代码目录,然后进入default,开始第二个make,-C选项进入内核源代码目录,找到顶层的makefile,然后-M返回当前目录执行makefile文件,这就是第二次进入这个makefile,在这次,由于KERNELRELEASE变量已经定义,因此不需要进入else语言,在这里,obj-m:=hello.o这个语句和我们以前不是驱动程序中的makefile不同,在这里内核会帮你处理一切,这句话是告诉内核,需要从hello.o创建一个驱动模型(module)。
lwn上是这么说的:
The makefile will be read twice; the first time it will simply invoke the kernel build system, while the actual work will get done in the second pass. A makefile written in this way is simple, and it should be robust with regard to kernel build changes.
这个模板显示有点臃肿,但青菜萝卜,各有所爱,看久了就不觉得麻烦啰嗦了,而且能应用于驱动程序绝大部分场合。
本文适合那些喜欢捣鼓且有闲情逸致的人来研究,只追求结果者可以飘过。
后记:在某次实践中,在模块名称后多了一个空格,编译死活通不过。所以要特别注意这些很细节的细节,像shell脚本、C语言中用到的“\”后面也不能有空格。最后附图一张。
图1 pc平台,使用fc
图2 pc下交叉编译,使用的