在閱讀Linux內核代碼的時候,會經常遇到下面的幾個宏函數:

IS_ENABLED  這個宏最爲常見

IS_BUILTIN

IS_MODULE

IS_REACHABLE

這幾個宏函數是在文件include/linux/kconfig.h中定義的,如下:

/*
* Helper macros to use CONFIG_ options in C/CPP expressions. Note that
* these only work with boolean and tristate options.
*/ /*
* Getting something that works in C and CPP for an arg that may or may
* not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1"
* we match on the placeholder define, insert the "0," for arg1 and generate
* the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one).
* When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
* the last step cherry picks the 2nd arg, we get a zero.
*/
#define __ARG_PLACEHOLDER_1 0,
#define config_enabled(cfg) _config_enabled(cfg)
#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
#define ___config_enabled(__ignored, val, ...) val /*
* IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
* 0 otherwise.
*
*/
#define IS_ENABLED(option) \
(config_enabled(option) || config_enabled(option##_MODULE)) /*
* IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
* otherwise. For boolean options, this is equivalent to
* IS_ENABLED(CONFIG_FOO).
*/
#define IS_BUILTIN(option) config_enabled(option) /*
* IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
* otherwise.
*/
#define IS_MODULE(option) config_enabled(option##_MODULE) /*
* IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled
* code can call a function defined in code compiled based on CONFIG_FOO.
* This is similar to IS_ENABLED(), but returns false when invoked from
* built-in code when CONFIG_FOO is set to 'm'.
*/
#define IS_REACHABLE(option) (config_enabled(option) || \
(config_enabled(option##_MODULE) && config_enabled(MODULE)))

首先需要有一些基礎知識.

我們知道,在進行內核配置的時候,內核配置若是boolean類型,那麼對應的配置有y和n兩種狀態,如果是tristate,那麼對應的配置有y,n和m三種狀態.

然後,在編譯內核的時候會生成include/generated/autoconf.h

如果某個配置被設置爲了y,那麼在.config文件中:

CONFIG_SND_DUMMY=y

在autoconf.h中會看到:

#define CONFIG_SND_DUMMY 1

如果被設置爲了m,表示這個部分代碼會編譯成內核模塊,那麼在.config中會看到:

CONFIG_SND_DUMMY=m

在autoconf.h中會看到:

#define CONFIG_SND_DUMMY_MODULE 1

可以看到,在宏的末尾多了一個_MODULE的後綴.

如果被設置爲了n,那麼在.config中會看到:

# CONFIG_SND_DUMMY is not set

而在autoconf.h中看不到這個宏的任何定義.

對於靜態編譯到kernel中的文件, 在編譯的時候會宏MODULE不會被定義

而對於編譯到模塊中的文件,在編譯的時候,編譯系統會定義MODULE宏.

下面解釋一下這幾個宏函數的作用

  • IS_ENABLED

如果option或者option_MODULE所表示的宏定義在當前上下文被設置爲了1, 那麼這個宏函數會返回1;如果沒有定義或者被定義爲了0, 那麼就返回0.

無論CONFIG_SND_DUMMY被設置爲了y還是m,IS_ENABLED(CONFIG_SND_DUMMY)都會返回1.

  • IS_BUILTIN

如果option所表示的宏定義在當前上下文被設置爲了1, 那麼這個宏函數會返回1;如果沒有定義或者被定義爲了0, 那麼就返回0.

只有CONFIG_SND_DUMMY被設置爲了y,IS_BUILTIN(CONFIG_SND_DUMMY)才會返回1.

  • IS_MODULE

如果option_MODULE所表示的宏定義在當前上下文被設置爲了1, 那麼這個宏函數會返回1;如果沒有定義或者被定義爲了0, 那麼就返回0.

只有CONFIG_SND_DUMMY被設置爲了m,IS_MODULE(CONFIG_SND_DUMMY)才會返回1.

  • IS_REACHABLE

這個宏函數跟IS_ENABLED的類似, 不同之處是,如果CONFIG_SND_DUMMY被設置爲了m,那麼IS_REACHABLE(CONFIG_SND_DUMMY)在靜態編譯到kernel中的文件中被預處理的時候會返回0,而在編譯到模塊的文件中預處理時會返回0.原因是MODULE宏只有在編譯模塊代碼期間纔會被定義.

下面我們將config_enabled(CONFIG_SND_DUMMY)展開:

如果CONFIG_SND_DUMMY在autoconf.h中被設置爲了1, 那麼展開如下:

___config_enabled(__ARG_PLACEHOLDER_1 1, 0)

再進一步展開

___config_enabled(, , )

最後展開如下:

如果CONFIG_SND_DUMMY在autoconf.h中沒有被設置, 那麼展開如下:

___config_enabled(__ARG_PLACEHOLDER_CONFIG_SND_DUMMY , )

進一步展開如下:

下面用一個簡單的測試程序試試:

a.c

 #define __ARG_PLACEHOLDER_1 0,
#define config_enabled(cfg) _config_enabled(cfg)
#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
#define ___config_enabled(__ignored, val, ...) val #define ONE 2
#define TWO 1
#define THREE 0
#define FOUR int main(int argc, char *argv[])
{ int a; if (config_enabled(ONE)) {
a = ;
} if (config_enabled(TWO)) {
a = ;
} if (config_enabled(THREE)) {
a = ;
} if (config_enabled(FOUR)) {
a = ;
} if (config_enabled(FIVE)) {
a = ;
} return ;
}

然後使用gcc的預編譯命令 gcc -E a.c -o a.i 編譯出文件a.i如下:

 int main(int argc, char *argv[])
{ int a; if () {
a = ;
} if () {
a = ;
} if () {
a = ;
} if () {
a = ;
} if () {
a = ;
} return ;
}

完.

Linux驱动开发—— IS_ENABLED的更多相关文章

  1. 嵌入式Linux驱动开发日记

    嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...

  2. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  3. 【转】linux驱动开发的经典书籍

    原文网址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书 ...

  4. Linux驱动开发 -- 打开dev_dbg()

    Linux驱动开发 -- 打开dev_dbg() -- :: 分类: LINUX linux设备驱动调试,我们在内核中看到内核使用dev_dbg来控制输出信息,这个函数的实质是调用printk(KER ...

  5. Linux驱动开发学习的一些必要步骤

      1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ...

  6. 驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  7. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  8. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html   IT168 技术文档]在开始步入L ...

  9. Linux内核(17) - 高效学习Linux驱动开发

    这本<Linux内核修炼之道>已经开卖(网上的链接为: 卓越.当当.china-pub ),虽然是严肃文学,但为了保证流畅性,大部分文字我还都是斟词灼句,反复的念几遍才写上去的,尽量考虑到 ...

随机推荐

  1. Scrapy框架爬虫初探——中关村在线手机参数数据爬取

    关于Scrapy如何安装部署的文章已经相当多了,但是网上实战的例子还不是很多,近来正好在学习该爬虫框架,就简单写了个Spider Demo来实践.作为硬件数码控,我选择了经常光顾的中关村在线的手机页面 ...

  2. Partition:增加分区

    在关系型 DB中,分区表经常使用DateKey(int 数据类型)作为Partition Column,每个月的数据填充到同一个Partition中,由于在Fore-End呈现的报表大多数是基于Mon ...

  3. 红黑树——算法导论(15)

    1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...

  4. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  5. .Net 大型分布式基础服务架构横向演变概述

    一. 业务背景 构建具备高可用,高扩展性,高性能,能承载高并发,大流量的分布式电子商务平台,支持用户,订单,采购,物流,配送,财务等多个项目的协作,便于后续运营报表,分析,便于运维及监控. 二. 基础 ...

  6. Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用

    通过本文你将学会如下内容: 1,如何使用Xamarin开发跨平台(Windows,Android,iOS)应用. 2,如何使用微软的登录界面登入Microsoft账号. 3,如何使用Outlook邮箱 ...

  7. InstallShield 脚本语言学习笔记

    InstallShield脚本语言是类似C语言,利用InstallShield的向导或模板都可以生成基本的脚本程序框架,可以在此基础上按自己的意愿进行修改和添加.     一.基本语法规则      ...

  8. 读python源码--对象模型

    学python的人都知道,python中一切皆是对象,如class生成的对象是对象,class本身也是对象,int是对象,str是对象,dict是对象....所以,我很好奇,python是怎样实现这些 ...

  9. linux应用调试技术之GDB和GDBServer

    1.调试原理 GDB调试是应用程序在开发板上运行,然后在PC机上对开发板上得应用程序进行调试,PC机运行GDB,开发板上运行GDBServer.在应用程序调试的时候,pc机上的gdb向开发板上的GDB ...

  10. 【JQ基础】数组

    each() 方法规定为每个匹配元素规定运行的函数.