c++写入vs读取访问权限冲突突是怎么了

Kbuild文件
时间: 20:01:25
&&&& 阅读:57
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&3 Kbuild文件
大部分内核中的Makefile都是使用Kbuild组织结构的Kbuild Makefile。这章将介绍Kbuild Makefile的语法。
对于Kbuild文件名来讲,Kbuild编译系统更倾向于使用"Makefile"这个名字,当然"Kbuild"也是可以用的。但如果"Makefile"和"Kbuild"同时存在的话,Kbuild编译系统使用的将会是"Kbuild"文件。
3.1节将是对目标定义的一个快速介绍,以后的几章会提供更详细的内容以及实例。
3.1 目标定义
目标定义是Kbuild Makefile的主要部分,也是核心部分。主要是定义了要编译的文件,所有的选项,以及到哪些子目录去执行递归操作。
最简单的Kbuild makefile 只包含一行:
&&& 例子:
&&&&&&&&& obj-y += foo.o
&&& 该例子告诉Kbuild:在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c或foo.S文件编译得到。
&&& 如果foo.o要编译成一模块,那就要用obj-m了。所采用的形式如下:
&&& 例子:
&&&&&&&&& obj-$(CONFIG_FOO) += foo.o
&&& $(CONFIG_FOO)可以为y(编译进内核) 或m(编译成模块)。如果CONFIG_FOO既不是y又不是m,那么该文件就不会被编译链接了。
3.2 编译进内核 -- obj-y
Kbuild Makefile 规定所有编译进内核的目标文件都在$(obj-y)列表中。而这些列表依赖内核的配置(.config)。
&&& Kbuild编译所有的$(obj-y)文件。然后,调用"$(LD) -r"将它们合并到一个build-in.o文件中。稍后,该build-in.o会被其父Makefile链接进vmlinux中。
$(obj-y)列表中的文件是有顺序讲究的。而且$(obj-y)列表中可以有重复项:但是当第一个文件被链接到built-in.o中后,其余重复的文件就被忽略了。
链接目标这个动作也是有顺序的,因为有些函数,例如module_init()/__initcall,将会在启动时按照他们出现的顺序被调用。所以,记住改变链接的顺序可能改变你SCSI控制器的检测顺序,从而导致你的硬盘数据损害。
&&&&&&&&& # drivers/isdn/i4l/Makefile
&&&&&&&&& # Makefile for the kernel ISDN subsystem and device drivers.
&&&&&&&&& # Each configuration option enables a list of files.
&&&&&&&&& obj-$(CONFIG_ISDN)&&&&&&& += isdn.o
&&&&&&&&& obj-$(CONFIG_ISDN_PPP_BSDCOMP)&&& += isdn_bsdcomp.o
3.3 编译可装载模块 -- obj-m
$(obj-m) 列举出了哪些文件要编译成可装载模块。
& &&一个模块可以由一个文件或多个文件编译而成。如果是一个源文件,Kbuild Makefile只需简单的将其加到$(obj-m)中去就可以了。
&&&&&&&&& # drivers/isdn/i4l/Makefile
&&&&&&&&& obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
注意:此例中 $(CONFIG_ISDN_PPP_BSDCOMP) 的值为‘m‘
如果内核模块是由多个源文件编译而成,那你就要采用上面那个例子一样的方法去声明你所要编译的模块。
&&& Kbuild系统需要知道你所编译的模块是基于哪些文件,所以你需要通过变量:
$(&module_name&-objs)
来告诉它。
&&& 例子:
&&&&&&&&& #drivers/isdn/i4l/Makefile
&&&&&&&&& obj-$(CONFIG_ISDN) += isdn.o
&&&&&&&& &isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
在这个例子中,模块名是isdn.o,Kbuild将对$(isdn-objs)中列出的所有文件进行编译,然后使用"$(LD) -r"生成isdn.o。
Kbuild recognises objects used for composite objects by the suffix -objs, and the suffix -y。
This allows the Makefiles to use the value of a CONFIG_ symbol to determine if an object is part
of a composite object.&& &
&& &&&&&&&# fs/ext2/Makefile
&&&&&&&&& obj-$(CONFIG_EXT2_FS)&&&&&&& += ext2.o
&&&&&&&& &ext2-y&&&&&&&&&&&&&&&& := balloc.o bitmap.o
&&&&&&&&& ext2-$(CONFIG_EXT2_FS_XATTR)&&& += xattr.o
& &&在这个例子中,如果 $(CONFIG_EXT2_FS_XATTR) 是 ‘y‘,xattr.o将是复合对象 ext2.o的一部分。
注意:其实,将对象编译进内核时,上面的语法同样适用。所以,如果你的 CONFIG_EXT2_FS=y,那Kbuild会按你所期望的那样,生成一个独立ext2.o文件,然后将其链接到 built-in.o中。
3.4 输出的符号
Makefile对模块输出的符号没有特殊要求。
3.5 目标库文件 -- lib-y
&&& obj-* 中所列出的目标文件是用来编译成模块或者是链接到特定目录中的built-in.o的。同样,你也可以列出一些目标文件,它们将被包含在lib.a库中。
&& &lib-y 所列出的目标文件将会被用来组成该目录下的一个单独的库文件。
&&& obj-y 与 lib-y 同时列出的目标文件,因为都是可以访问的,所以该文件是不会被包含在库文件中的。
&&& 同样,lib-m 中所列出的目标文件就要包含在 lib.a 库文件中。
注意:一个Kbuild makefile可以同时列出要编译进内核的文件和要编译成库的文件。所以,在一个目录里可以同时存在 built-in.o 与 lib.a 两种文件。
&&& 例子:
&&&&&&&&& # arch/i386/lib/Makefile
&&&&&&&& &lib-y&&& := chechsum.o delay.o
&&& 这将由 checksum.o 和delay.o 两个文件创建一个库文件lib.a。为了让Kbuild 系统真正认识到这里要有一个库文件 lib.a 要创建,库文件lib.a所在的目录需要加到 libs-y 列表中。
还可参考"6.3 递归向下时要访问的目录列表"。&&&
lib-y 的使用一般限制在 lib/ 和 arch/*/lib 中。
3.6 递归向下访问目录
&&& 其实,一个Makefile只负责编译其所在目录下的对象文件。在子目录中的文件的编译要由其所在的子目录的Makefile来管理。只要你让Kbuild系统知道它应该递归操作,那么Kbuild系统就会在其子目录中自动调用 make 从而进行递归操作。
&&& obj-y 和 obj-m 就有这样的作用。
&&& ext2 被放在一个单独的目录下,在fs目录下的Makefile会告诉Kbuild系统使用下面的赋值进行向下递归操作。
&&& 例子:
&&&&&&&&& # fs/Makefile
&&&&&&&&& obj-$(CONFIG_EXT2_FS) += ext2/
&& &如果 CONFIG_EXT2_FS 被设置为 ‘y‘(编译进内核)或是‘m‘(编译成模块),相应的 obj- 变量就会被设置,并且Kbuild就会递归向下访问 ext2 目录。
&&& Kbuild系统只是用这些信息来决定它是否需要访问该目录,而具体怎么编译由该子目录中的Makefile来决定。
It is good practice to use a CONFIG_ variable when assigning directory&&& names. This allows kbuild to totally skip the directory if the corresponding CONFIG_ option is neither ‘y‘ nor ‘m‘.
3.7 编辑标志
&&& EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS
&&& 所有的EXTRA_ 变量只在其被定义的Kbuild Makefile文件中起作用。而且,EXTRA_ 变量可以在Kbuild Makefile中的所有命令中使用。
l&&&&&&&&& $(EXTRA_CFLAGS) 是用 $(CC) 编译C源文件时要用到的选项。
&&& 例子:
&&&&&&&&& # drivers/sound/emu10kl/Makefile
&&&&&&&&& EXTRA_CFLAGS += -I$(obj)
&&&&&&&&& ifdef DEBUG
&&&&&&&&&&&&& EXTRA_CFLAGS += -DEMU10KL_DEBUG
&&&&&&&&& endif
EXTRA_CFLAGS变量是必须的,因为顶层Makefile使用 $(EXTRA_CFLAGS)作为整个源代码树的编译选项。
l&&&&&&&&& $(EXTRA_AFLAGS) 也是一个针对每个目录的选项,只不过它是用来编译汇编源代码的。
&&& 例子:
&&&&&&& # arch/x86_64/kernel/Makefile
&&&&&&& EXTRA_AFLAGS := -traditional
l&&&&&&&&& $(EXTRA_LDFLAGS) 和 $(EXTRA_ARFLAGS)分别与 $(LD)和 $(AR)类似,只不过,他们是针对内核的每个目录的编辑标志。
&&& 例子:
&&&&&&& # arch/m68k/fpsp040/Makefile
&&&&&&& EXTRA_LDFLAGS := -x
l&&&&&&&&& CFLAGS_$@, AFLSGA_$@
&&& &&&&CFLAGS_$@ 和 AFLAGS_$@ 只能在当前Kbuild Makefile中的命令中使用。
$(CFLAGS_$@) 是 $(CC) 针对每个文件的选项。$@ 表明了具体操作的目标文件。
&&& 例子:
&&&&&&& # drivers/scsi/Makefile
&&&&&&& CFLAGS_aha152x.o =& -DAHA152X_STAT -DAUTOCONF
&&&&&&& CFLAGS_gdth.o&&& =& # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \
&&&&&&&&&&&&&&&&&&&&& -DGDTH_STATISTICS
&&&&&&& CFLAGS_seagate.o =& -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
&&& &&&&以上三行分别设置了aha152x.o,gdth.o 和 seagate.o的编译选项。
l&&&&&&&&& $(AFLAGS_$@)也类似,只是针对汇编语言的。
&&& 例子:
&&&&&&& # arch/arm/kernel/Makefile
&&&&&&& AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
&&&&&&& AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) &traditional
3.9 跟踪依赖
&&& Kbuild 跟踪以下情况的依赖:
1)&& 所有要参与编译的文件(所有的.c 和.h文件)
2)&& 在参与编译文件中所要使用的 CONFIG_ 选项
3)&& 用于编译目标的命令行
&&& 因此,如果你改变了 $(CC) 的选项,所有受影响的文件都要重新编译。
3.10 特殊规则
&&& 特殊规则就是Kbuild编译系统不能提供所要求的支持时,所使用的规则。一个典型的例子就是在构建过程中生成的头文件。Another example are the architecture-specific Makefiles which need special rules to prepare boot images etc.
Special rules are written as normal Make rules.
&&&&&&&& Kbuild is not executing in the directory where the Makefile is located, so all special rules shall provide a relative&&&& path to prerequisite files and target files.
&&&&&&&& Two variables are used when defining special rules:
l&&&&&&&&& $(src)
&&& $(src) 表明Makefile所在目录的相对路径。需要定位源代码树中的文件时经常使用该变量。
l&&&&&&&&& $(obj)
&&& $(obj) 表明目标文件所要存储目录的相对路径。经常在定位所生成的目标文件时使用该变量。
&&& 例子:
&&&&&&& # drivers/scsi/Makefile
&&&&&&& $(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl
&&&&&&&&&&& $(CPP) -DCHIP=810 - & $& | ... $(src)/script_asm.pl
&&& 这就是一个特殊规则,遵守着make所要求的普通语法。
&&& 目标文件依赖于两个源文件。用$(obj)来定位目标文件,用$(src)来定位源文件。
3.11 $(CC) 支持的函数
&&& 内核可能由多个不同版本的$(CC)编译,而每个版本都支持不同的功能集与选项集。Kbuild系统提供了检查 $(CC) 可用选项的基本功能。$(CC)一般情况下是gcc编译器,但也可以使用其它编译器来代替gcc。
l&&&&&&&&& as-option
&&& as-option,当编译汇编文件(*.S)时,用来检查 $(CC) 是否支持特定选项。如果第一个选项不支持的话,可选的第二个选项就派上用场了。
&&& 例子:
&&&&&&& # arch/sh/Makefile
&&&&&&& cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)
&&& 在上面的例子里,如果 $(CC) 支持选项 -Wa$(comma)-isa=$(isa-y),cflags-y就会被赋予该值。&&& 第二个参数是可选的,当第一个参数不支持时,就会使用该值。
l&&&&&&&&& ld-option
&&& ld-option,当链接目标文件时,用来检查 $(CC) 是否支持特定选项。如果第一个选项不支持的话,可选的第二个选项可以用来指定。
&&& 例子:
&&&&&&& #arch/i386/kernel/Makefile
&&&&&&& vsyscall-flags += $(call ld-option, -Wl$(comma)--hash-style=sysv)
&&& 在上面的例子中,如果 $(CC)支持选项 -Wl$(comma)--hash-style=sysv,ld-option就会被赋予该值。
&&& 第二个参数是可选的,当第一个参数不支持时,就会使用该值。
l&&&&&&&&& cc-option
&&& cc-option,用来检查 $(CC) 是否支持特定选项,并且不支持使用可选的第二项。
&&& 例子:
&&&&&&& # arch/i386/Makefile
&&&&&&& cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)
&&& 在上面的例子中,如果 $(CC)支持选项 -march=pentium-mmx,cc-option就会被赋予该值,否则就赋 -march-i586。
&&& cc-option的第二个参数是可选的。如果忽略的话,当第一个选项不支持时,cflags-y 不会被赋值。
l&&&&&&&&& cc-option-yn
&&&&&&& cc-option-yn,用来检查 gcc 是否支持特定选项,返回‘y‘支持,否则为‘n‘。
&&& 例子:
&&&&&&& # arch/ppc/Makefile
&&&&&&& biarch& := $(call cc-option-yn, -m32)
&&&&&&& aflags-$(biarch) += -a32
&&&&&&& cflags-$(biarch) += -m32
&&& 在上面的例子里,当 $(CC) 支持 -m32选项时,$(biarch)设置为y。当$(biarch) 为y时,扩展的 $(aflags-y) 和 $(cflags-y)变量就会被赋值为:-a32 和 -m32。
l&&&&&&&&& cc-option-align
&&& gcc版本大于3.0时,改变了函数,循环等用来声明内存对齐的选项。当用到对齐选项时,$(cc-option-align) 用来选择正确的前缀:
& &&gcc & 3.00
&&&&&&& cc-option-align = -malign
&&& gcc &= 3.00
&&&&&&& cc-option-align = -falign
&&& 例子:
&&&&&&& CFLAGS += $(cc-option-align)-functions=4
&&& 在上面的例子中,选项 -falign-funcions=4 被用在gcc &= 3.00的时候。对于小于3.00时, 使用 -malign-funcions=4 。
l&&&&&&&&& cc-version
&&& cc-version以数学形式返回 $(CC) 编译器的版本号。
&&& 其格式是:&major&&minor&,二者都是数学。比如,gcc 3.41 会返回 0341。 当某版本的 $(CC) 在某方面有缺陷时,cc-version就会很有用。比如,选项-mregparm=3 虽然会被gcc接受,但其实现是有问题的。
&&& 例子:
&&&&&&& # arch/i386/Makefile
&&&&&&& cflags-y += $(shell \
&&&&&&& if [ $(call cc-version) -ge 0300 ] ; then \
&&&&&&&&&&& echo "-meregparm=3";)
&&& 在上面的例子中,-mregparm=3只会在gcc的版本号大于等于3.0的时候使用。
l&&&&&&&&& cc-ifversion
&&& cc-ifversion测试 $(CC) 的版本号,如果版本表达式为真,就赋值为最后的参数。
&&& 例子:
&&&&&&& #fs/reiserfs/Makefile
&&&&&&& EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0402, -O1)
&&& 在这个例子中,如果 $(CC) 的版本小于4.2,EXTRA_CFLAGS就被赋值 -O1。
&&& cc-ifversion 可使用所有的shell 操作符:-eq,-ne,-lt,-le,-gt,和-ge。
&&& 第三个参数可以像上面例子一样是个文本,但也可以是个扩展的变量或宏。标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&原文:/welhzh/p/4786932.html
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!1051人阅读
驱动开发(41)
&&&&&& 在驱动中,有很多打印信息,有些是默认不能打开的,如dev_dbg或dev_vdbg等,为了方便调试,需要将这些打印信息全部打印出来,可通过如下步骤来打开开关。
我们先来看dev_dbg的定义
在linux/device.h文件中:
#ifdef DEBUG
#define dev_dbg(dev, format, arg...)
dev_printk(KERN_DEBUG , dev , format , ## arg)
static inline int __attribute__ ((format (printf, 2, 3)))
dev_dbg(struct device * dev, const char * fmt, ...)
#endif那我们在包含该头文件之前,需要声明一下DEBUG。
#define DEBUG
#include &linux/kernel.h&
#include &linux/init.h&
#include &linux/clk.h&
#include &linux/module.h&
#include &linux/platform_device.h&但是这个打开了之后,也不能顺利的输出信息,原因是printk有默认的信息级别。在include/linux/kernel.h文件中
KERN_EMERG
KERN_ALERT
KERN_WARNING
KERN_NOTICE
KERN_DEBUG
&&7&&可以看到KERN_DEBUG是级别最低的。
2、修改文件include/linux/printk.h文件#define DEFAULT_MESSAGE_LOGLEVEL 4
#define MINIMUM_CONSOLE_LOGLEVEL 1
#define DEFAULT_CONSOLE_LOGLEVEL 8
kernel/printk.c
int console_printk[4] = {
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */
CONSOLE_LOGLEVEL_MIN,
/* minimum_console_loglevel */
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
该数组的信息可通过cat /proc/sys/kernel/printk节点来查看。当然,也可以通过写上述节点的方法来更改打印级别。
其中DEFAULT_CONSOLE_LOGLEVEL 为终端console输出的最低级别,比这严重的都将输出。原来该值为7,则调试信息无法输出,修改为8则全部有输出。
对于dev_vdbg函数,查看源码
#ifdef VERBOSE_DEBUG
#define dev_vdbg
#define dev_vdbg(dev, format, arg...)
dev_printk(KERN_DEBUG, dev, format, ##arg);
则需要在头文件之前多加一个VERBOSE_DEBUG声明。
对应内核常见的其他打印函数,收集到的信息如下
对应pr_xxx()API的好处是,可以在文件最开头通过pr_fmt定义一个打印格式,比如在kernel/watchdog.c的最开头通过如下定义保证以后watchdog.c调用的
所以pr_xxx()打印的信息都自动带有& NMI watchdog: &的前缀。(linux/include/printk.h)
#define pr_fmt(fmt)& & NMI watchdog: & fmt
#ifndef pr_fmt
#define pr_fmt(fmt) fmt
#define pr_emerg(fmt, ...) \
    printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
    printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
    printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
    printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
    printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
    printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
    printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_cont(fmt, ...) \
    printk(KERN_CONT fmt, ##__VA_ARGS__)
/* pr_devel() should produce zero code unless DEBUG is defined */
#ifdef DEBUG
#define pr_devel(fmt, ...) \
    printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_devel(fmt, ...) \
    no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#include &linux/dynamic_debug.h&
/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_DEBUG)
/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
#define pr_debug(fmt, ...) \
    dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
    printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug(fmt, ...) \
    no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
使用dev_xxx()族API打印的时候,设备名称对自动加到打印信息的前头。 (drivers/base/core.c)
static int __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
return printk(&%s(NULL device *): %pV&, level, vaf);
return dev_printk_emit(level[1] - '0', dev,
&%s %s: %pV&,
dev_driver_string(dev), dev_name(dev), vaf);
int dev_printk(const char *level, const struct device *dev,
const char *fmt, ...)
struct va_
va_start(args, fmt);
vaf.va = &
r = __dev_printk(level, dev, &vaf);
va_end(args);
EXPORT_SYMBOL(dev_printk);
#define define_dev_printk_level(func, kern_level)
int func(const struct device *dev, const char *fmt, ...) \
struct va_
va_start(args, fmt);
vaf.va = &
r = __dev_printk(kern_level, dev, &vaf);
va_end(args);
EXPORT_SYMBOL(func);
define_dev_printk_level(dev_emerg, KERN_EMERG);
define_dev_printk_level(dev_alert, KERN_ALERT);
define_dev_printk_level(dev_crit, KERN_CRIT);
define_dev_printk_level(dev_err, KERN_ERR);
define_dev_printk_level(dev_warn, KERN_WARNING);
define_dev_printk_level(dev_notice, KERN_NOTICE);
define_dev_printk_level(_dev_info, KERN_INFO);
此外,打印中还经常看到pr_debug函数,可以动态的打印调试信息()
如要打开该函数,只需在内核中配置CONFIG_DYNAMIC_DEBUG,并且将debugfs挂载到某个文件夹mount -t debugfs none /sys/kernel/debug/,
就可以通过echo -n &file xxxxxx.c +p& & /sys/kernel/debug/dynamic_debug/control来打开调试信息啦。
#if defined(CONFIG_DYNAMIC_DEBUG)
/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
#define pr_debug(fmt, ...) \
dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug(fmt, ...) \
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
下面的程序printk_test.c用来测试上面的打印函数,如下
#define pr_fmt(fmt) KBUILD_MODNAME
pr_test::::::& fmt
#define DEBUG
#define VERBOSE_DEBUG
#include &linux/module.h&
#include &linux/platform_device.h&
#include &linux/miscdevice.h&
#include &asm/uaccess.h&
#include &linux/sched.h&
#include &linux/fs.h&
#include &linux/device.h&
#include &linux/delay.h&
#define GTP_INFO(fmt,arg...)
printk(&&&-GTP-INFO-&& &fmt&\n&,##arg)
#define DEVICE_NAME &printk&
static int printk_test(struct device *dev)
printk(KERN_INFO KBUILD_MODNAME &
%d\n&,__LINE__);
dev_emerg(dev,&dev_emerg %d\n&,__LINE__);
dev_alert(dev,&dev_alert %d\n&,__LINE__);
dev_crit(dev,&dev_crit %d\n&,__LINE__);
dev_err(dev,&dev_err %d\n&,__LINE__);
dev_warn(dev,&dev_warn %d\n&,__LINE__);
dev_notice(dev,&dev_notice %d\n&,__LINE__);
dev_info(dev,&dev_info %d\n&,__LINE__);
_dev_info(dev,&_dev_info %d\n&,__LINE__);
pr_emerg(&pr_emerg %d\n&,__LINE__);
pr_alert(&pr_alert %d\n&,__LINE__);
pr_crit(&pr_crit %d\n&,__LINE__);
pr_err(&pr_err %d\n&,__LINE__);
pr_warning(&pr_warning %d\n&,__LINE__);
pr_warn(&pr_warn %d\n&,__LINE__);
pr_notice(&pr_notice %d\n&,__LINE__);
pr_info(&pr_info %d\n&,__LINE__);
pr_cont(&pr_cont %d\n&,__LINE__);
GTP_INFO(&%d\n&,__LINE__);
msleep(8000);
pr_debug(&pr_debug\n&);
dev_dbg(dev,&dev_dbg %d\n&,__LINE__);
dev_vdbg(dev,&dev_vdbg %d\n&,__LINE__);
static struct miscdevice dev = {
= MISC_DYNAMIC_MINOR,
= DEVICE_NAME,
static int __init printk_init(void)
printk(&%s\n&,__func__);
ret = misc_register(&dev);
ret = printk_test(dev.this_device);
static void __exit printk_exit(void)
misc_deregister(&dev);
printk(&%s\n&,__func__);
module_init(printk_init);
module_exit(printk_exit);
MODULE_LICENSE(&GPL&);
编译并安装驱动,修改打印级别echo 8 &/proc/sys/kernel/printk,打印信息为
这里的pr_debug函数也打印出来了,因为把DEBUG的声明放在CONFIG_DYNAMIC_DEBUG声明之前,pr_debug走的是printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__),
如果没有声明DEBUG,可通过echo -n &file printk_test.c +p& & /sys/kernel/debug/dynamic_debug/control来打开调试信息。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:83562次
积分:1960
积分:1960
排名:第17209名
原创:110篇
转载:102篇
评论:17条
(2)(1)(2)(8)(6)(1)(7)(8)(13)(12)(16)(19)(22)(6)(26)(18)(29)(14)(3)linux内核及驱动(11)
Linux Kbuild文档
Linux内核配置方式1.1&概述
Linux内核源代码组织了一个配置系统,该配置系统可以生成内核配置菜单,方便内核配置。配置系统主要包含Makefile、Kconfig和配置工具,可以生成配置界面。其中,配置界面是通过配置工具来生成的,配置工具通过Makefile编译执行,配置界面中的选项则是通过各级的Kconfig(老版本也称Config.in)和Makefile(老版本也称Kbuild)文件定义。
Linux内核配置系统也被移植到其它软件(如Busybox、glibc、uclibc等)中,来提供同样的配置界面以方便有选择性的配置。
1.2&内核配置工具
Linux内核配置命令主要有:make config、make menuconfig、make xconfig和make
gconfig,分别是字符界面、ncurses光标菜单、QT图形窗口和GTK图形窗口的配置界面。字符界面配置方式需要回答每一个选项提示,逐个回答进行配置并不方便,而光标和图形配置界面界面友好,方便实用。
make config是完全命令行的配置方式,make menuconfig依赖于ncurses库,make
xconfig依赖于QT图形库,make gconfig依赖于GTK图形库。
不同的内核配置方式,分别通过不同的配置工具来完成。scripts目录下提供了各种内核配置工具,表1是这些工具的说明。
表1&内核配置工具说明
Makefile相关目标
依赖的程序
config defconfig oldconfig …
conf.c、zconf.tab.c
menuconfig
mconf.c、zconf.tab.c
qconf.c、kconfig_load.c、zconf.tab.c
gconf.c、kconfig_load.c、zconf.tab.c
其中zconf.tab.c程序实现了解析Kconfig文件和内核配置主要函数。Zconf.tab.c程序还直接包括了下列一些C程序,这样各种配置功能都包含在zconf.tab.o目标文件中了。
其中,lex.zconf.c实现lex语法解析器,
util.c实现配置工具,
confdata.c实现.config等相关数据文件保存,
expr.c实现表达式函数,
symbol.c实现变量处理函数,
menu.c实现菜单控制函数。
1.3&内核配置方式
在顶层的Makefile中,可以查找到如下几行定义的规则:
这就是生成内核配置界面的命令规则,它也定义了执行的目标和依赖的前提条件,还有要执行的命令。这条规则定义的目标为config %config,通配符%意味着可以包括config、menuconfig、xconfig、gconfig等。依赖的前提条件是scripts_basic
outputmakefile,这些在Makefile中也是规则定义,主要用来编译生成配置工具。这条规则执行的命令就是执行scripts/kconfig/Makefile制定的规则。
根据配置工具的不同,内核有不同的配置方式。有命令行方式,还有图形界面方式。表2是各种内核配置方法的说明。
表2&内核配置方法的说明
通过命令行程序更新当前配置
menuconfig
通过菜单程序更新当前配置
通过QT图形界面更新当前配置
通过GTK图形界面更新当前配置
通过已经提供的.config文件更新当前配置
Randconfig
对所有的选项随机配置
对所有的选项缺省配置
allmodconfig
对所有的选项尽可能选择“m”
allyesconfig
对所有的选项尽可能选择“y”
allnoconfig
对所有的选项尽可能选择“n”的最小配置
这些内核配置方式是在scripts/kconfig/Makefile中通过规则定义的。从这个Makefile中,可以找到下面一些规则定义。如果把变量或者通配符带进去,就可以明白要执行的操作。
这里的ARCH以arm为例来说明。
执行命令:scripts/kconfig/qconf arch/arm/Kconfig,使用QT图形库生成配置界面,arch/arm/Kconfig是菜单的主配置文件,每种配置方式都需要。
执行命令:scripts/kconfig/qconf arch/arm/Kconfig,使用GTK图形库生成配置界面。
执行命令:scripts/kconfig/mconf arch/arm/Kconfig,使用lxdialog工具,生成光标配置菜单。
执行命令:scripts/kconfig/conf (-o/s) arch/arm/Kconfig,完全命令行的内核配置方式。使用“-o”选项,直接读取已经存在的.config文件,要求确定内核新的配置项。使用“-s”选项,直接读取已经存在的.config文件,提示但不要求确认内核新的配置项。
通过上述各种方式都可以完成配置内核的工作,在顶层目录下生成.config文件。这个.config文件保存大量的内核配置项,.config会自动转换成include/linux/autoconf.h头文件。在include/linux/config.h文件中,将包含使用include/linux/autoconf.h头文件。
2. Kconfig
linux在2.6版本以后将配置文件由原来的config.in改为Kconfig,对于Kconfig的语法在内核源代码/Documentation/kbuild/kconfig-language.txt中做了详细的说明。
2.1 Kconfig的树状关系
Kconfig的配置选项是以树的形式组织的,如下所示所示:
每个选项都有其自己的依赖关系。这些依赖关系决定了选项是否是可见的。父选项可见,子选项才能可见。
arch/$(ARCH)/Kconfig文件是主Kconfig文件,跟体系结构有关系。主Kconfig文件调用其他目录的Kconfig文件,其他的Kconfig文件又调用各级子目录的配置文件,成树状关系。
2.2菜单选项
多数选项定义了一个配置选项,其它选项起辅助组织作用。一个配置选项定义可以是下面的形式:
每行都是以关键字开始,并可以接多个参数。&config&&为定义了一新的配置选项。下面的几行定义了该配置选项的属性。属性可以是该配置选项的类型,输入提示(input prompt),依赖关系,帮助信息和默认值。一个配置选项可以用相同的名字定义多次,但每个定义只能有一个输入提示并且类型还不能冲突。
2.3菜单属性
一个菜单选项可以有多个属性,这些属性受到语法的限制。每个配置选项都必须指定类型。类型定义包括:&bool&、&tristate&、&string&、&hex&、&int&共五种。其中有两个基本类型:tristate&和&string,其他类型都是基于这两个基本类型。内核菜单属性说明表3所示。
表3&内核菜单属性说明
&prompt& &prompt&
[&if& &expr&]
每个菜单选项最多只能有一个显示给用户的输入提示。可以用&if&&来表示该提示的依赖关系,当然这是可选的。
默认值
&default& &expr&
[&if& &expr&]
一个配置选项可以有任意多个默认值。如果有多个默认值,那么只有第一个被定义的值是可用的。默认值并不是只限于应用在定义他们的菜单选项。这就意味着默认值可以定义在任何地方或被更早的定义覆盖。如果用户没有设置(通过上面的输入提示),配置选项的值就是默认值。如果可以显示输入提示的话,就会把默认值显示给用户,并可以让用户进行修改。默认值的依赖关系可以用&&if&&添加。
&depends on&
/&requires& &expr&
为一菜单选项定义依赖关系。如果定义了多个依赖关系,它们之间用&'&&'&间隔。依赖关系也可以应用到该菜单中所有的其它选项(同样接受一if表达式)。
反向依赖关系
&select& &symbol&
[&if& &expr&]
尽管普通的依赖关系可以降低一选项的上限,反向依赖能将这一限制降的更低。当前菜单选项的值是symbol的最小值。如果symbol被选择了多次,上限就是其中的最大值。反向依赖只能用在&boolean&或&tristate&选项上。
&range& &symbol&
[&if& &expr&]
为int和hex类型的选项设置可以接受输入值范围。用户只能输入大于等于第一个symbol,小于等于第二个symbol的值。
&---help---&
定义一帮助信息。帮助信息的结束就由缩进的水平决定的,这也就意味着信息是在第一个比帮助信息开始行的缩进小的行结束。&---help---&&和&&help&&在实现的作用上没有区别,&---help---&&有助于将文件中的配置逻辑与给开发人员的提示分开。
2.4菜单依赖关系
依赖关系决定了菜单选项是否可见,也可以减少tristate的输入范围。tristate逻辑比boolean逻辑在表达式中用更多的状态(state)来表示模块的状态。依赖关系表达式的语法如表4所示,表达式是以优先级的降序列出的。
表4&菜单依赖关系语法说明
&expr& ::= &symbol&
将symbol赋给表达式。boolean和tristate类型的symbol直接赋给表达式。所有其它类型的symbol都赋&'n'。
&symbol& '=' &symbol&
如果两个symbol相等,返回'y',否则为'n'。
&symbol& '!=' &symbol&
如果两个symbol相等,返回'n',否则为'y'。
'(' &expr& ')'
返回表达式的值。用于改变优先级。
'!' &expr&
返回&(2-/expr/)&的结果。
&expr& '&&' &expr&
返回&min(/expr/,/expr/)&的结果。
&expr& '||' &expr&
返回&max(/expr/,/expr/)&的结果。
一个表达式的值可以是'n','m'或'y'(或者是计算的结果&0,1,2)。当表达式的值为'm'或'y'的时候,菜单项才是可见的。
symbol有两种类型:不可变的和可变的。不可变的symbol是最普通的,由'config'语句定义,完全由数字、字母和下划线组成(alphanumeric
characters or underscores)。
不可变的symbol只是表达式的一部分。经常用单引号或双引号括起来。在引号中,可以使用任何字符,使用引号要用转义字符'\'。
2.5菜单结构
菜单在树中的位置可由两种方法决定。
第一种可以是这样:
所有的在&menu& ... &endmenu&&之间都是&Network device support&的子菜单。所有的子菜单选项都继承了父菜单的依赖关系,比如,&NET&的依赖关系就被加到了配置选项NETDEVICES的依赖列表中。
第二种是通过分析依赖关系生成菜单的结构。如果菜单选项在一定程度上依赖于前面的选项,它就能成为该选项的子菜单。首先,前面的(父)选项必须是依赖列表中的一部分并且它们中必须有满足下面两个条件的选项:如果父选项为'n',子选项必须不可见;如果父选项可见,子选项才能可见。
MODVERSIONS&直接依赖&MODULES,这就意味着如果MODULES不为'n',该选项才可见。换句话说,当MODULES可见时,选项才可见(MODULES的(空)依赖关系也是选项依赖关系的一部分)。
2.6 Kconfig语法
配置文件描述了菜单选项,每行都是以一关键字开头(除了帮助信息)。菜单的关键字如表5所示。其中菜单开头的关键字有:config、menuconfig、choice/endchoice、comment、menu/endmenu。它们也可以结束一个菜单选项,另外还有if/endif、source也可以结束菜单选项。
表5 Kconfig菜单关键字说明
&config& &symbol&
&config options&
定义了一配置选项&&symbol&&并且可以接受任何前面介绍的属性。
menuconfig
&menuconfig& &symbol&
&config options&
此关键字和前面的关键字很相似,但它在前面的基础上要求所有的子选项作为独立的行显示。
&choice options&
&choice block&
&endchoice&
该关键字定义了一组选择项,并且选项可以是前面描述的任何属性。尽管boolean只允许选择一个配置选项,tristate可以抒多个配置选项设为'm',但选项只能是boolean或tristate类型。这可以在一个硬件有多个驱动的情况下使用,最终只有一个驱动被编译进/加载到内核,,但所有的驱动都可以编译成模块。选项可以接受的另一个选项是&optional&,这样选项就被设置为'n',没有被选中的。
&comment& &prompt&
&comment options&
这定义了在配置过程中显示给用户的注释,该注释还将写进输出文件中。唯一可用的可选项是依赖关系。
&menu& &prompt&
&menu options&
&menu block&
这里定义了一个菜单,详细信息请看前面的&菜单结构&。唯一可用的可选项是依赖关系。
&if& &expr&
&if block&
这里定义了if结构。依赖关系&expr&被加到所有在if ... endif&中的菜单选项中。
“source” &prompt&
读取指定的配置文件。读取的文件也会解析生成菜单。
3. Kbuild Makefile
Linux内核源代码是通过Makefile组织编译的,Linux2.6内核Makefile的许多特性和2.4内核差别很大,在内核目录的documention/kbuild/makefiles.txt中有详细的说明。
3.1 Makefile的组织结构
Linux内核的Makefile分为5个部分,如表6所示:
表6 Makefile的5个部分
顶层Makefile
内核配置文件
arch/$(ARCH)/Makefile
具体架构的Makefile
scripts/Makefile.*
通用的规则等。面向所有的Kbuild Makefiles。
kbuild Makefiles
内核源代码中大约有500个这样的文件
顶层Makefile阅读的.config文件,而该文件是由内核配置程序生成的。
顶层Makefile负责制作:vmlinux(内核文件)与模块(任何模块文件)。制作的过程主要是
通过递归向下访问子目录的形式完成。并根据内核配置文件确定访问哪些子目录。顶层Makefile要原封不动的包含一具体架构的Makefile,其名字类似于arch/$(ARCH)/Makefile。该架构Makefile向顶层Makefile提供其架构的特别信息。
每一个子目录都有一个Kbuild Makefile文件,用来执行从其上层目录传递下来的命令。
Kbuild Makefile从.config文件中提取信息,生成Kbuild完成内核编译所需的文件列表。
scripts/Makefile.*包含了所有的定义、规则等信息。这些文件被用来编译基于kbuild
Makefile的内核。
3.2 Makefile语言
内核的Makefile使用的是GNU Make。该Makefile只使用GNU
Make已注明的功能,并使用了许多GNU&的扩展功能。
GNU Make支持基本的显示处理过程的函数。内核Makefile&使用了一种类似小说的方式,显示&if&语句的构造、处理过程。
GNU Make&有2个赋值操作符,&:=&和&=&。&:=&,将对右边的表达式求值,并将所求的值赋给左边。&=&更像是一个公式定义,只是将右边的值简单的赋值给左边,当左边的表达式被使用时,才求值。
有时使用&=&是正确的。但是,一般情况下,推荐使用&:=&。
3.3 Kbuild&变量
顶层Makefile输出以下变量:
(1)VERSION、PATCHLEVEL、SUBLEVEL和EXTRAVERSION
这些变量定义了当前内核的版本号。只有很少一部分Makefile会直接用到这些变量;可使用&$(KERNELRELEASE)代替。$(VERSION),$(PATCHLEVEL),和$(SUBLEVEL)定义了最初使用的三个数字的版本号,比如&2&&4&和&0&。这三个值一般是数字。$(EXTRAVERSION)&为了补丁定义了更小的版本号。一般是非数字的字符串,比如&-pre4&&,或就空着。
(2)KERNELRELEASE
$(KERNELRELEASE)&是一个字符串,类似&2.4.0-pre4&,用于安装目录的命名或显示当前的版本号。一部分架构Makefile使用该变量。
该变量定义了目标架构,比如&i386&,&arm&&或&sparc&。有些Kbuild Makefile根据&$(ARCH)&决定编译哪些文件。
默认情况下,顶层Makefile将其设置为本机架构。如果是跨平台编译,用户可以用下面的命令覆盖该值:
make ARCH=m68k ...
(4)INSTALL_PATH
该变量为架构Makefile定义了安装内核镜像与&System.map&文件的目录。主要用来指明架构特殊的安装路径。
(5)INSTALL_MOD_PATH和MODLIB
$(INSTALL_MOD_PATH)&为了安装模块,给&$(MODLIB)&声明了前缀。该变量不能在Makefile中定义,但可以由用户传给Makefile。
$(MODLIB)&具体的模块安装的路径。顶层Makefile将$(MODLIB)定义为
$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。用户可以通过命令行参数的形式将其覆盖。
(6)INSTALL_MOD_STRIP
如果该变量有定义,模块在安装之前,会被剥出符号表。如果INSTALL_MOD_STRIP&为&&1&,就使用默认选项&--strip-debug。否则,INSTALL_MOD_STRIP&将作为命令&strip的选项使用。
3.4 Kbuild Makefile的定义
大部分内核中的Makefile都是使用Kbuild组织结构的Kbuild Makefile。这章介绍了
Kbuild Makefile的语法。
Kbuild文件倾向于&Makefile&这个名字,&Kbuild&也是可以用的。但如果&Makefile&
&Kbuild&同时出现的话,使用的将会是&Kbuild&文件。
3.4.1&目标定义
目标定义是Kbuild Makefile的主要部分,也是核心部分。主要是定义了要编
译的文件,所有的选项,以及到哪些子目录去执行递归操作。
最简单的Kbuild makefile&只包含一行,如:
该例子告诉Kbuild在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c或foo.S文件编译得到。
如果foo.o要编译成一模块,那就要用obj-m了。所采用的形式如下:
$(CONFIG_FOO)可以为y(编译进内核)&或m(编译成模块)。如果CONFIG_FOO不是y和m,那么该文件就不会被编译联接了。
3.4.2&编译进内核&- obj-y
Kbuild Makefile&规定所有编译进内核的目标文件都存在$(obj-y)列表中。而这些列表依赖内核的配置。
Kbuild编译所有的$(obj-y)文件。然后,调用&$(LD) -r&将它们合并到一个build-in.o文件中。稍后,该build-in.o会被其父Makefile联接进vmlinux中。
$(obj-y)中的文件是有顺序的。列表中有重复项是可以的:当第一个文件被联接到built-in.o中后,其余文件就被忽略了。联接也是有顺序的,那是因为有些函数(module_init()/__initcall)将会在启动时按照他们出现的顺序进行调用。所以,记住改变联接的顺序可能改变你SCSI控制器的检测顺序,从而导致你的硬盘数据损害。
举例说明obj-y:
3.4.3&编译可装载模块&- obj-m
$(obj-m)&列举出了哪些文件要编译成可装载模块。
一个模块可以由一个文件或多个文件编译而成。如果是一个源文件,Kbuild Makefile只需简单的将其加到$(obj-m)中去就可以了。例如:
注意:此例中&$(CONFIG_ISDN_PPP_BSDCOMP)&的值为'm'
如果内核模块是由多个源文件编译而成,那你就要采用上面那个例子一样的方法去声明你所要编译的模块。Kbuild需要知道你所编译的模块是基于哪些文件,所以你需要通过变量$(&module_name&-objs)来告诉它。例如:
在这个例子中,模块名将是isdn.o,Kbuild将编译在$(isdn-objs)中列出的所有文件,然后使用&$(LD) -r&生成isdn.o。
Kbuild能够识别用于组成目标文件的后缀-objs和后缀-y。这就让Kbuild Makefile可以通过使用&CONFIG_&符号来判断该对象是否是用来组合对象的。例如:
在这个例子中,如果&$(CONFIG_EXT2_FS_XATTR)&是&'y',xattr.o将是复合对象ext2.o的一部分。
注意:当然,当你要将其编译进内核时,上面的语法同样适用。所以,如果你的CONFIG_EXT2_FS=y,那Kbuild会按你所期望的那样,生成ext2.o文件,然后将其联接到built-in.o中。
3.4.4目标库文件&- lib-y
在obj-*中所列文件是用来编译模块或者是联接到特定目录中的built-in.o。同样,也可以列出一些将被包含在lib.a库中的文件。在&lib-y&中所列出的文件用来组成该目录下的一个库文件。在obj-y与lib-y中同时列出的文件,因为都是可以访问的,所以该文件是不会被包含在库文件中的。同样的情况,lib-m中的文件就要包含在lib.a库文件中。
注意,一个Kbuild makefile可以同时列出要编译进内核的文件与要编译成库的文件。所以,在一个目录里可以同时存在built-in.o与lib.a两个文件。例如:
这将由&checksum.o&和delay.o&两个文件创建一个库文件&lib.a。为了让Kbuild真正认识到这里要有一个库文件lib.a要创建,其所在的目录要加到libs-y列表中。
3.4.5递归向下访问目录
一个Makefile只对编译所在目录的对象负责。在子目录中的文件的编译要由其所在的子目录的Makefile来管理。只要你让Kbuild知道它应该递归操作,那么该系统就会在其子目录中自动的调用&make&递归操作。
这就是obj-y和obj-m的作用。比如ext2被放的一个单独的目录下,在fs目录下的Makefile会告诉Kbuild使用下面的赋值进行向下递归操作。
如果&CONFIG_EXT2_FS&被设置为&'y'(编译进内核)或是'm'(编译成模块),相应的&obj-&变量就会被设置,并且Kbuild就会递归向下访问&ext2&目录。Kbuild只是用这些信息来决定它是否需要访问该目录,而具体怎么编译由该目录中的Makefile来决定。将&CONFIG_&变量设置成目录名是一个好的编程习惯。这让Kbuild在完全忽略那些相应的CONFIG_&值不是'y'和'm'的目录。
3.4.6编辑标志
编辑标记包括:EXTRA_CFLAGS,、EXTRA_AFLAGS、EXTRA_LDFLAGS、EXTRA_ARFLAG。所有的EXTRA_变量只在所定义的Kbuild
Makefile中起作用。EXTRA_变量可以在Kbuild Makefile中所有命令中使用。
$(EXTRA_CFLAGS)&是用&$(CC)&编译C源文件时的选项。例如:
该变量是必须的,因为顶层Makefile拥有变量&$(CFLAGS)&并用来作为整个源代码树的编译选项。
$(EXTRA_AFLAGS)&也是一个针对每个目录的选项,只不过它是用来编译汇编源代码的。例如:
$(EXTRA_LDFLAGS)和$(EXTRA_ARFLAGS)分别与$(LD)和$(AR)类似,只不过它们是针对每个目录的。例如:
CFLAGS_$@, AFLSGA_$@
CFLAGS_$@&和&AFLAGS_$@&只能在当前Kbuild Makefile中的命令中使用。
$(CFLAGS_$@)&是&$(CC)&针对每个文件的选项。$@&表明了具体操作的文件。例如:
以上三行分别设置了aha152x.o,gdth.o&和&seagate.o的编辑选项。
$(AFLAGS_$@)&也类似,只不是是针对汇编语言的。例如:
3.4.7依赖跟踪
Kbuild&跟踪在以下方面依赖于:
1)&所有要参与编译的文件(所有的.c&和.h文件)
2)&在参与编译文件中所要使用的&CONFIG_&选项
3)&用于编译目标的命令行
因此,如果你改变了&$(CC)&的选项,所有受影响的文件都要重新编译。
3.4.8特殊规则
特殊规则就是那Kbuild架构不能提供所要求的支持时,所使用的规则。一个典型的例子就是在构建过程中生成的头文件。另一个例子就是那些需要采用特殊规则来准备启动镜像。
特殊规则的写法与普通Make规则一样。Kbuild并不在Makefile所在的目录执行,所以所有的特殊规则都要提供参与编译的文件和目标文件的相对路径。
在定义特殊规则时,要使用以下两个变量:$(src)和$(obj)。$(src)&表明Makefile所在目录的相对路径。经常在定位源代码树中的文件时,使用该变量。$(obj)&表明目标文件所要存储目录的相对路径。经常在定位所生成的文件时,使用该变量。例如:
这就是一个特殊规则,遵守着make所要求的普通语法。
4.&一个使用linux kbuild实现可配置编译的例子
我编写了一个使用Linux kbuild机制实现可配置编译的小例子,工程名为print-example。包括如下如下几个目录:
其中scripts、Makefile、Makefile.flags是从busybox-1.9.0复制过来的。
4.1&运行print
运行make menuconfig命令弹出配置菜单如下:
进入Print Configure选项选择配置项:
这里选择代印信息1和2,保存退出配置界面。
运行make命令编译程序,生成print可执行文件,运行print结果如下:
运行make clean编译产生文件。
4.2&实现print
4.2.1&主目录Makefile
主目录Makefile修改部分代码如下:
使用core-y时是使用的静态链接目标文件obj-y,使用libs-y时是使用库目标文件lib-y,各个子目录的Makefile应该相应的使用obj-y或lib-y。
4.2.2主目录Kconfig
主目录Kconfig代码如下:
它给出了主菜单的配置选项,并有source关键字加入子目录的Kconfig文件。
4.2.3 main文件夹
main文件夹下共两个文件:
其中,main.c代码如下:
头文件autoconf.h是在编译过程中生成的。
Makefile代码如下:
4.2.4 printfun文件夹
printfun文件夹下有六个文件:
其中,printx.c(print1.c, print2.c, print3.c, print4.c)代码如下:
Makefile代码如下:
Kconfig代码如下:
4.2.5 include目录
include目录下只有一个文件print.h,代码如下:
【1】孙纪坤 配置编译内核
【2】linux kernel /Documentation/kbuild/kconfig-language.txt
【3】2.6Kconfig语法
【4】linux kernel /Documentation/kbuild/makefile.txt
【5】linux2.6内核Makefile详解
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:9536次
排名:千里之外
原创:13篇
转载:30篇
(1)(5)(4)(21)(12)

我要回帖

更多关于 写入位置发生访问冲突 的文章

 

随机推荐