[RFC PATCH 1/2] Kconfig: Introduce "uses" keyword

From: Saeed Mahameed
Date: Thu Apr 16 2020 - 21:13:07 EST


Due to the changes to the semantics of imply keyword [1], which now
doesn't force any config options to the implied configs any more.

A module (FOO) that has a weak dependency on some other modules (BAR)
is now broken if it was using imply to force dependency restrictions.
e.g.: FOO needs BAR to be reachable, especially when FOO=y and BAR=m.
Which might now introduce build/link errors.

There are two options to solve this:
1. use IS_REACHABLE(BAR), everywhere BAR is referenced inside FOO.
2. in FOO's Kconfig add: depends on (BAR || !BAR)

The first option is not desirable, and will leave the user confused when
setting FOO=y and BAR=m, FOO will never reach BAR even though both are
compiled.

The 2nd one is the preferred approach, and will guarantee BAR is always
reachable by FOO if both are compiled. But, (BAR || !BAR) is really
confusing for those who don't really get how kconfig tristate arithmetics
work.

To solve this and hide this weird expression and to avoid repetition
across the tree, we introduce new keyword "uses" to the Kconfig options
family.

uses BAR:
Equivalent to: depends on symbol || !symbol
Semantically it means, if FOO is enabled (y/m) and has the option:
uses BAR, make sure it can reach/use BAR when possible.

For example: if FOO=y and BAR=m, FOO will be forced to m.

[1] https://lore.kernel.org/linux-doc/20200302062340.21453-1-masahiroy@xxxxxxxxxx/

Link: https://lkml.org/lkml/2020/4/8/839
Signed-off-by: Saeed Mahameed <saeedm@xxxxxxxxxxxx>
Cc: Masahiro Yamada <masahiroy@xxxxxxxxxx>
Cc: linux-kbuild@xxxxxxxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
Documentation/kbuild/kconfig-language.rst | 10 ++++++++++
scripts/kconfig/expr.h | 1 +
scripts/kconfig/lexer.l | 1 +
scripts/kconfig/menu.c | 4 +++-
scripts/kconfig/parser.y | 15 +++++++++++++++
scripts/kconfig/symbol.c | 2 ++
6 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/Documentation/kbuild/kconfig-language.rst b/Documentation/kbuild/kconfig-language.rst
index a1601ec3317b..8db8c2d80794 100644
--- a/Documentation/kbuild/kconfig-language.rst
+++ b/Documentation/kbuild/kconfig-language.rst
@@ -130,6 +130,16 @@ applicable everywhere (see syntax).
bool "foo"
default y

+- uses dependencies: "uses" <symbol>
+
+ Equivalent to: depends on symbol || !symbol
+ Semantically it means, if FOO is enabled (y/m) and has the option:
+ uses BAR, make sure it can reach/use BAR when possible.
+ For example: if FOO=y and BAR=m, FOO will be forced to m.
+
+ Note:
+ To understand how (symbol || !symbol) is actually computed, please see `Menu dependencies`_
+
- reverse dependencies: "select" <symbol> ["if" <expr>]

While normal dependencies reduce the upper limit of a symbol (see
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 5c3443692f34..face672fb4b4 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -185,6 +185,7 @@ enum prop_type {
P_CHOICE, /* choice value */
P_SELECT, /* select BAR */
P_IMPLY, /* imply BAR */
+ P_USES, /* uses BAR */
P_RANGE, /* range 7..100 (for a symbol) */
P_SYMBOL, /* where a symbol is defined */
};
diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l
index 6354c905b006..c6a0017b10d4 100644
--- a/scripts/kconfig/lexer.l
+++ b/scripts/kconfig/lexer.l
@@ -102,6 +102,7 @@ n [A-Za-z0-9_-]
"default" return T_DEFAULT;
"defconfig_list" return T_DEFCONFIG_LIST;
"depends" return T_DEPENDS;
+"uses" return T_USES;
"endchoice" return T_ENDCHOICE;
"endif" return T_ENDIF;
"endmenu" return T_ENDMENU;
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index e436ba44c9c5..e26161b31a11 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -274,7 +274,9 @@ static void sym_check_prop(struct symbol *sym)
break;
case P_SELECT:
case P_IMPLY:
- use = prop->type == P_SELECT ? "select" : "imply";
+ case P_USES:
+ use = prop->type == P_SELECT ? "select" :
+ prop->type == P_IMPLY ? "imply" : "uses";
sym2 = prop_get_symbol(prop);
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
prop_warn(prop,
diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
index 708b6c4b13ca..c5e9abb49d29 100644
--- a/scripts/kconfig/parser.y
+++ b/scripts/kconfig/parser.y
@@ -57,6 +57,7 @@ static struct menu *current_menu, *current_entry;
%token T_DEF_BOOL
%token T_DEF_TRISTATE
%token T_DEPENDS
+%token T_USES
%token T_ENDCHOICE
%token T_ENDIF
%token T_ENDMENU
@@ -169,6 +170,7 @@ config_option_list:
/* empty */
| config_option_list config_option
| config_option_list depends
+ | config_option_list uses
| config_option_list help
;

@@ -261,6 +263,7 @@ choice_option_list:
/* empty */
| choice_option_list choice_option
| choice_option_list depends
+ | choice_option_list uses
| choice_option_list help
;

@@ -360,6 +363,7 @@ menu_option_list:
/* empty */
| menu_option_list visible
| menu_option_list depends
+ | menu_option_list uses
;

source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
@@ -384,6 +388,7 @@ comment_stmt: comment comment_option_list
comment_option_list:
/* empty */
| comment_option_list depends
+ | comment_option_list uses
;

/* help option */
@@ -418,6 +423,16 @@ depends: T_DEPENDS T_ON expr T_EOL
printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
};

+/* uses symbol: depends on symbol || !symbol */
+uses: T_USES symbol T_EOL
+{
+ struct expr *symexpr = expr_alloc_symbol($2);
+
+ menu_add_dep(expr_alloc_two(E_OR, symexpr, expr_alloc_one(E_NOT, symexpr)));
+ printd(DEBUG_PARSE, "%s:%d: uses: depends on %s || ! %s\n",
+ zconf_curname(), zconf_lineno(), $2->name, $2->name);
+};
+
/* visibility option */
visible: T_VISIBLE if_expr T_EOL
{
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 3dc81397d003..422f7ea47722 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -1295,6 +1295,8 @@ const char *prop_get_type_name(enum prop_type type)
return "choice";
case P_SELECT:
return "select";
+ case P_USES:
+ return "uses";
case P_IMPLY:
return "imply";
case P_RANGE:
--
2.25.2