之前对make的使用都仅局限于单个文件,比如用make编译单个文件的内核模块。我试着将一个程序分解成多个文件,然后再通过make进行多文件的编译,途中还是遇到一些列问题,因此总结成下文。
1.文件清单
下面的文件清单类出的是一个内核模块程序,我们这里不去深究这个模块的功能。procfs_mod.c主要包含内核模块程序的主要框架,比如加载函数和卸载函数等;procfs.c包含主要的函数的实现;而procfs.h是整个程序所用到的头文件,包含函数以及变量的声明等。
edsionte@edsionte-desktop:~/proc_vfs$ ls Makefile procfs.c procfs.h procfs_mod.c
2.Makefile的组成
我们可以将Makefile看作是编译规则集合,它告诉make应该如何进行编译,最终生成目标文件。
edsionte@edsionte-desktop:~/proc_vfs$ cat Makefile obj-m += myprocfs.o myprocfs-objs := procfs.o procfs_mod.o all: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
在这个Makefile中,obj-m说明最终生成的内核模块目标文件是myprofs.ko,并且它必须依赖两个文件procfs.c和procfs_mod.c。因此,通过模块名加-objs的形式可以定义整个模块所包含的文件。注意,这里定义的都是与原文件同名的目标文件。
3.头文件的引用
在本文所举例的源程序中,procfs.h包含了整个程序所需要的函数以及变量,也即是说所有.c的源程序都会引用该头文件。为了防止头文件被多次重复引用,我们应该在头文件中使用条件编译。
edsionte@edsionte-desktop:~/proc_vfs$ cat procfs.h #ifndef _MY_PROC_FS_H #define _MY_PROC_FS_H #include ………… #endif
也就是将整个头文件的内容用头文件包围起来。上面的条件编译说明:如果没有定义符号常量_MY_PROC_FS_H,就定义该变量并且包含该头文件。
但是,即便我在头文件中使用了条件编译,在编译时还是出现了下面的错误:
edsionte@edsionte-desktop:~/proc_vfs$ make make -C /lib/modules/2.6.32-24-generic/build M=/home/edsionte/proc_vfs modules make[1]: 正在进入目录 `/usr/src/linux-headers-2.6.32-24-generic' CC [M] /home/edsionte/proc_vfs/procfs.o CC [M] /home/edsionte/proc_vfs/procfs_mod.o LD [M] /home/edsionte/proc_vfs/myprocfs.o /home/edsionte/proc_vfs/procfs_mod.o:(.bss+0x820): multiple definition of `my_proc_file' /home/edsionte/proc_vfs/procfs.o:(.bss+0x820): first defined here /home/edsionte/proc_vfs/procfs_mod.o:(.data+0x80): multiple definition of `my_inode_ops' /home/edsionte/proc_vfs/procfs.o:(.data+0x80): first defined here make[2]: *** [/home/edsionte/proc_vfs/myprocfs.o] 错误 1 make[1]: *** [_module_/home/edsionte/proc_vfs] 错误 2 make[1]:正在离开目录 `/usr/src/linux-headers-2.6.32-24-generic' make: *** [all] 错误 2
产生这种错误的原因是我之前一直在头文件对一些全局变量进行定义,这样导致进行了多次定义。正确的做法是在某一个.c中进行全局变量的定义,而在.h文件中使用extern进行外部即可。