summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2026-02-27 08:57:48 -0600
committerTom Rini <trini@konsulko.com>2026-02-27 12:27:39 -0600
commitae3abb9ee4f475023254711becc2eeacfe631925 (patch)
treee34d61b00e82afcd784de5dfe46f02709c52318a
parent1ecb19c7b4b57f7c3b358e419b8d202ae84d3d3e (diff)
resync with 4.19
Signed-off-by: Tom Rini <trini@konsulko.com>
-rw-r--r--scripts/kconfig/Makefile18
-rw-r--r--scripts/kconfig/conf.c38
-rw-r--r--scripts/kconfig/confdata.c31
-rw-r--r--scripts/kconfig/expr.c2
-rw-r--r--scripts/kconfig/gconf.c41
-rw-r--r--scripts/kconfig/list.h4
-rw-r--r--scripts/kconfig/lkc.h1
-rw-r--r--scripts/kconfig/lkc_proto.h2
-rw-r--r--scripts/kconfig/lxdialog/checklist.c15
-rw-r--r--scripts/kconfig/lxdialog/dialog.h16
-rw-r--r--scripts/kconfig/lxdialog/inputbox.c15
-rw-r--r--scripts/kconfig/lxdialog/menubox.c15
-rw-r--r--scripts/kconfig/lxdialog/textbox.c16
-rw-r--r--scripts/kconfig/lxdialog/util.c15
-rw-r--r--scripts/kconfig/lxdialog/yesno.c15
-rw-r--r--scripts/kconfig/mconf.c1
-rw-r--r--scripts/kconfig/menu.c1
-rwxr-xr-xscripts/kconfig/merge_config.sh11
-rw-r--r--scripts/kconfig/nconf.c3
-rw-r--r--scripts/kconfig/nconf.gui.c5
-rw-r--r--scripts/kconfig/qconf.cc2
-rw-r--r--scripts/kconfig/symbol.c2
-rw-r--r--scripts/kconfig/tests/err_recursive_dep/expected_stderr14
-rw-r--r--scripts/kconfig/tests/preprocess/builtin_func/Kconfig27
-rw-r--r--scripts/kconfig/tests/preprocess/builtin_func/__init__.py9
-rw-r--r--scripts/kconfig/tests/preprocess/builtin_func/expected_stderr5
-rw-r--r--scripts/kconfig/tests/preprocess/builtin_func/expected_stdout1
-rw-r--r--scripts/kconfig/tests/preprocess/circular_expansion/Kconfig5
-rw-r--r--scripts/kconfig/tests/preprocess/circular_expansion/__init__.py11
-rw-r--r--scripts/kconfig/tests/preprocess/circular_expansion/expected_stderr1
-rw-r--r--scripts/kconfig/tests/preprocess/escape/Kconfig44
-rw-r--r--scripts/kconfig/tests/preprocess/escape/__init__.py8
-rw-r--r--scripts/kconfig/tests/preprocess/escape/expected_stderr10
-rw-r--r--scripts/kconfig/tests/preprocess/variable/Kconfig53
-rw-r--r--scripts/kconfig/tests/preprocess/variable/__init__.py8
-rw-r--r--scripts/kconfig/tests/preprocess/variable/expected_stderr9
36 files changed, 418 insertions, 56 deletions
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index abc34f60d15..4be95c7ac57 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -50,7 +50,7 @@ build_xconfig: $(obj)/qconf
localyesconfig localmodconfig: $(obj)/conf
$(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
- $(Q)if [ -f .config ]; then \
+ $(Q)if [ -f .config ]; then \
cmp -s .tmp.config .config || \
(mv -f .config .config.old.1; \
mv -f .tmp.config .config; \
@@ -74,7 +74,21 @@ PHONY += $(simple-targets)
$(simple-targets): $(obj)/conf
$< $(silent) --$@ $(Kconfig)
-PHONY += savedefconfig defconfig
+PHONY += oldnoconfig silentoldconfig savedefconfig defconfig
+
+# oldnoconfig is an alias of olddefconfig, because people already are dependent
+# on its behavior (sets new symbols to their default value but not 'n') with the
+# counter-intuitive name.
+oldnoconfig: olddefconfig
+ @echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
+ @echo " Please use \"olddefconfig\" instead, which is an alias."
+
+# We do not expect manual invokcation of "silentoldcofig" (or "syncconfig").
+silentoldconfig: syncconfig
+ @echo " WARNING: \"silentoldconfig\" has been renamed to \"syncconfig\""
+ @echo " and is now an internal implementation detail."
+ @echo " What you want is probably \"oldconfig\"."
+ @echo " \"silentoldconfig\" will be removed after Linux 4.19"
savedefconfig: $(obj)/conf
$< $(silent) --$@=defconfig $(Kconfig)
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 376f796f674..7b2b3726066 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -460,6 +460,12 @@ static struct option long_opts[] = {
{"randconfig", no_argument, NULL, randconfig},
{"listnewconfig", no_argument, NULL, listnewconfig},
{"olddefconfig", no_argument, NULL, olddefconfig},
+ /*
+ * oldnoconfig is an alias of olddefconfig, because people already
+ * are dependent on its behavior(sets new symbols to their default
+ * value but not 'n') with the counter-intuitive name.
+ */
+ {"oldnoconfig", no_argument, NULL, olddefconfig},
{NULL, 0, NULL, 0}
};
@@ -474,6 +480,7 @@ static void conf_usage(const char *progname)
printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
" include/{generated/,config/}\n");
printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
+ printf(" --oldnoconfig An alias of olddefconfig\n");
printf(" --defconfig <file> New config with default defined in <file>\n");
printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
printf(" --allnoconfig New config where all options are answered with no\n");
@@ -684,29 +691,32 @@ int main(int ac, char **av)
break;
}
- if (sync_kconfig) {
- /* syncconfig is used during the build so we shall update autoconf.
- * All other commands are only used to generate a config.
- */
- if (!no_conf_write && conf_write(NULL)) {
- fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
- exit(1);
- }
- if (conf_write_autoconf()) {
- fprintf(stderr, "\n*** Error during update of the configuration.\n\n");
- return 1;
- }
- } else if (input_mode == savedefconfig) {
+ if (input_mode == savedefconfig) {
if (conf_write_defconfig(defconfig_file)) {
fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
defconfig_file);
return 1;
}
} else if (input_mode != listnewconfig) {
- if (conf_write(NULL)) {
+ if (!no_conf_write && conf_write(NULL)) {
fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
exit(1);
}
+
+ /*
+ * Create auto.conf if it does not exist.
+ * This prevents GNU Make 4.1 or older from emitting
+ * "include/config/auto.conf: No such file or directory"
+ * in the top-level Makefile
+ *
+ * syncconfig always creates or updates auto.conf because it is
+ * used during the build.
+ */
+ if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
+ fprintf(stderr,
+ "\n*** Error during sync of the configuration.\n\n");
+ return 1;
+ }
}
return 0;
}
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index d587b10d7f8..91d0a5c014a 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -197,14 +197,18 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
case S_STRING:
if (*p++ != '"')
break;
- /* Last char has to be a '"' */
- if (p[strlen(p) - 1] != '"') {
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
if (def != S_DEF_AUTO)
conf_warning("invalid string found");
return 1;
}
- /* Overwrite '"' with \0 for string termination */
- p[strlen(p) - 1] = 0;
/* fall through */
case S_INT:
case S_HEX:
@@ -663,7 +667,6 @@ static void conf_write_symbol(FILE *fp, struct symbol *sym,
struct conf_printer *printer, void *printer_arg)
{
const char *str;
- char *str2;
switch (sym->type) {
case S_OTHER:
@@ -671,10 +674,9 @@ static void conf_write_symbol(FILE *fp, struct symbol *sym,
break;
case S_STRING:
str = sym_get_string_value(sym);
- str2 = xmalloc(strlen(str) + 3);
- sprintf(str2, "\"%s\"", str);
- printer->print_symbol(fp, sym, str2, printer_arg);
- free((void *)str2);
+ str = sym_escape_string_value(str);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ free((void *)str);
break;
default:
str = sym_get_string_value(sym);
@@ -1011,13 +1013,17 @@ out:
return res;
}
-int conf_write_autoconf(void)
+int conf_write_autoconf(int overwrite)
{
struct symbol *sym;
const char *name;
+ const char *autoconf_name = conf_get_autoconfig_name();
FILE *out, *tristate, *out_h;
int i;
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
+
sym_clear_all_valid();
conf_write_dep("include/config/auto.conf.cmd");
@@ -1080,14 +1086,13 @@ int conf_write_autoconf(void)
if (rename(".tmpconfig_tristate", name))
return 1;
- name = conf_get_autoconfig_name();
- if (make_parent_dir(name))
+ if (make_parent_dir(autoconf_name))
return 1;
/*
* This must be the last step, kbuild has a dependency on auto.conf
* and this marks the successful completion of the previous steps.
*/
- if (rename(".tmpconfig", name))
+ if (rename(".tmpconfig", autoconf_name))
return 1;
return 0;
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index 9f79bdfaaa5..e1a39e90841 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -894,7 +894,7 @@ bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
default:
;
}
- return false;
+ return false;
}
/*
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index aee993a778f..36f578415c4 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -360,8 +360,10 @@ void init_right_tree(void)
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
}
+
/* Utility Functions */
+
static void text_insert_help(struct menu *menu)
{
GtkTextBuffer *buffer;
@@ -386,6 +388,7 @@ static void text_insert_help(struct menu *menu)
str_free(&help);
}
+
static void text_insert_msg(const char *title, const char *message)
{
GtkTextBuffer *buffer;
@@ -406,6 +409,7 @@ static void text_insert_msg(const char *title, const char *message)
NULL);
}
+
/* Main Windows Callbacks */
void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
@@ -453,11 +457,13 @@ gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
return FALSE;
}
+
void on_window1_destroy(GtkObject * object, gpointer user_data)
{
gtk_main_quit();
}
+
void
on_window1_size_request(GtkWidget * widget,
GtkRequisition * requisition, gpointer user_data)
@@ -477,8 +483,10 @@ on_window1_size_request(GtkWidget * widget,
gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
}
+
/* Menu & Toolbar Callbacks */
+
static void
load_filename(GtkFileSelection * file_selector, gpointer user_data)
{
@@ -512,12 +520,15 @@ void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
gtk_widget_show(fs);
}
+
void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
{
if (conf_write(NULL))
text_insert_msg("Error", "Unable to save configuration !");
+ conf_write_autoconf(0);
}
+
static void
store_filename(GtkFileSelection * file_selector, gpointer user_data)
{
@@ -551,12 +562,14 @@ void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
gtk_widget_show(fs);
}
+
void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
if (!on_window1_delete_event(NULL, NULL, NULL))
gtk_widget_destroy(GTK_WIDGET(main_wnd));
}
+
void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkTreeViewColumn *col;
@@ -567,6 +580,7 @@ void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
gtk_tree_view_column_set_visible(col, show_name);
}
+
void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkTreeViewColumn *col;
@@ -584,6 +598,7 @@ void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
}
+
void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkTreeViewColumn *col;
@@ -594,6 +609,7 @@ void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
gtk_tree_view_column_set_visible(col, show_value);
}
+
void
on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
{
@@ -602,6 +618,7 @@ on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
display_tree(&rootmenu); /* instead of update_tree to speed-up */
}
+
void
on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
{
@@ -610,6 +627,7 @@ on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
display_tree(&rootmenu); /* instead of update_tree to speed-up */
}
+
void
on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
{
@@ -618,10 +636,11 @@ on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
display_tree(&rootmenu); /* instead of update_tree to speed-up */
}
+
void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkWidget *dialog;
- const gchar *intro_text =
+ const gchar *intro_text =
"Welcome to gkc, the GTK+ graphical configuration tool\n"
"For each option, a blank box indicates the feature is disabled, a\n"
"check indicates it is enabled, and a dot indicates that it is to\n"
@@ -648,6 +667,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
gtk_widget_show_all(dialog);
}
+
void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkWidget *dialog;
@@ -665,6 +685,7 @@ void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
gtk_widget_show_all(dialog);
}
+
void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkWidget *dialog;
@@ -683,6 +704,7 @@ void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
gtk_widget_show_all(dialog);
}
+
void on_back_clicked(GtkButton * button, gpointer user_data)
{
enum prop_type ptype;
@@ -697,11 +719,13 @@ void on_back_clicked(GtkButton * button, gpointer user_data)
gtk_widget_set_sensitive(back_btn, FALSE);
}
+
void on_load_clicked(GtkButton * button, gpointer user_data)
{
on_load1_activate(NULL, user_data);
}
+
void on_single_clicked(GtkButton * button, gpointer user_data)
{
view_mode = SINGLE_VIEW;
@@ -710,6 +734,7 @@ void on_single_clicked(GtkButton * button, gpointer user_data)
display_tree_part();
}
+
void on_split_clicked(GtkButton * button, gpointer user_data)
{
gint w, h;
@@ -725,6 +750,7 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
gtk_widget_set_sensitive(back_btn, FALSE);
}
+
void on_full_clicked(GtkButton * button, gpointer user_data)
{
view_mode = FULL_VIEW;
@@ -735,16 +761,19 @@ void on_full_clicked(GtkButton * button, gpointer user_data)
gtk_widget_set_sensitive(back_btn, FALSE);
}
+
void on_collapse_clicked(GtkButton * button, gpointer user_data)
{
gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
}
+
void on_expand_clicked(GtkButton * button, gpointer user_data)
{
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
}
+
/* CTree Callbacks */
/* Change hex/int/string value in the cell */
@@ -846,6 +875,7 @@ static gint column2index(GtkTreeViewColumn * column)
return -1;
}
+
/* User click: update choice (full) or goes down (single) */
gboolean
on_treeview2_button_press_event(GtkWidget * widget,
@@ -947,6 +977,7 @@ on_treeview2_key_press_event(GtkWidget * widget,
return FALSE;
}
+
/* Row selection changed: update help */
void
on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
@@ -962,6 +993,7 @@ on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
}
}
+
/* User click: display sub-tree in the right frame. */
gboolean
on_treeview1_button_press_event(GtkWidget * widget,
@@ -1001,6 +1033,7 @@ on_treeview1_button_press_event(GtkWidget * widget,
return FALSE;
}
+
/* Fill a row of strings */
static gchar **fill_row(struct menu *menu)
{
@@ -1125,6 +1158,7 @@ static gchar **fill_row(struct menu *menu)
return row;
}
+
/* Set the node content with a row of strings */
static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
{
@@ -1160,6 +1194,7 @@ static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
g_object_unref(pix);
}
+
/* Add a node to the tree */
static void place_node(struct menu *menu, char **row)
{
@@ -1170,6 +1205,7 @@ static void place_node(struct menu *menu, char **row)
set_node(node, menu, row);
}
+
/* Find a node in the GTK+ tree */
static GtkTreeIter found;
@@ -1205,6 +1241,7 @@ GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
return NULL;
}
+
/*
* Update the tree by adding/removing entries
* Does not change other nodes
@@ -1293,6 +1330,7 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
}
}
+
/* Display the whole tree (single/split/full view) */
static void display_tree(struct menu *menu)
{
@@ -1402,6 +1440,7 @@ void fixup_rootmenu(struct menu *menu)
}
}
+
/* Main */
int main(int ac, char *av[])
{
diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h
index 9f1d16a43c2..45cb237ab7e 100644
--- a/scripts/kconfig/list.h
+++ b/scripts/kconfig/list.h
@@ -20,10 +20,12 @@
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
+
struct list_head {
struct list_head *next, *prev;
};
+
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
@@ -46,7 +48,7 @@ struct list_head {
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
+ &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 2daf47f57cc..9eb7c837cd8 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -131,6 +131,7 @@ static inline tristate sym_get_tristate_value(struct symbol *sym)
return sym->curr.tri;
}
+
static inline struct symbol *sym_get_choice_value(struct symbol *sym)
{
return (struct symbol *)sym->curr.val;
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index cf4510a2bdc..86c267540cc 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -7,7 +7,7 @@ int conf_read(const char *name);
int conf_read_simple(const char *name, int);
int conf_write_defconfig(const char *name);
int conf_write(const char *name);
-int conf_write_autoconf(void);
+int conf_write_autoconf(int overwrite);
bool conf_get_changed(void);
void conf_set_changed_callback(void (*fn)(void));
void conf_set_message_callback(void (*fn)(const char *s));
diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c
index fd161cfff12..2e96323ad11 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -1,4 +1,3 @@
-// SPDX-License-Identifier: GPL-2.0+
/*
* checklist.c -- implements the checklist box
*
@@ -6,6 +5,20 @@
* Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
* Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index 7675c4702ac..0b00be5abaa 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -1,8 +1,21 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
/*
* dialog.h -- common declarations for all dialog modules
*
* AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/types.h>
@@ -213,6 +226,7 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width);
int dialog_msgbox(const char *title, const char *prompt, int height,
int width, int pause);
+
typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
*_data);
int dialog_textbox(const char *title, char *tbuf, int initial_height,
diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c
index 611945611bf..fe82ff6d744 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -1,9 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0+
/*
* inputbox.c -- implements the input box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c
index 58c2f8afe59..d70cab36137 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -1,9 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0+
/*
* menubox.c -- implements the menu box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
index 12e68c0fb64..88d2818ed95 100644
--- a/scripts/kconfig/lxdialog/textbox.c
+++ b/scripts/kconfig/lxdialog/textbox.c
@@ -1,9 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0+
/*
* textbox.c -- implements the text box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
@@ -33,6 +46,7 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
wrefresh(dialog);
}
+
/*
* Display text from a file in a dialog box.
*
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index 1b490d4af0d..f7abdeb92af 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -1,9 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0+
/*
* util.c
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdarg.h>
diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c
index bcaac9b7bab..cd1223c903d 100644
--- a/scripts/kconfig/lxdialog/yesno.c
+++ b/scripts/kconfig/lxdialog/yesno.c
@@ -1,9 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0+
/*
* yesno.c -- implements the yes/no box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index c1b38747c14..143c05fec16 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -973,6 +973,7 @@ static int handle_exit(void)
"\n\n");
return 1;
}
+ conf_write_autoconf(0);
/* fall through */
case -1:
if (!silent)
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 0fe7f3255af..4cf15d449c0 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -853,6 +853,7 @@ struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
return res;
}
+
void menu_get_ext_help(struct menu *menu, struct gstr *help)
{
struct symbol *sym = menu->sym;
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 0ef90649964..67d13144763 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -33,15 +33,12 @@ usage() {
echo " -n use allnoconfig instead of alldefconfig"
echo " -r list redundant entries when merging fragments"
echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead."
- echo
- echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable."
}
RUNMAKE=true
ALLTARGET=alldefconfig
WARNREDUN=false
OUTPUT=.
-CONFIG_PREFIX=${CONFIG_-CONFIG_}
while true; do
case $1 in
@@ -102,9 +99,7 @@ if [ ! -r "$INITFILE" ]; then
fi
MERGE_LIST=$*
-SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p"
-SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p"
-
+SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
echo "Using $INITFILE as base"
@@ -117,7 +112,7 @@ for MERGE_FILE in $MERGE_LIST ; do
echo "The merge file '$MERGE_FILE' does not exist. Exit." >&2
exit 1
fi
- CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE)
+ CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE)
for CFG in $CFG_LIST ; do
grep -q -w $CFG $TMP_FILE || continue
@@ -160,7 +155,7 @@ make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
# Check all specified config values took (might have missed-dependency issues)
-for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do
+for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG")
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index ca878212f0a..1ef232ae5ab 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -674,6 +674,7 @@ static int do_exit(void)
"Your configuration changes were NOT saved.",
1,
"<OK>");
+ conf_write_autoconf(0);
break;
default:
btn_dialog(
@@ -687,6 +688,7 @@ static int do_exit(void)
return 0;
}
+
static void search_conf(void)
{
struct symbol **sym_arr;
@@ -730,6 +732,7 @@ again:
str_free(&title);
}
+
static void build_conf(struct menu *menu)
{
struct symbol *sym;
diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c
index 2a3b853e7ea..88874acfda3 100644
--- a/scripts/kconfig/nconf.gui.c
+++ b/scripts/kconfig/nconf.gui.c
@@ -143,6 +143,7 @@ void set_colors(void)
}
}
+
/* this changes the windows attributes !!! */
void print_in_middle(WINDOW *win,
int starty,
@@ -153,6 +154,7 @@ void print_in_middle(WINDOW *win,
{ int length, x, y;
float temp;
+
if (win == NULL)
win = stdscr;
getyx(win, y, x);
@@ -254,6 +256,7 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
int i, x, y;
int res = -1;
+
va_start(ap, btn_num);
for (i = 0; i < btn_num; i++) {
btn = va_arg(ap, char *);
@@ -277,6 +280,7 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
y = (getmaxy(stdscr)-(msg_lines+4))/2;
x = (getmaxx(stdscr)-(total_width+4))/2;
+
/* create the windows */
if (btn_num > 0)
win_rows = msg_lines+4;
@@ -311,6 +315,7 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
set_menu_mark(menu, "");
post_menu(menu);
+
touchwin(win);
refresh_all_windows(main_window);
while ((res = wgetch(win))) {
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 0c3fa940568..ef4310f2558 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -1534,6 +1534,8 @@ bool ConfigMainWindow::saveConfig(void)
QMessageBox::information(this, "qconf", "Unable to save configuration!");
return false;
}
+ conf_write_autoconf(0);
+
return true;
}
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 5245804bb33..703b9b899ee 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -1117,7 +1117,7 @@ static void sym_check_print_recursive(struct symbol *last_sym)
}
fprintf(stderr,
- "For a resolution refer to Documentation/kbuild/kconfig-language.rst\n"
+ "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n"
"subsection \"Kconfig recursive dependency limitations\"\n"
"\n");
diff --git a/scripts/kconfig/tests/err_recursive_dep/expected_stderr b/scripts/kconfig/tests/err_recursive_dep/expected_stderr
index c9f4abf9a79..84679b10465 100644
--- a/scripts/kconfig/tests/err_recursive_dep/expected_stderr
+++ b/scripts/kconfig/tests/err_recursive_dep/expected_stderr
@@ -1,38 +1,38 @@
Kconfig:11:error: recursive dependency detected!
Kconfig:11: symbol B is selected by B
-For a resolution refer to Documentation/kbuild/kconfig-language.rst
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:5:error: recursive dependency detected!
Kconfig:5: symbol A depends on A
-For a resolution refer to Documentation/kbuild/kconfig-language.rst
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:17:error: recursive dependency detected!
Kconfig:17: symbol C1 depends on C2
Kconfig:21: symbol C2 depends on C1
-For a resolution refer to Documentation/kbuild/kconfig-language.rst
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:32:error: recursive dependency detected!
Kconfig:32: symbol D2 is selected by D1
Kconfig:27: symbol D1 depends on D2
-For a resolution refer to Documentation/kbuild/kconfig-language.rst
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:37:error: recursive dependency detected!
Kconfig:37: symbol E1 depends on E2
Kconfig:42: symbol E2 is implied by E1
-For a resolution refer to Documentation/kbuild/kconfig-language.rst
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:60:error: recursive dependency detected!
Kconfig:60: symbol G depends on G
-For a resolution refer to Documentation/kbuild/kconfig-language.rst
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
Kconfig:51:error: recursive dependency detected!
Kconfig:51: symbol F2 depends on F1
Kconfig:49: symbol F1 default value contains F2
-For a resolution refer to Documentation/kbuild/kconfig-language.rst
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"
diff --git a/scripts/kconfig/tests/preprocess/builtin_func/Kconfig b/scripts/kconfig/tests/preprocess/builtin_func/Kconfig
new file mode 100644
index 00000000000..baa32882791
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/builtin_func/Kconfig
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# 'info' prints the argument to stdout.
+$(info,hello world 0)
+
+# 'warning-if', if the first argument is y, sends the second argument to stderr,
+# and the message is prefixed with the current file name and line number.
+$(warning-if,y,hello world 1)
+
+# 'error-if' is similar, but it terminates the parsing immediately.
+# The following is just no-op since the first argument is not y.
+$(error-if,n,this should not be printed)
+
+# Shorthand
+warning = $(warning-if,y,$(1))
+
+# 'shell' executes a command, and returns its stdout.
+$(warning,$(shell,echo hello world 3))
+
+# Every newline in the output is replaced with a space,
+# but any trailing newlines are deleted.
+$(warning,$(shell,printf 'hello\nworld\n\n4\n\n\n'))
+
+# 'filename' is expanded to the currently parsed file name,
+# 'lineno' to the line number.
+$(warning,filename=$(filename))
+$(warning,lineno=$(lineno))
diff --git a/scripts/kconfig/tests/preprocess/builtin_func/__init__.py b/scripts/kconfig/tests/preprocess/builtin_func/__init__.py
new file mode 100644
index 00000000000..2e53ba08fca
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/builtin_func/__init__.py
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Built-in function tests.
+"""
+
+def test(conf):
+ assert conf.oldaskconfig() == 0
+ assert conf.stdout_contains('expected_stdout')
+ assert conf.stderr_matches('expected_stderr')
diff --git a/scripts/kconfig/tests/preprocess/builtin_func/expected_stderr b/scripts/kconfig/tests/preprocess/builtin_func/expected_stderr
new file mode 100644
index 00000000000..33ea9ca3840
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/builtin_func/expected_stderr
@@ -0,0 +1,5 @@
+Kconfig:8: hello world 1
+Kconfig:18: hello world 3
+Kconfig:22: hello world 4
+Kconfig:26: filename=Kconfig
+Kconfig:27: lineno=27
diff --git a/scripts/kconfig/tests/preprocess/builtin_func/expected_stdout b/scripts/kconfig/tests/preprocess/builtin_func/expected_stdout
new file mode 100644
index 00000000000..82de3a7e97d
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/builtin_func/expected_stdout
@@ -0,0 +1 @@
+hello world 0
diff --git a/scripts/kconfig/tests/preprocess/circular_expansion/Kconfig b/scripts/kconfig/tests/preprocess/circular_expansion/Kconfig
new file mode 100644
index 00000000000..6838997c23b
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/circular_expansion/Kconfig
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+X = $(Y)
+Y = $(X)
+$(info $(X))
diff --git a/scripts/kconfig/tests/preprocess/circular_expansion/__init__.py b/scripts/kconfig/tests/preprocess/circular_expansion/__init__.py
new file mode 100644
index 00000000000..419bda3e075
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/circular_expansion/__init__.py
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Detect circular variable expansion.
+
+If a recursively expanded variable references itself (eventually),
+it should fail with an error message.
+"""
+
+def test(conf):
+ assert conf.oldaskconfig() != 0
+ assert conf.stderr_matches('expected_stderr')
diff --git a/scripts/kconfig/tests/preprocess/circular_expansion/expected_stderr b/scripts/kconfig/tests/preprocess/circular_expansion/expected_stderr
new file mode 100644
index 00000000000..cde68fa989d
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/circular_expansion/expected_stderr
@@ -0,0 +1 @@
+Kconfig:5: Recursive variable 'X' references itself (eventually)
diff --git a/scripts/kconfig/tests/preprocess/escape/Kconfig b/scripts/kconfig/tests/preprocess/escape/Kconfig
new file mode 100644
index 00000000000..4e3f4444554
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/escape/Kconfig
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Shorthand
+warning = $(warning-if,y,$(1))
+
+# You can not pass commas directly to a function since they are treated as
+# delimiters. You can use the following trick to do so.
+comma := ,
+$(warning,hello$(comma) world)
+
+# Like Make, single quotes, double quotes, spaces are treated verbatim.
+# The following prints the text as-is.
+$(warning, ' " '" ' ''' "'")
+
+# Unlike Make, '$' has special meaning only when it is followed by '('.
+# No need to escape '$' itself.
+$(warning,$)
+$(warning,$$)
+$ := 1
+$(warning,$($))
+
+# You need a trick to escape '$' followed by '('
+# The following should print "$(X)". It should not be expanded further.
+dollar := $
+$(warning,$(dollar)(X))
+
+# You need a trick to treat unbalanced parentheses.
+# The following should print "(".
+left_paren := (
+$(warning,$(left_paren))
+
+# A simple expanded should not be expanded multiple times.
+# The following should print "$(X)". It should not be expanded further.
+Y := $(dollar)(X)
+$(warning,$(Y))
+
+# The following should print "$(X)" as well.
+Y = $(dollar)(X)
+$(warning,$(Y))
+
+# The following should print "$(".
+# It should not be emit "unterminated reference" error.
+unterminated := $(dollar)(
+$(warning,$(unterminated))
diff --git a/scripts/kconfig/tests/preprocess/escape/__init__.py b/scripts/kconfig/tests/preprocess/escape/__init__.py
new file mode 100644
index 00000000000..7ee8e747f54
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/escape/__init__.py
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Escape sequence tests.
+"""
+
+def test(conf):
+ assert conf.oldaskconfig() == 0
+ assert conf.stderr_matches('expected_stderr')
diff --git a/scripts/kconfig/tests/preprocess/escape/expected_stderr b/scripts/kconfig/tests/preprocess/escape/expected_stderr
new file mode 100644
index 00000000000..1c00957ddaa
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/escape/expected_stderr
@@ -0,0 +1,10 @@
+Kconfig:9: hello, world
+Kconfig:13: ' " '" ' ''' "'"
+Kconfig:17: $
+Kconfig:18: $$
+Kconfig:20: 1
+Kconfig:25: $(X)
+Kconfig:30: (
+Kconfig:35: $(X)
+Kconfig:39: $(X)
+Kconfig:44: $(
diff --git a/scripts/kconfig/tests/preprocess/variable/Kconfig b/scripts/kconfig/tests/preprocess/variable/Kconfig
new file mode 100644
index 00000000000..9ce2f95cbd2
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/variable/Kconfig
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Shorthand
+warning = $(warning-if,y,$(1))
+
+# Simply expanded variable.
+X := 1
+SIMPLE := $(X)
+X := 2
+$(warning,SIMPLE = $(SIMPLE))
+
+# Recursively expanded variable.
+X := 1
+RECURSIVE = $(X)
+X := 2
+$(warning,RECURSIVE = $(RECURSIVE))
+
+# Append something to a simply expanded variable.
+Y := 3
+SIMPLE += $(Y)
+Y := 4
+$(warning,SIMPLE = $(SIMPLE))
+
+# Append something to a recursively expanded variable.
+Y := 3
+RECURSIVE += $(Y)
+Y := 4
+$(warning,RECURSIVE = $(RECURSIVE))
+
+# Use += operator to an undefined variable.
+# This works as a recursively expanded variable.
+Y := 3
+UNDEFINED_VARIABLE += $(Y)
+Y := 4
+$(warning,UNDEFINED_VARIABLE = $(UNDEFINED_VARIABLE))
+
+# You can use variable references for the lefthand side of assignment statement.
+X := A
+Y := B
+$(X)$(Y) := 5
+$(warning,AB = $(AB))
+
+# User-defined function.
+greeting = $(1), my name is $(2).
+$(warning,$(greeting,Hello,John))
+
+# The number of arguments is not checked for user-defined functions.
+# If some arguments are optional, it is useful to pass fewer parameters.
+# $(2) will be blank in this case.
+$(warning,$(greeting,Hello))
+
+# Unreferenced parameters are just ignored.
+$(warning,$(greeting,Hello,John,ignored,ignored))
diff --git a/scripts/kconfig/tests/preprocess/variable/__init__.py b/scripts/kconfig/tests/preprocess/variable/__init__.py
new file mode 100644
index 00000000000..e88b1708d6d
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/variable/__init__.py
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Variable and user-defined function tests.
+"""
+
+def test(conf):
+ assert conf.oldaskconfig() == 0
+ assert conf.stderr_matches('expected_stderr')
diff --git a/scripts/kconfig/tests/preprocess/variable/expected_stderr b/scripts/kconfig/tests/preprocess/variable/expected_stderr
new file mode 100644
index 00000000000..a4841c3fdff
--- /dev/null
+++ b/scripts/kconfig/tests/preprocess/variable/expected_stderr
@@ -0,0 +1,9 @@
+Kconfig:10: SIMPLE = 1
+Kconfig:16: RECURSIVE = 2
+Kconfig:22: SIMPLE = 1 3
+Kconfig:28: RECURSIVE = 2 4
+Kconfig:35: UNDEFINED_VARIABLE = 4
+Kconfig:41: AB = 5
+Kconfig:45: Hello, my name is John.
+Kconfig:50: Hello, my name is .
+Kconfig:53: Hello, my name is John.