Menu

#4 Linux kernel IS_ENABLED, IS_BUILTIN, IS_MODULE support

v6.0
open
None
3
2017-08-18
2014-11-22
No

How difficult would adding optional support for kernel style IS_ENABLED, IS_MODULE, and IS_BUILTIN be? I patched the original unifdef source provided in the kernel, which added support for these.

I work on a Linux module which has several layers of configuration and we use unifdef today for pre-processing our code into distributable source. However, I would like to switch over to using coan for this.

I tried creating a definition for IS_ENABLED, but coan seemed not to be smart enough at processing it.

I don't know how complicated it would be to add more expressions so that IS_ENABLED would work like defined() does. Obviously this would have to be behind a special option to enable the extra support as it is non-standard.

Related

help: #4

Discussion

  • Mike Kinghan

    Mike Kinghan - 2014-11-23

    Hi Jacob,

    Is the -m | --implicit option too much of a shotgun for your purposes?
    E.g.

    $ cat test.c
    #define CONFIG_YES 1
    #define CONFIG_NO 0
    
    #define IS_ENABLED(m) ((m) != 0)
    
    #if IS_ENABLED(CONFIG_YES)
    CONFIG_YES is enabled
    #else
    CONFIG_YES is not enabled
    #endif
    #if IS_ENABLED(CONFIG_NO)
    CONFIG_NO is enabled
    #else
    CONFIG_NO is not enabled
    #endif
    
    #if IS_ENABLED(CONFIG_UNDEF)
    CONFIG_UNDEF is enabled
    #else
    CONFIG_UNDEF is not enabled
    #endif
    
    $ coan source -m test.c > out.c
    coan: /home/imk/develop/scrap/test.c: line 1: warning 0x0041b: "-DCONFIG_YES=1" has been assumed for the current file
    coan: /home/imk/develop/scrap/test.c: line 2: warning 0x0041b: "-DCONFIG_NO=0" has been assumed for the current file
    coan: /home/imk/develop/scrap/test.c: line 4: warning 0x0041b: "-DIS_ENABLED(m)=((m) != 0)" has been assumed for the current file
    
    $ cat out.c
    #define CONFIG_YES 1
    #define CONFIG_NO 0
    
    #define IS_ENABLED(m) ((m) != 0)
    
    CONFIG_YES is enabled
    CONFIG_NO is not enabled
    
    CONFIG_UNDEF is not enabled
    
     
  • Jacob Keller

    Jacob Keller - 2014-11-25

    Hi. Here are the problems with this approach

    IS_ENABLED is defined in the kernel headers, not in the code we are stripping so I would have to define it on the command line. Also, IS_ENABLED has the following definition in order to work even with symbols which are not defined.

    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 IS_ENABLED(option) \

    (config_enabled(option) || config_enabled(option##_MODULE))
    

    I tried using this with coan source -m, and I was not able to handle symbols correctly. I also tried a simpler definition:

    define IS_ENABLED(option) defined(option) || defined (option##module)

    However, this does not properly work because using preprocessor "defined" sets inside of the macro is undefined behavior. It works in gcc, but apparently does not work in coan.

    I need IS_ENABLED, (IS_BUILTIN, and IS_MODULE) to work for symbols defined or not, and to be treated essentially as "defined" is.

    Preferably (for simplicity with how stripping really is used) IS_ENABLED could be just a synonym for defined(option). This mirrors how we use it now, but having the full functionality wouldn't hurt.

     
  • Mike Kinghan

    Mike Kinghan - 2014-11-29

    I see that --implicit can't solve this one. However I do not want to put in a feature as narrow as providing a special implementation for a particular macro or set of macros. I'd like coan to cope with your problem macros, but in a generally useful way.

    Obviously, the right answer is to implement variadic macro support in coan. It's a C99 standard feature I have just left aside for years because macro expansion was so hard even without it. Coan even retains the information that a macro is variadic just so that it can emit an apology for not expanding any of its invocations. So that's what I will do. I'll put variadic macro support on the v7.0 feature set. v7.0 is the next release and would probably have landed in Feb/Mar '15. Variadic macro support and the other good feature you want - filtering insoluble symbols - will set it back about a month.

    Meantime I'll drop you a one-off patch that just maps IS_ENABLED(x), IS_BUILTIN(x) and IS_MODULE(x) to defined(x). I'm afraid I don't have time this weekend: you can expect it within a week.

     
  • Jacob Keller

    Jacob Keller - 2014-12-01

    Note that I tried using a simpler form of

    define IS_ENABLED(x) defined(x) || defined(x##_MODULE)

    This doesn't work either because coan doesn't support using cpp directive defined in the macro. It sees x and says X isn't a defined value and then fails to work.

    I don't strictly need support for the variadic macros, though support for the ## expansion is important for IS_MODULE, which is effectively

    define IS_MODULE(x) defined(x##_MODULE)

    I know this is a non-standard "undefined behavior" feature, but I think it would be good to support it. At least GCC seems to support it correctly.

    I agree making coan have a side feature for a specific build system isn't as good as supporting the full macros correctly (though this is indeed quite complex)

    Thanks for the help.

     
  • Mike Kinghan

    Mike Kinghan - 2014-12-05

    Jacob,

    Here is a hack to be going on with. In the coan-6.0.1 source package,
    edit src/expression_parser.cpp, replacing the lines 596-625 inclusive, i.e.

    if (word == TOK_DEFINED) {
        bool paren;
        chew(greyspace);
        paren = *chew == '(';
        if (paren) {
            chew(+1,greyspace);
        }
        symbol::locator sloc(chew);
        chew(greyspace);
        if (paren) {
            if (*chew == ')') {
                chew(+1,greyspace);
            } else {
            /* Missing ')'*/
                error_unbalanced_paren() << "Expected \")\" after \""
                << citable(!options::plaintext(),_seq.substr(0,size_t(chew)))
                    << "\" in \""
                << citable(!options::plaintext(),_seq) << '\"' << defer();
                result.set_insoluble();
            }
        }
        sloc->report();
        if (!sloc->configured()) {
            if (options::implicit()) {
                result.set_value(0);
            }
            break;
        }
        result.set_value(sloc->defined());
        break;
    

    with:

    if (word == TOK_DEFINED ||
        word == "IS_ENABLED" ||
        word == "IS_MODULE" ||
        word == "IS_BUILTIN") {
        bool paren;
        chew(greyspace);
        paren = *chew == '(';
        if (paren) {
            chew(+1,greyspace);
        }
        symbol::locator sloc(chew);
        chew(greyspace);
        if (paren) {
            if (*chew == ')') {
                chew(+1,greyspace);
            } else {
            /* Missing ')'*/
                error_unbalanced_paren() << "Expected \")\" after \""
                << citable(!options::plaintext(),_seq.substr(0,size_t(chew)))
                    << "\" in \""
                << citable(!options::plaintext(),_seq) << '\"' << defer();
                result.set_insoluble();
            }
        }
        sloc->report();
        if (word == TOK_DEFINED) {
            if (!sloc->configured()) {
                if (options::implicit()) {
                    result.set_value(0);
                }
                break;
            }
            result.set_value(sloc->defined());
        } else if (word == "IS_BUILTIN") {
            if (!sloc->configured()) {
                break;
            }
            result.set_value(sloc->defined());
        } else if (word == "IS_MODULE") {
            string s = sloc->id() + "_MODULE";
            symbol::locator sloc_mod(s);
            if (!sloc_mod->configured()) {
                break;
            }
            result.set_value(sloc_mod->defined());
        } else if (word == "IS_ENABLED") {
            string s = sloc->id() + "_MODULE";
            symbol::locator sloc_mod(s);
            if (!sloc->configured() && !sloc_mod->configured()) {
                break;
            }
            result.set_value(sloc->defined() || sloc_mod->defined());
        }
        break;
    

    Then rebuild.

    This has the effects:-

    • coan evaluates IS_BUILTIN(s) as {true|false|indeterminate} in the
      same circumstances as defined(s)

    • coan evaluates IS_MODULE(s) as {true|false|indeterminate} in the
      same circumstances as defined(s_MODULE)

    • coan evaluates IS_ENABLED(s) as {true|false|indeterminate} in the
      same circumstances as defined(s) || defined(s_MODULE)

    with the proviso that the {-m | --implicit} option is not respected
    by the IS_XXXXX operators.

    Because the IS_XXXXX are hacked as operators, the symbols command
    will not report them (as really it should)

    Hope this is good enough as a stop-gap.

     
    • Jacob Keller

      Jacob Keller - 2014-12-09

      Thanks! This is perfect stopgap. J

      Regards,
      Jake

      From: Mike Kinghan [mailto:imkinghan@users.sf.net]
      Sent: Friday, December 05, 2014 7:24 AM
      To: [coan2:help]
      Subject: [coan2:help] #4 Linux kernel IS_ENABLED, IS_BUILTIN, IS_MODULE support

      Jacob,

      Here is a hack to be going on with. In the coan-6.0.1 source package,
      edit src/expression_parser.cpp, replacing the lines 596-625 inclusive, i.e.

      if (word == TOK_DEFINED) {

      bool paren;
      
      chew(greyspace);
      
      paren = *chew == '(';
      
      if (paren) {
      
          chew(+1,greyspace);
      
      }
      
      symbol::locator sloc(chew);
      
      chew(greyspace);
      
      if (paren) {
      
          if (*chew == ')') {
      
              chew(+1,greyspace);
      
          } else {
      
          /* Missing ')'*/
      
              error_unbalanced_paren() << "Expected \")\" after \""
      
              << citable(!options::plaintext(),_seq.substr(0,size_t(chew)))
      
                  << "\" in \""
      
              << citable(!options::plaintext(),_seq) << '\"' << defer();
      
              result.set_insoluble();
      
          }
      
      }
      
      sloc->report();
      
      if (!sloc->configured()) {
      
          if (options::implicit()) {
      
              result.set_value(0);
      
          }
      
          break;
      
      }
      
      result.set_value(sloc->defined());
      
      break;
      

      with:

      if (word == TOK_DEFINED ||

      word == "IS_ENABLED" ||
      
      word == "IS_MODULE" ||
      
      word == "IS_BUILTIN") {
      
      bool paren;
      
      chew(greyspace);
      
      paren = *chew == '(';
      
      if (paren) {
      
          chew(+1,greyspace);
      
      }
      
      symbol::locator sloc(chew);
      
      chew(greyspace);
      
      if (paren) {
      
          if (*chew == ')') {
      
              chew(+1,greyspace);
      
          } else {
      
          /* Missing ')'*/
      
              error_unbalanced_paren() << "Expected \")\" after \""
      
              << citable(!options::plaintext(),_seq.substr(0,size_t(chew)))
      
                  << "\" in \""
      
              << citable(!options::plaintext(),_seq) << '\"' << defer();
      
              result.set_insoluble();
      
          }
      
      }
      
      sloc->report();
      
      if (word == TOK_DEFINED) {
      
          if (!sloc->configured()) {
      
              if (options::implicit()) {
      
                  result.set_value(0);
      
              }
      
              break;
      
          }
      
          result.set_value(sloc->defined());
      
      } else if (word == "IS_BUILTIN") {
      
          if (!sloc->configured()) {
      
              break;
      
          }
      
          result.set_value(sloc->defined());
      
      } else if (word == "IS_MODULE") {
      
          string s = sloc->id() + "_MODULE";
      
          symbol::locator sloc_mod(s);
      
          if (!sloc_mod->configured()) {
      
              break;
      
          }
      
          result.set_value(sloc_mod->defined());
      
      } else if (word == "IS_ENABLED") {
      
          string s = sloc->id() + "_MODULE";
      
          symbol::locator sloc_mod(s);
      
          if (!sloc->configured() && !sloc_mod->configured()) {
      
              break;
      
          }
      
          result.set_value(sloc->defined() || sloc_mod->defined());
      
      }
      
      break;
      

      Then rebuild.

      This has the effects:-

      • coan evaluates IS_BUILTIN(s) as {true|false|indeterminate} in the
        same circumstances as defined(s)

      • coan evaluates IS_MODULE(s) as {true|false|indeterminate} in the
        same circumstances as defined(s_MODULE)

      • coan evaluates IS_ENABLED(s) as {true|false|indeterminate} in the
        same circumstances as defined(s) || defined(s_MODULE)

      with the proviso that the {-m | --implicit} option is not respected
      by the IS_XXXXX operators.

      Because the IS_XXXXX are hacked as operators, the symbols command
      will not report them (as really it should)

      Hope this is good enough as a stop-gap.


      [help:#4]http://sourceforge.net/p/coan2/help/4 Linux kernel IS_ENABLED, IS_BUILTIN, IS_MODULE support

      Status: open
      Group: v6.0
      Created: Sat Nov 22, 2014 01:16 AM UTC by Jacob Keller
      Last Updated: Mon Dec 01, 2014 10:04 PM UTC
      Owner: Mike Kinghan

      How difficult would adding optional support for kernel style IS_ENABLED, IS_MODULE, and IS_BUILTIN be? I patched the original unifdef source provided in the kernel, which added support for these.

      I work on a Linux module which has several layers of configuration and we use unifdef today for pre-processing our code into distributable source. However, I would like to switch over to using coan for this.

      I tried creating a definition for IS_ENABLED, but coan seemed not to be smart enough at processing it.

      I don't know how complicated it would be to add more expressions so that IS_ENABLED would work like defined() does. Obviously this would have to be behind a special option to enable the extra support as it is non-standard.


      Sent from sourceforge.net because you indicated interest in https://sourceforge.net/p/coan2/help/4/https://sourceforge.net/p/coan2/help/4

      To unsubscribe from further messages, please visit https://sourceforge.net/auth/subscriptions/https://sourceforge.net/auth/subscriptions

       

      Related

      help: #4

  • Klaus

    Klaus - 2017-08-18

    I just stumbled across this, because we came across a similar issue as we want to apply coan to Linux.
    According to this discussion soon a new release was expected that should take care of full support for these macros.
    However, it seems this new release never came? Is this still in development or abandoned?

    Thanks in advance for any update on the status!

     
  • Jacob Keller

    Jacob Keller - 2017-08-18

    I haven't heard anything more about this myself. I suspect it's very difficult to add full proper support for complex multi-layered macros. I do not know the difficulty of just hacked in support for IS_ENABLED and friends. I personally would love to see such support as I think coan is much more featured than unifdef, but I do not know if the project is still actively developed at all.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.