• Linux驱动开发—— IS_ENABLED


    在閱讀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_DUMMYautoconf.h中被設置爲了1, 那麼展開如下:

    ___config_enabled(__ARG_PLACEHOLDER_1 1, 0)

    再進一步展開

    ___config_enabled(0, 1, 0) 

    最後展開如下:

      1 

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

     ___config_enabled(__ARG_PLACEHOLDER_CONFIG_SND_DUMMY 1, 0) 

    進一步展開如下:

      0 

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

    a.c

     1 #define __ARG_PLACEHOLDER_1 0,
     2 #define config_enabled(cfg) _config_enabled(cfg)
     3 #define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
     4 #define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
     5 #define ___config_enabled(__ignored, val, ...) val
     6 
     7 #define ONE 2
     8 #define TWO 1
     9 #define THREE 0
    10 #define FOUR
    11 
    12 int main(int argc, char *argv[])
    13 {
    14 
    15     int a;
    16 
    17     if (config_enabled(ONE)) {
    18          a = 1;
    19     }
    20 
    21     if (config_enabled(TWO)) {
    22          a = 1;
    23     }
    24 
    25     if (config_enabled(THREE)) {
    26          a = 1;
    27     }
    28 
    29     if (config_enabled(FOUR)) {
    30          a = 1;
    31     }
    32 
    33     if (config_enabled(FIVE)) {
    34          a = 1;
    35     }
    36 
    37     return 0;
    38 }

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

     1 int main(int argc, char *argv[])
     2 {
     3 
     4  int a;
     5 
     6  if (0) {
     7    a = 1;
     8  }
     9 
    10  if (1) {
    11    a = 1;
    12  }
    13 
    14  if (0) {
    15    a = 1;
    16  }
    17 
    18  if (0) {
    19    a = 1;
    20  }
    21 
    22  if (0) {
    23    a = 1;
    24  }
    25 
    26  return 0;
    27 }

    完.

  • 相关阅读:
    07noip 统计数字 解题报告
    07noip 矩阵取数游戏 解题报告
    10 noip 乌龟棋 解题报告
    10 noip 引水入城 解题报告
    让我们来看一看C++ 简短自序
    curl post请求封装
    array_merge与数组加
    composer设置autoload自己的代码
    mysql使用笔记
    android入门:zxing学习笔记(六)
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/5960412.html
Copyright © 2020-2023  润新知