24小时学通Linux内核总结篇(kconfig和Makefile & 讲不出再见)
既然是总结,那么最后一天我就和大家一起分享一下学习Linux内核的方法以及难点重点吧,希望各路大神多加补充以及讨论,互相学习。
毫不夸张地说,Kconfig和Makefile是我们浏览内核代码时最为依仗的两个文件,分布在各目录下的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。基本上,Linux内核中每一个目录下边都会有一个Kconfig文件和一个Makefile文件。Kconfig和Makefile就是Linux Kernel迷宫里的地图。地图引导我们去认识一个城市,而Kconfig和Makefile则可以让我们了解一个Kernel目录下面的结构。我们每次浏览kernel寻找属于自己的那一段代码时,都应该首先看看目录下的这两个文件。
下面简要介绍一下Kconfig
每个菜单项都有一个关键字标识,最常见的就是config。
语法:
config symbol
options
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
symbol就是新的菜单项,options是在这个新的菜单项下的属性和选项
其中options部分有:
1、类型定义:
每个config菜单项都要有类型定义,bool:布尔类型, tristate三态:内建、模块、移除, string:字符串, hex:十六进制, integer:整型
2、依赖型定义depends on或requires
指此菜单的出现是否依赖于另一个定义
3、帮助性定义
只是增加帮助用关键字help或---help---
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
Kconfig文件的基本要素:
1.config条目(entry)
config是关键字,表示一个配置选项的开始;紧跟着的TMPFS_POSIX_ACL是配置选项的名称,省略了前缀"CONFIG_"
bool表示变量类型,即"CONFIG_ TMPFS_POSIX_ACL "的类型,有5种类型:bool、tristate、string、hex和int,其中tristate和string是基本的类型
bool变量的值: y和n
tristate变量的值:y、n和m
string变量的值: 字符串
bool之后的字符串“Tmpfs POSIX Access Control Lists”是提示信息,在配置界面中上下移动光标选中它时,就可以通过按空格或回车键来设置
CONFIG_ TMPFS_POSIX_ACL的值
depends on:表示依赖于XXX,“depends on TMPFS”表示只有当TMPFS配置选项被选中时,当前配置选项的提示信息才会出现,才能设置当前配置选项
2.menu条目
menu条目用于生成菜单,其格式如下:
menu "Floating poing emulation"
config FPE_NWFPE
..............
config FPE_NWFPE_XP
.............
endmenu
menu之后的Floating poing emulation是菜单名,menu和endmenu间有很多config条目,在配置界面中如下所示:
Floating poing emulation--->
[] FPE_NWFPE
[] FPE_NWFPE_XP
3.choice条目
choice条目将多个类似的配置选项组合在一起,供用户单选或多选
choice
prompt "ARM system type"
default ARCH_VERSATILE
config ARCH_AAEC2000
.........
config ARCH_REALVIEW
.........
endchoice
prompt "ARM system type"给出提示信息“ARM system type”,光标选中后回车进入就可以看到多个config条目定义的配置选项 choice条目中定义的变量只有bool和tristate
4.comment条目
comment条目用于定义一些帮助信息,出现在界面的第一行,如在arch/arm/Kconifg中有如下代码:
menu "Floating point emulation" comment "At least one emulation must be selected" config FPE_NWFPE ......... config FPE_NWFPE_XP
5.source条目
source条目用于读取另一个Kconfig文件,如:
source "net/Kconifg"
介绍一下makefile
Makefile可比Kconfig简略多了,内核的Makefile分为5个组成部分:
- Makefile 最顶层的Makefile
- .config 内核的当前配置文档,编译时成为顶层Makefile的一部分
- arch/$(ARCH)/Makefile 和体系结构相关的Makefile
- Makefile.* 一些特定Makefile的规则
- kbuild级别Makefile 各级目录下的大概约500个文档,编译时根据上层Makefile传下来的宏定义和其他编译规则,将源代码编译成模块或编入内核。顶层的Makefile文档读取.config文档的内容,并总体上负责build内核和模块。Arch Makefile则提供补充体系结构相关的信息。其中.config的内容是在make menuconfig的时候,通过Kconfig文档配置的结果。
对Makefile函数,我们从初始化函数开始,针对某个子系统或某个驱动,内核使用subsys_initcall或module_init宏指定初始化函数。在drivers/usb/core/usb.c文件中,我们可以发现下面的代码:
subsys_initcall(usb_init); //告诉我们usb_init是USB子系统真正的初始化函数,
module_exit(usb_exit); //将是整个USB子系统的结束时的清理函数
为了研究USB子系统在内核中的实现,我们需要从usb_init函数开始看起,,,下面的代码求大神指教,不懂啊
static int __init usb_init(void)
{
int retval;
if (nousb) {
pr_info("%s: USB support disabled\n", usbcore_name);
return ;
} retval = ksuspend_usb_init();
if (retval)
goto out;
retval = bus_register(&usb_bus_type);
if (retval)
goto bus_register_failed;
retval = usb_host_init();
if (retval)
goto host_init_failed;
retval = usb_major_init();
if (retval)
goto major_init_failed;
retval = usb_register(&usbfs_driver);
if (retval)
goto driver_register_failed;
retval = usb_devio_init();
if (retval)
goto usb_devio_init_failed;
retval = usbfs_init();
if (retval)
goto fs_init_failed;
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
if (!retval)
goto out; usb_hub_cleanup();
hub_init_failed:
usbfs_cleanup();
fs_init_failed:
usb_devio_cleanup();
usb_devio_init_failed:
usb_deregister(&usbfs_driver);
driver_register_failed:
usb_major_cleanup();
major_init_failed:
usb_host_cleanup();
host_init_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
ksuspend_usb_cleanup();
out:
return retval;
}
API感想(此处我也不懂,API的概念我脑海中还没建立,贴出来大家一起分享注意一下)
“比起知道你所用技术的重要性,成为某一个特别领域的专家是不重要的。知道某一个具体API调用一点好处都没有,当你需要他的时候只要查询下就好了。”这句话源于我看到的一篇翻译过来的博客。我想强调的就是,这句话针应用型编程再合适不过,但是内核API就不完全如此。
内核相当复杂,学习起来很不容易,但是当你学习到一定程度,你会发现,如果自己打算写内核代码,到最后要关注的仍然是API接口,只不过这些API绝大部分是跨平台的,满足可移植性。内核黑客基本上已经标准化、文档化了这些接口,你所要做的只是调用而已。当然,在使用的时候,最好对可移植性这一话题在内核中的编码约定烂熟于心,这样才会写出可移植性的代码。就像应用程序一样,可以使用开发商提供的动态库API,或者使用开源API。同样是调用API,不同点在于使用内核API要比使用应用API了解的东西要多出许多。
当你了解了操作系统的实现---这些实现可都是对应用程序的基础性支撑啊---你再去写应用程序的时候,应用程序中用到的多线程,定时器,同步锁机制等等等等,使用共享库API的时候,联系到操作系统,从而把对该API的文档描述同自己所了解到的这些方面在内核中的相应支撑性实现结合起来进行考虑,这会指导你选择使用哪一个API接口,选出效率最高的实现方式。对系统编程颇有了解的话,对应用编程不无益处,甚至可以说是大有好处。
内核文档
最后来说下相关的内核文档,内核代码中包含有大量的文档,这些文档对于学习理解内核有着不可估量的价值,记住,在任何时候,它们在我们心目中的地位都应该高于那些各式的内核参考书,只不过都是英文的了.不过还好,,嘎嘎,大一的时候就把英语六级过了,还是有点信心的,,不过过去两年了不知道自己的英语忘光了没有,下面是一些我们这些内核新人所应该阅读的文档。
README这个文件首先简单介绍了Linux内核的背景,然后描述了如何配置和编译内核,最后还告诉我们出现问题时应该怎么办。
Documentation/Changes这个文件给出了用来编译和使用内核所需要的最小软件包列表。
Documentation/CodingStyle这个文件描述了内核首选的编码风格,所有代码都应该遵守里面定义的规范。
Documentation/SubmittingPatches
Documentation/SubmittingDrivers
Documentation/SubmitChecklist //这三个文件都是描述如何提交代码的,其中SubmittingPatches给出创建和提交补丁的过程,
SubmittingDrivers描述了如何将 设备驱动提交给2.4、2.6等不同版本的内核树,SubmitChecklist则描述了提交代码之前需要check自己的代码应该遵守的某些事项。
Documentation/stable_api_nonsense.txt这个文件解释了为什么内核没有一个稳定的内部API(到用户空间的接口——系统调用——是稳定的),它对于理解Linux的开发哲学至关重要,对于将开发平台从其他操作系统转移到Linux的开发者来说也很重要。
Documentation/stable_kernel_rules.txt解释了稳定版内核(stable releases)发布的规则,以及如何将补丁提交给这些版本。
Documentation/SecurityBugs内核开发者对安全性问题非常关注,如果你认为自己发现了这样的问题,可以根据这个文件中给出的联系方式提交bug,以便能够尽可能快的解决这个问题。
Documentation/kernel-docs.txt这个文件列举了很多内核相关的文档和书籍,里面不乏经典之作。
Documentation/applying-patches.txt这个文件回答了如何为内核打补丁。
Documentation/bug-hunting这个文件是有关寻找、提交、修正bug的。
Documentation/HOWTO这个文件将指导你如何成为一名内核开发者,并且学会如何同内核开发社区合作。它尽可能不包括任何关于内核编程的技术细节,但会给你指引一条获得这些知识的正确途径。
小结
最后一天没有说到一些具体的关于内核的知识,只是想重点分享一下kconfig和Makefile,这对学习内核来说至关重要,,当然了,上述提到的也是看了好多大牛的文章以及查阅了一些相关知识,大家可以参考一下一篇文章,具体讲了这些,我把链接附在下面:http://blog.chinaunix.net/uid-26258259-id-3783679.html 不知不觉这一系列的文章就要结束了,自己也要好好整理这些天所欠缺的,,非常感谢期间有些读者对我的支持,很开心和你们分享这些,,接下来要开始新的生活了,,但是我们的学习仍将继续,我们的激情不会褪去,我们的梦想我们的青春永恒~~
版权所有,转载请注明转载地址:http://www.cnblogs.com/lihuidashen/p/4257007.html