Re: [PATCH v2 09/21] kconfig: add 'macro' keyword to support user-defined function
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
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
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
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
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) {