MIPS 架构 Linux driver编译时遇到的问题
Linux kernel在V 2.6之后,modules的编译有些修改。不再是单独编译,而是将本module添加入:obj-m,并最终调用Linux Kernel Makefile 来编译modules.
任务一:
这次Sam需要在某一平台上编译Bluetooth driver.其实也就是BlueZ的Kernel部分。但这个平台Kernel Source Code做过精简,Bluetooth子系统已经被去掉了。所以Sam将Bluetooth driver从其它平台Kernel Source Code中抽出来,以Modules的形式加入。
1. 确定copy文件:
Sam需要声成bluetooth.ko, hci_usb.ko, l2cap.ko, hidp.ko。
2. 写Modules Makefile:
ifneq ($(KERNELRELEASE),)
obj-m += hci_usb.o
obj-m += hidp.o
obj-m += l2cap.o
obj-m += bluetooth.o
bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o
hidp-objs := core.o sock.o
else
KERNELDIR ?=/home/sam/work/current/BCM/Kernel2.6
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
这个结构很简单:手动调用Makefile时,会进入else.设置了Kernel目录和当前目录,然后利用 -C 进入Kernel Source顶层目录,调用的是Kernel 顶层Makefile。 M= 则让Kernel Makefile去编译这个目录内的Module。 则Kernel Makefile再次调用我们写的Makefile。这次因为KERNELRELEASE已被设置。所以在obj-m(所需要编译的Modules) 中添加了我们需要的这些项目。
又因为bluetooth.ko 和 hidp.ko是多个文件编译而成的,所以又作了以下动作:
bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o
hidp-objs := core.o sock.o #这两句也是从Bluetooth Kernel Makefile中抄来的。
3. 将所需要的.c, .h文件从Kernel 树中 copy到本目录内。
4. #make . 4个 ko文件就顺利生产了。
注意:如果当前Kernel树中有Bluetooth目录,则这个办法有缺陷。因为很可能两部分blueZ Version不同,造成很多struct 有变化,无法编译通过。
blueZ版本号: net/bluetooth/af_bluetooth.c中:version 就是。
任务二:
工作Linux Server机器上,不同平台的交叉编译工具有不少,所以Sam很不喜欢有人用export PATH=...的方式指定交叉编译器。这样很容易造成错误和误会。
Sam的办法是:每个人在写Makefile中,都用绝对路径指定所需要的cross comple. 但在编译Kernel时,就有问题了。需要去改动Kernel Makefile。这样很不方便。也觉得很硬,一直没有好的办法。
先说之前的办法:
一般是在 arch/*/Makefile中去强硬的修改CROSS_COMPILE。这样的问题是,如果ToolChain换了地点或者这份Source Code 换到另一台机器。就需要再去修改。让人很烦。
今天无意中看了一眼CROSS_COMPILE说明,才发现有非常好的办法:
#make CROSS_COMPLE="绝对路径"/mipsel-linux-
这样就很容易解决了上述问题。 当然,定义环境变量也能达到以上效果。
知识点1:
MIPS架构中的Endianess Selection.
MIPS架构中,有Little endian和Big endian. 所以,在针对MIPS架构的Kernel中,有配置大头或小头的选项。 Endianess selection-->
因为MIPS架构中分大小头,所以理所当然,交叉编译器也需要分大小头。
通常,MIPS交叉编译器中会有 mipsel-linux, mips-linux这2个目录。
其中,mips-linux是指 大头(Big endian)所使用的交叉编译器。
mipsel-linux是小头(little endian)所使用的交叉编译器。
知识点2:
Linux Modules版本察看:
Sam在提供bluetooth modules (ko文件)给另家公司时,反映kernel版本与modules版本不同。
kernel版本可以使用#uname -r 来查看。但Modules版本怎么看,一下子来不及查,就直接使用emacs 打开ko文件,去看了版本信息。呵呵,觉得太粗暴了。查了一下:
#modinfo xxx.ko 就可以查看。嘿嘿。
知识点3:
mipsel-linux-gcc找不到库位置的处理:
#mipsel-linux-gcc -Wl,-rpath-link -Wl,/home/sam/work/current/BCM/BCM7403/ToolChain/crosstools_sf-linux-2.6.12.0_gcc-3.4.6-21_uclibc-0.9.28-20050817-20070607/mipsel-linux/lib test.c -o test
知识点4:
-rpath, -rpath-link 与 -L的区别。
当Link阶段,找不到库时,编译器会自动找几个地点(具体地点在libtool学习中有)
但 -L也是这个作用。
Sam猜想是这样的,如果显式的使用 -lxxx. 则 -rpath-link与 -L都可指定位置。
如果是c基本库,则只能使用-rpath, -rpath-link。
另外,-rpath, -rpath-link都是给link的,所以需要用 -W1,的形式传递给ld.