Re: [PATCH v2 09/21] kconfig: add 'macro' keyword to support user-defined function

2018-04-12 Thread Masahiro Yamada
2018-04-01 15:05 GMT+09:00 Ulf Magnusson :
> On Tue, Mar 27, 2018 at 7:29 AM, Masahiro Yamada
>  wrote:
>> Now, we got a basic ability to test compiler capability in Kconfig.
>>
>> config CC_HAS_STACKPROTECTOR
>> def_bool $(shell (($CC -Werror -fstack-protector -c -x c /dev/null 
>> -o /dev/null) && echo y) || echo n)
>>
>> This works, but it is ugly to repeat this long boilerplate.
>>
>> We want to describe like this:
>>
>> config CC_HAS_STACKPROTECTOR
>> bool
>> default $(cc-option -fstack-protector)
>>
>> It is straight-forward to add a new function, but I do not like to
>> hard-code specialized functions like this.  Hence, here is another
>> feature to add functions from Kconfig files.
>>
>> A user-defined function is defined with a special keyword 'macro'.
>> It can be referenced in the same way as built-in functions.  This
>> feature was also inspired by Makefile where user-defined functions
>> are referenced by $(call func-name, args...), but I omitted the 'call'
>> to makes it shorter.
>>
>> The macro definition can contain $(1), $(2), ... which will be replaced
>> with arguments from the caller.  The macro works just as a textual
>> shorthand, which is also expanded in the lexer phase.
>>
>> [Example Code]
>>
>>   macro success $(shell ($(1) && echo y) || echo n)
>>
>>   config TRUE
>>   bool "true"
>>   default $(success true)
>>
>>   config FALSE
>>   bool "false"
>>   default $(success false)
>>
>> [Result]
>>
>>   $ make -s alldefconfig
>>   $ tail -n 2 .config
>>   CONFIG_TRUE=y
>>   # CONFIG_FALSE is not set
>>
>> [Example Code]
>>
>>   macro success $(shell ($(1) && echo y) || echo n)
>>
>>   macro cc-option $(success $CC -Werror $(1) -c -x c /dev/null -o /dev/null)
>>
>>   config CC_HAS_STACKPROTECTOR
>>   def_bool $(cc-option -fstack-protector)
>>
>> [Result]
>>   $ make -s alldefconfig
>>   $ tail -n 1 .config
>>   CONFIG_CC_HAS_STACKPROTECTOR=y
>>
>> Signed-off-by: Masahiro Yamada 
>> ---
>>
>> Reminder for myself:
>> Update Documentation/kbuild/kconfig-language.txt
>>
>> Changes in v2:
>>   - Use 'macro' directly instead of inside the string type symbol.
>>
>>  scripts/kconfig/function.c  | 59 
>> +++--
>>  scripts/kconfig/lkc_proto.h |  1 +
>>  scripts/kconfig/zconf.l | 31 
>>  3 files changed, 89 insertions(+), 2 deletions(-)
>>
>> diff --git a/scripts/kconfig/function.c b/scripts/kconfig/function.c
>> index 913685f..389bb44 100644
>> --- a/scripts/kconfig/function.c
>> +++ b/scripts/kconfig/function.c
>> @@ -15,6 +15,7 @@ static LIST_HEAD(function_list);
>>  struct function {
>> char *name;
>> char *(*func)(struct function *f, int argc, char *argv[]);
>> +   char *macro;
>> struct list_head node;
>>  };
>>
>> @@ -31,7 +32,8 @@ static struct function *func_lookup(const char *name)
>>  }
>>
>>  static void func_add(const char *name,
>> -char *(*func)(struct function *f, int argc, char 
>> *argv[]))
>> +char *(*func)(struct function *f, int argc, char 
>> *argv[]),
>> +const char *macro)
>>  {
>> struct function *f;
>>
>> @@ -44,6 +46,7 @@ static void func_add(const char *name,
>> f = xmalloc(sizeof(*f));
>> f->name = xstrdup(name);
>> f->func = func;
>> +   f->macro = macro ? xstrdup(macro) : NULL;
>>
>> list_add_tail(&f->node, &function_list);
>>  }
>> @@ -51,6 +54,7 @@ static void func_add(const char *name,
>>  static void func_del(struct function *f)
>>  {
>> list_del(&f->node);
>> +   free(f->macro);
>> free(f->name);
>> free(f);
>>  }
>> @@ -108,6 +112,57 @@ char *func_eval_n(const char *func, size_t n)
>> return res;
>>  }
>>
>> +/* run user-defined function */
>> +static char *do_macro(struct function *f, int argc, char *argv[])
>> +{
>> +   char *new;
>> +   char *src, *p, *res;
>> +   size_t newlen;
>> +   int n;
>> +
>> +   new = xmalloc(1);
>> +   *new = 0;
>
> new = '\0' would be consistent with the rest of the code.
>
>> +
>> +   /*
>> +* This is a format string. $(1), $(2), ... must be replaced with
>> +* function arguments.
>> +*/
>> +   src = f->macro;
>> +   p = src;
>> +
>> +   while ((p = strstr(p, "$("))) {
>> +   if (isdigit(p[2]) && p[3] == ')') {
>> +   n = p[2] - '0';
>> +   if (n < argc) {
>> +   newlen = strlen(new) + (p - src) +
>> +   strlen(argv[n]) + 1;
>> +   new = xrealloc(new, newlen);
>> +   strncat(new, src, p - src);
>> +   strcat(new, argv[n]);
>> +   src = p + 4;
>> +   }
>
> Might be nice to warn when a macro call has missing argu

Re: [PATCH v2 09/21] kconfig: add 'macro' keyword to support user-defined function

2018-03-31 Thread Ulf Magnusson
On Sun, Apr 1, 2018 at 8:05 AM, Ulf Magnusson  wrote:
> On Tue, Mar 27, 2018 at 7:29 AM, Masahiro Yamada
>  wrote:
>> Now, we got a basic ability to test compiler capability in Kconfig.
>>
>> config CC_HAS_STACKPROTECTOR
>> def_bool $(shell (($CC -Werror -fstack-protector -c -x c /dev/null 
>> -o /dev/null) && echo y) || echo n)
>>
>> This works, but it is ugly to repeat this long boilerplate.
>>
>> We want to describe like this:
>>
>> config CC_HAS_STACKPROTECTOR
>> bool
>> default $(cc-option -fstack-protector)
>>
>> It is straight-forward to add a new function, but I do not like to
>> hard-code specialized functions like this.  Hence, here is another
>> feature to add functions from Kconfig files.
>>
>> A user-defined function is defined with a special keyword 'macro'.
>> It can be referenced in the same way as built-in functions.  This
>> feature was also inspired by Makefile where user-defined functions
>> are referenced by $(call func-name, args...), but I omitted the 'call'
>> to makes it shorter.
>>
>> The macro definition can contain $(1), $(2), ... which will be replaced
>> with arguments from the caller.  The macro works just as a textual
>> shorthand, which is also expanded in the lexer phase.
>>
>> [Example Code]
>>
>>   macro success $(shell ($(1) && echo y) || echo n)
>>
>>   config TRUE
>>   bool "true"
>>   default $(success true)
>>
>>   config FALSE
>>   bool "false"
>>   default $(success false)
>>
>> [Result]
>>
>>   $ make -s alldefconfig
>>   $ tail -n 2 .config
>>   CONFIG_TRUE=y
>>   # CONFIG_FALSE is not set
>>
>> [Example Code]
>>
>>   macro success $(shell ($(1) && echo y) || echo n)
>>
>>   macro cc-option $(success $CC -Werror $(1) -c -x c /dev/null -o /dev/null)
>>
>>   config CC_HAS_STACKPROTECTOR
>>   def_bool $(cc-option -fstack-protector)
>>
>> [Result]
>>   $ make -s alldefconfig
>>   $ tail -n 1 .config
>>   CONFIG_CC_HAS_STACKPROTECTOR=y
>>
>> Signed-off-by: Masahiro Yamada 
>> ---
>>
>> Reminder for myself:
>> Update Documentation/kbuild/kconfig-language.txt
>>
>> Changes in v2:
>>   - Use 'macro' directly instead of inside the string type symbol.
>>
>>  scripts/kconfig/function.c  | 59 
>> +++--
>>  scripts/kconfig/lkc_proto.h |  1 +
>>  scripts/kconfig/zconf.l | 31 
>>  3 files changed, 89 insertions(+), 2 deletions(-)
>>
>> diff --git a/scripts/kconfig/function.c b/scripts/kconfig/function.c
>> index 913685f..389bb44 100644
>> --- a/scripts/kconfig/function.c
>> +++ b/scripts/kconfig/function.c
>> @@ -15,6 +15,7 @@ static LIST_HEAD(function_list);
>>  struct function {
>> char *name;
>> char *(*func)(struct function *f, int argc, char *argv[]);
>> +   char *macro;
>> struct list_head node;
>>  };
>>
>> @@ -31,7 +32,8 @@ static struct function *func_lookup(const char *name)
>>  }
>>
>>  static void func_add(const char *name,
>> -char *(*func)(struct function *f, int argc, char 
>> *argv[]))
>> +char *(*func)(struct function *f, int argc, char 
>> *argv[]),
>> +const char *macro)
>>  {
>> struct function *f;
>>
>> @@ -44,6 +46,7 @@ static void func_add(const char *name,
>> f = xmalloc(sizeof(*f));
>> f->name = xstrdup(name);
>> f->func = func;
>> +   f->macro = macro ? xstrdup(macro) : NULL;
>>
>> list_add_tail(&f->node, &function_list);
>>  }
>> @@ -51,6 +54,7 @@ static void func_add(const char *name,
>>  static void func_del(struct function *f)
>>  {
>> list_del(&f->node);
>> +   free(f->macro);
>> free(f->name);
>> free(f);
>>  }
>> @@ -108,6 +112,57 @@ char *func_eval_n(const char *func, size_t n)
>> return res;
>>  }
>>
>> +/* run user-defined function */
>> +static char *do_macro(struct function *f, int argc, char *argv[])
>> +{
>> +   char *new;
>> +   char *src, *p, *res;
>> +   size_t newlen;
>> +   int n;
>> +
>> +   new = xmalloc(1);
>> +   *new = 0;
>
> new = '\0' would be consistent with the rest of the code.
>
>> +
>> +   /*
>> +* This is a format string. $(1), $(2), ... must be replaced with
>> +* function arguments.
>> +*/
>> +   src = f->macro;
>> +   p = src;
>> +
>> +   while ((p = strstr(p, "$("))) {
>> +   if (isdigit(p[2]) && p[3] == ')') {
>> +   n = p[2] - '0';
>> +   if (n < argc) {
>> +   newlen = strlen(new) + (p - src) +
>> +   strlen(argv[n]) + 1;
>> +   new = xrealloc(new, newlen);
>> +   strncat(new, src, p - src);
>> +   strcat(new, argv[n]);
>> +   src = p + 4;
>> +   }
>
> Might be nice to warn when a macro call has m

Re: [PATCH v2 09/21] kconfig: add 'macro' keyword to support user-defined function

2018-03-31 Thread Ulf Magnusson
On Tue, Mar 27, 2018 at 7:29 AM, Masahiro Yamada
 wrote:
> Now, we got a basic ability to test compiler capability in Kconfig.
>
> config CC_HAS_STACKPROTECTOR
> def_bool $(shell (($CC -Werror -fstack-protector -c -x c /dev/null -o 
> /dev/null) && echo y) || echo n)
>
> This works, but it is ugly to repeat this long boilerplate.
>
> We want to describe like this:
>
> config CC_HAS_STACKPROTECTOR
> bool
> default $(cc-option -fstack-protector)
>
> It is straight-forward to add a new function, but I do not like to
> hard-code specialized functions like this.  Hence, here is another
> feature to add functions from Kconfig files.
>
> A user-defined function is defined with a special keyword 'macro'.
> It can be referenced in the same way as built-in functions.  This
> feature was also inspired by Makefile where user-defined functions
> are referenced by $(call func-name, args...), but I omitted the 'call'
> to makes it shorter.
>
> The macro definition can contain $(1), $(2), ... which will be replaced
> with arguments from the caller.  The macro works just as a textual
> shorthand, which is also expanded in the lexer phase.
>
> [Example Code]
>
>   macro success $(shell ($(1) && echo y) || echo n)
>
>   config TRUE
>   bool "true"
>   default $(success true)
>
>   config FALSE
>   bool "false"
>   default $(success false)
>
> [Result]
>
>   $ make -s alldefconfig
>   $ tail -n 2 .config
>   CONFIG_TRUE=y
>   # CONFIG_FALSE is not set
>
> [Example Code]
>
>   macro success $(shell ($(1) && echo y) || echo n)
>
>   macro cc-option $(success $CC -Werror $(1) -c -x c /dev/null -o /dev/null)
>
>   config CC_HAS_STACKPROTECTOR
>   def_bool $(cc-option -fstack-protector)
>
> [Result]
>   $ make -s alldefconfig
>   $ tail -n 1 .config
>   CONFIG_CC_HAS_STACKPROTECTOR=y
>
> Signed-off-by: Masahiro Yamada 
> ---
>
> Reminder for myself:
> Update Documentation/kbuild/kconfig-language.txt
>
> Changes in v2:
>   - Use 'macro' directly instead of inside the string type symbol.
>
>  scripts/kconfig/function.c  | 59 
> +++--
>  scripts/kconfig/lkc_proto.h |  1 +
>  scripts/kconfig/zconf.l | 31 
>  3 files changed, 89 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/kconfig/function.c b/scripts/kconfig/function.c
> index 913685f..389bb44 100644
> --- a/scripts/kconfig/function.c
> +++ b/scripts/kconfig/function.c
> @@ -15,6 +15,7 @@ static LIST_HEAD(function_list);
>  struct function {
> char *name;
> char *(*func)(struct function *f, int argc, char *argv[]);
> +   char *macro;
> struct list_head node;
>  };
>
> @@ -31,7 +32,8 @@ static struct function *func_lookup(const char *name)
>  }
>
>  static void func_add(const char *name,
> -char *(*func)(struct function *f, int argc, char 
> *argv[]))
> +char *(*func)(struct function *f, int argc, char 
> *argv[]),
> +const char *macro)
>  {
> struct function *f;
>
> @@ -44,6 +46,7 @@ static void func_add(const char *name,
> f = xmalloc(sizeof(*f));
> f->name = xstrdup(name);
> f->func = func;
> +   f->macro = macro ? xstrdup(macro) : NULL;
>
> list_add_tail(&f->node, &function_list);
>  }
> @@ -51,6 +54,7 @@ static void func_add(const char *name,
>  static void func_del(struct function *f)
>  {
> list_del(&f->node);
> +   free(f->macro);
> free(f->name);
> free(f);
>  }
> @@ -108,6 +112,57 @@ char *func_eval_n(const char *func, size_t n)
> return res;
>  }
>
> +/* run user-defined function */
> +static char *do_macro(struct function *f, int argc, char *argv[])
> +{
> +   char *new;
> +   char *src, *p, *res;
> +   size_t newlen;
> +   int n;
> +
> +   new = xmalloc(1);
> +   *new = 0;

new = '\0' would be consistent with the rest of the code.

> +
> +   /*
> +* This is a format string. $(1), $(2), ... must be replaced with
> +* function arguments.
> +*/
> +   src = f->macro;
> +   p = src;
> +
> +   while ((p = strstr(p, "$("))) {
> +   if (isdigit(p[2]) && p[3] == ')') {
> +   n = p[2] - '0';
> +   if (n < argc) {
> +   newlen = strlen(new) + (p - src) +
> +   strlen(argv[n]) + 1;
> +   new = xrealloc(new, newlen);
> +   strncat(new, src, p - src);
> +   strcat(new, argv[n]);
> +   src = p + 4;
> +   }

Might be nice to warn when a macro call has missing arguments.

> +   p += 2;
> +   }
> +   p += 2;
> +   }

I had to stare at this for a while to see how it worked. What do you
think of this tweak?

while ((p =

Re: [PATCH v2 09/21] kconfig: add 'macro' keyword to support user-defined function

2018-03-27 Thread Kees Cook
On Mon, Mar 26, 2018 at 10:29 PM, Masahiro Yamada
 wrote:
> Now, we got a basic ability to test compiler capability in Kconfig.
>
> config CC_HAS_STACKPROTECTOR
> def_bool $(shell (($CC -Werror -fstack-protector -c -x c /dev/null -o 
> /dev/null) && echo y) || echo n)
>
> This works, but it is ugly to repeat this long boilerplate.
>
> We want to describe like this:
>
> config CC_HAS_STACKPROTECTOR
> bool
> default $(cc-option -fstack-protector)
>
> It is straight-forward to add a new function, but I do not like to
> hard-code specialized functions like this.  Hence, here is another
> feature to add functions from Kconfig files.
>
> A user-defined function is defined with a special keyword 'macro'.
> It can be referenced in the same way as built-in functions.  This
> feature was also inspired by Makefile where user-defined functions
> are referenced by $(call func-name, args...), but I omitted the 'call'
> to makes it shorter.
>
> The macro definition can contain $(1), $(2), ... which will be replaced
> with arguments from the caller.  The macro works just as a textual
> shorthand, which is also expanded in the lexer phase.
>
> [Example Code]
>
>   macro success $(shell ($(1) && echo y) || echo n)
>
>   config TRUE
>   bool "true"
>   default $(success true)
>
>   config FALSE
>   bool "false"
>   default $(success false)
>
> [Result]
>
>   $ make -s alldefconfig
>   $ tail -n 2 .config
>   CONFIG_TRUE=y
>   # CONFIG_FALSE is not set
>
> [Example Code]
>
>   macro success $(shell ($(1) && echo y) || echo n)
>
>   macro cc-option $(success $CC -Werror $(1) -c -x c /dev/null -o /dev/null)
>
>   config CC_HAS_STACKPROTECTOR
>   def_bool $(cc-option -fstack-protector)
>
> [Result]
>   $ make -s alldefconfig
>   $ tail -n 1 .config
>   CONFIG_CC_HAS_STACKPROTECTOR=y
>
> Signed-off-by: Masahiro Yamada 

Cool, I like this "macro" idea for keeping this clean.

> ---
>
> Reminder for myself:
> Update Documentation/kbuild/kconfig-language.txt

Yes please. :)

Otherwise, looks good!

-Kees

-- 
Kees Cook
Pixel Security


[PATCH v2 09/21] kconfig: add 'macro' keyword to support user-defined function

2018-03-26 Thread Masahiro Yamada
Now, we got a basic ability to test compiler capability in Kconfig.

config CC_HAS_STACKPROTECTOR
def_bool $(shell (($CC -Werror -fstack-protector -c -x c /dev/null -o 
/dev/null) && echo y) || echo n)

This works, but it is ugly to repeat this long boilerplate.

We want to describe like this:

config CC_HAS_STACKPROTECTOR
bool
default $(cc-option -fstack-protector)

It is straight-forward to add a new function, but I do not like to
hard-code specialized functions like this.  Hence, here is another
feature to add functions from Kconfig files.

A user-defined function is defined with a special keyword 'macro'.
It can be referenced in the same way as built-in functions.  This
feature was also inspired by Makefile where user-defined functions
are referenced by $(call func-name, args...), but I omitted the 'call'
to makes it shorter.

The macro definition can contain $(1), $(2), ... which will be replaced
with arguments from the caller.  The macro works just as a textual
shorthand, which is also expanded in the lexer phase.

[Example Code]

  macro success $(shell ($(1) && echo y) || echo n)

  config TRUE
  bool "true"
  default $(success true)

  config FALSE
  bool "false"
  default $(success false)

[Result]

  $ make -s alldefconfig
  $ tail -n 2 .config
  CONFIG_TRUE=y
  # CONFIG_FALSE is not set

[Example Code]

  macro success $(shell ($(1) && echo y) || echo n)

  macro cc-option $(success $CC -Werror $(1) -c -x c /dev/null -o /dev/null)

  config CC_HAS_STACKPROTECTOR
  def_bool $(cc-option -fstack-protector)

[Result]
  $ make -s alldefconfig
  $ tail -n 1 .config
  CONFIG_CC_HAS_STACKPROTECTOR=y

Signed-off-by: Masahiro Yamada 
---

Reminder for myself:
Update Documentation/kbuild/kconfig-language.txt

Changes in v2:
  - Use 'macro' directly instead of inside the string type symbol.

 scripts/kconfig/function.c  | 59 +++--
 scripts/kconfig/lkc_proto.h |  1 +
 scripts/kconfig/zconf.l | 31 
 3 files changed, 89 insertions(+), 2 deletions(-)

diff --git a/scripts/kconfig/function.c b/scripts/kconfig/function.c
index 913685f..389bb44 100644
--- a/scripts/kconfig/function.c
+++ b/scripts/kconfig/function.c
@@ -15,6 +15,7 @@ static LIST_HEAD(function_list);
 struct function {
char *name;
char *(*func)(struct function *f, int argc, char *argv[]);
+   char *macro;
struct list_head node;
 };
 
@@ -31,7 +32,8 @@ static struct function *func_lookup(const char *name)
 }
 
 static void func_add(const char *name,
-char *(*func)(struct function *f, int argc, char *argv[]))
+char *(*func)(struct function *f, int argc, char *argv[]),
+const char *macro)
 {
struct function *f;
 
@@ -44,6 +46,7 @@ static void func_add(const char *name,
f = xmalloc(sizeof(*f));
f->name = xstrdup(name);
f->func = func;
+   f->macro = macro ? xstrdup(macro) : NULL;
 
list_add_tail(&f->node, &function_list);
 }
@@ -51,6 +54,7 @@ static void func_add(const char *name,
 static void func_del(struct function *f)
 {
list_del(&f->node);
+   free(f->macro);
free(f->name);
free(f);
 }
@@ -108,6 +112,57 @@ char *func_eval_n(const char *func, size_t n)
return res;
 }
 
+/* run user-defined function */
+static char *do_macro(struct function *f, int argc, char *argv[])
+{
+   char *new;
+   char *src, *p, *res;
+   size_t newlen;
+   int n;
+
+   new = xmalloc(1);
+   *new = 0;
+
+   /*
+* This is a format string. $(1), $(2), ... must be replaced with
+* function arguments.
+*/
+   src = f->macro;
+   p = src;
+
+   while ((p = strstr(p, "$("))) {
+   if (isdigit(p[2]) && p[3] == ')') {
+   n = p[2] - '0';
+   if (n < argc) {
+   newlen = strlen(new) + (p - src) +
+   strlen(argv[n]) + 1;
+   new = xrealloc(new, newlen);
+   strncat(new, src, p - src);
+   strcat(new, argv[n]);
+   src = p + 4;
+   }
+   p += 2;
+   }
+   p += 2;
+   }
+
+   newlen = strlen(new) + strlen(src) + 1;
+   new = xrealloc(new, newlen);
+   strcat(new, src);
+
+   res = expand_string_value(new);
+
+   free(new);
+
+   return res;
+}
+
+/* add user-defined function (macro) */
+void func_add_macro(const char *name, const char *macro)
+{
+   func_add(name, do_macro, macro);
+}
+
 /* built-in functions */
 static char *do_shell(struct function *f, int argc, char *argv[])
 {
@@ -157,7 +212,7 @@ static char *do_shell(struct function *f, int argc, char 
*argv[])
 void func_init(void)
 {