1. 程式人生 > >Linux kernel中的IS_ENABLED

Linux kernel中的IS_ENABLED

在kernel的程式碼中, 有時候會看見IS_ENABLED(CONFIG_XXXX)來測試某個Kconfig選項是否開啟(即選中為y或者m). 如

if (IS_ENABLED(CONFIG_TIME_LOW_RES) && timer->is_rel)
    rem -= hrtimer_resolution;

這裡當TIME_LOW_RES這個Kconfig選項配置為ym, 並且timer->is_rel不為0時呼叫rem -= hrtimer_resolution.
那麼這個是怎樣實現的呢?
首先在Kconfig中選中某個選項為ym時, 在.config

檔案中就會由一個CONFIG_XXXXX=yCONFIG_XXXXX=m, 並且會自動生成一個頭檔案autoconfig.h. 當選中為y時, 標頭檔案中包含#define CONFIG_XXXXX 1, 當選中為m時, 標頭檔案中包含#define CONFIG_XXXXX_MODULE 1, 當不選中是, 標頭檔案中不包含相關語句.
IS_ENABLED定義為

#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option))

IS_BUILTIN, IS_MODULE__or分別定義為

#define IS_BUILTIN(option) __is_defined(option)
#define IS_MODULE(option) __is_defined(option##_MODULE)
#define __or(x, y)          ___or(x, y)
#define ___or(x, y)         ____or(__ARG_PLACEHOLDER_##x, y)
#define ____or(arg1_or_junk, y)     __take_second_arg(arg1_or_junk 1, y)

__is_defined定義為

#define __is_defined(x)         ___is_defined(x)
#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) #define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0)

在這之前定義了

#define __ARG_PLACEHOLDER_1 0,
#define __take_second_arg(__ignored, val, ...) val

#define CONFIG_XXXXX 1__is_defined(1)展開為____is_defined(0,), 即__take_second_arg(0, 1, 0), 最終為1
CONFIG_XXXXX沒有定義時__is_defined()展開為____is_defined()(因為沒有定義__ARG_PLACEHOLDER_), 即__take_second_arg(1, 0), 最終為0
同樣的方法可以理解__or.
因此IS_ENABLED主要是將沒有定義的CONFIG_XXXXX對映到0.