对一个uClinux中的Makefile文件的简单分析(ZT)

为了彻底搞清楚linux uClinux 的设备驱动,我觉得有必要找一份devices.txt copy 。那上面详细列出了0 255 linux 主设备号的分配情况,以及各种设备的相应次设备号。对于,我自己开发非标准的linux 设备非常有用。uClinux 的设备和linux 一样,因此这个文档同样适用于uClinux 。这个文档可以从下列站点:http://www.lanana.org/docs/device-list/ 或者ftp://ftp.kernel.org/pub/linux/docs/device-list/ 获取。作为开发的常用手册,这个文档有必要打印并保存下来。

 

我自己为我的开发板上的按键写了一个驱动,我想要像其他linux 标准设备那样在uClinux 启动起来时,在/dev 目录下有例如/dev/key 这样一个设备。但是开始我一直搞不清楚为什么在menuconfig char device input core 菜单中居然没有关于键盘的选项,但键盘驱动又是确实被编译进系统中了。后来,经过比较linux uClinux 后,我发现问题的关键不在于char/ 目录下的config.in 文件,也不在于linux-2.4.x/arch/armnommu/Config.in 文件,而在于drivers/char/Makefile 文件。

 

简要说一下这个文件,它并不规定menuconfig char device 子菜单的构成,而是规定了drivers/char 这个目录下的文件的编译规则。通过在此文件中,加入一些条件判断,并根据条件判断为一些变量赋值,从而达到将特定设备编译进uClinux 的内核。

 

下面对Makefile 中的一些定义进行解释。

 

编译目标定义:

 

obj-$(CONFIG_TC) += tc.o 的语句是用来定义编译的目标,是子目录 Makefile 中最重要的部分。编译目标定义那些在本子目录(对于这个Makefile 来说,就是针对/linux-2.4.x/drivers/char 子目录)下,需要编译到 Linux 内核中的目标文件列表。为了只在用户选择了此功能后才编译,所有的目标定义都融合了对配置变量的判断。
前面说过,每个配置变量取值范围是:y n m 和空,obj-$(CONFIG_TC) 分别对应着 obj-y obj-n obj-m obj- 。如果 CONFIG_TC 配置为 y ,那么 tc.o 就进入了 obj-y 列表。obj-y 为包含到 Linux 内核 vmlinux 中的目标文件列表;obj-m 为编译成模块的目标文件列表;obj-n obj- 中的文件列表被忽略。配置系统就根据这些列表的属性进行编译和链接。export-objs 中的目标文件都使用了 EXPORT_SYMBOL() 定义了公共的符号,以便可装载模块使用。在 tc.c 文件的最后部分,有 "EXPORT_SYMBOL(search_tc_card);" ,表明 tc.o 有符号输出。其中的“obj-y += ”表示如果变量为真,那么就追加什么;而“obj-y = ”表示如果变量为真,那么就等于什么。

 

这里需要指出的是,对于编译目标的定义,存在着两种格式,分别是老式定义和新式定义。老式定义就是前面 Rules.make 使用的那些变量,新式定义就是 obj-y obj-m obj-n obj- Linux 内核推荐使用新式定义,不过由于 Rules.make 不理解新式定义,需要在 Makefile 中的适配段将其转换成老式定义。

 

另外,需要指出的是linux uClinux 源码树中的Makefile 分为两类,一类是由autoconf automake 根据configure.in 模板自动生成,另一类是由开发者自己手工写的Makefile 。所以,对于前者来说,修改文件中的任何语句或判断条件,都是徒劳无功的。因为每次创建新的配置或修改以前的配置后,Makefile 就会被改写或重新生成。要想要通过这种办法达到自己满意的编译配置是不可能的。但后者就不同,由于不是由内核自动生成,因此,不论配置修改多少次,这个文件都是不会改变的。所以,我们可以通过修改Makefile 中的语句或判断条件,来达到构建我们自己的编译配置。这一点对添加自己的非标准设备非常有用。

 

适配段:
适配段的作用是将新式定义转换成老式定义。在下面的例子中,适配段就是将 obj-y obj-m 转换成 Rules.make 能够理解的 L_TARGET L_OBJS LX_OBJS M_OBJS MX_OBJS

 

L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) 定义了 L_OBJS 的生成方式:在 obj-y 的列表中过滤掉 export-objs tc.o ),然后排序并去除重复的文件名。这里使用到了GNU Make 的一些特殊功能,具体的含义可参考Make 的文档(info make )。

 

显然,由于menuconfig 的图形配置菜单中根本没有关于键盘的选项,因此可以看到在obj-y 中并没有keyboard.o 。那么键盘驱动是怎么编译进char.o 的呢?

 

可以注意到:
KEYMAP    =defkeymap.o
KEYBD     =pc_keyb.o
CONSOLE =console.o
SERIAL    =serial.o
这四个变量都被赋值。它们分别表示键盘码和扫描码的映射表、键盘驱动、控制台驱动和串口驱动。上面是四个变量的默认值。

 

在下面这一段中,先判断变量ARCH 是否等于sh ,如果为真,那么变量为空;紧接着下一级逻辑判断中,判断变量CONFIG_SH_HP600 是否为真,如果为真,那么键盘映射表还是适用默认的映射表(defkeymap.o ),但键盘驱动就改为hp600_keyb.o scan_keyb.o ,控制台驱动不变。但是要注意串口在这一部分中,并没有加入判断语句中,因为串口驱动在下面用obj-$(CONFIG_68328_SERIAL) += 68328serial.o 这样的形势单独列出。

 

另外,需要特别指出的是,察看linux 或者uClinux 各种变量配置的情况,可以看 linux-2.4.x/include/linux/autoconf.h uClinux-dist/config.in 以及 linux-2.4.x/config.in 这三个文件。

 

 

还有 ifeq .. )表示假如等于 xxx ,那么 xxx ifneq .. )便是相反意思,表示假如不等于 xxx ,那么 xxx ifdef ()表示如果 xxx 为真,那么 xxx ifndef ()表示如果 xxx 为假,那么 xxx

 

ifeq ($(ARCH),sh)                                      如果ARCH=sh ,那么。。。
 KEYMAP    =
 KEYBD     =
 CONSOLE =
 ifeq ($(CONFIG_SH_HP600),y)               如果CONFIG_SH_HP600=y ,那么。。。
 KEYMAP    = defkeymap.o
 KEYBD     = scan_keyb.o hp600_keyb.o
 CONSOLE = console.o
 endif
endif

 

ifeq ($(ARCH),mips)
 ifneq ($(CONFIG_PC_KEYB),y)              如果CONFIG_PC_KEYB =y ,那么。。。
    KEYBD    =
 endif
endif

 

ifeq ($(ARCH),m68k)
   ifdef CONFIG_AMIGA                        如果CONFIG_AMIGA 为真(即变量为y ),那么。。。
      KEYBD = amikeyb.o
   else
      ifndef CONFIG_MAC                     如果CONFIG_AMIGA 为假,那么。。。
        KEYBD =
      endif
   endif
   SERIAL   =
endif

 

下面这一段很重要。
ifndef CONFIG_SUN_KEYBOARD              如果变量为假,那么判断变量CONFIG_VT

 

 obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) 
else
 obj-$(CONFIG_PCI) += keyboard.o $(KEYMAP)
endif
结果就是CONFIG_SUN_KEYBOARD SUN 公司PC 键盘)通常为假(我们不会用到),那么CONFIG_VT 是虚拟控制台,通常我们要选择,就是CONFIG_VT=y ,那么追加keyboard.o $(KEYMAP) $(KEYBD) 。这两个变量在最前面有定义:defkeymap.o pc_keyb.o 。因此,标准键盘驱动被自动编译进char.o 中,进而被编译进内核中。

 

所以,我就可以根据这个道理将自己的按键驱动自动加入到内核中。下面是我加入的一段语句,完成自动将我自己的按键驱动编译进内核。

 

ifeq($(CONFIG_ARCH_S 3C44B0),y)
KEYBD = key.o
KEYMAP = mykeymap.o
       CONSOLE = console.o
endif

 

这个Makefile 大致就解释到这儿。其实,不过是拿给自己看的罢了。
 

你可能感兴趣的:(对一个uClinux中的Makefile文件的简单分析(ZT))