]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kconfig: Error out on duplicated kconfig inclusion
authorNicolas Schier <nsc@kernel.org>
Fri, 20 Feb 2026 18:55:19 +0000 (19:55 +0100)
committerNicolas Schier <nsc@kernel.org>
Fri, 27 Feb 2026 08:26:58 +0000 (09:26 +0100)
Let kconfig exit with error on duplicated Kconfig file inclusion.

Repeated inclusion of Kbuild files are considered bad-practise with
regard to maintenance; and Kconfig language is rich enough that there
should be no need for that.

If repeated inclusion of Kconfig files is detected, error out with
messages like:

    Kconfig.inc1:4: error: repeated inclusion of Kconfig.inc3
    Kconfig.inc2:3: note: location of first inclusion of Kconfig.inc3

While commit f094f8a1b273 ("kconfig: allow multiple inclusion of the
same file") introduced detection of recursive inclusions of Kconfig
files, it explicitly allowed repeated inclusions, unfortunately w/o
reasoning.

Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Closes: https://lore.kernel.org/all/CAHk-=wj03hLzK2D=+OYmjgcmGM+XYymp8GyaEs=C0=rXG2nb7w@mail.gmail.com/
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Link: https://patch.msgid.link/20260220-kconfig-error-out-on-duplicated-inclusion-v1-1-be78aa241a53@kernel.org
Signed-off-by: Nicolas Schier <nsc@kernel.org>
scripts/kconfig/lexer.l
scripts/kconfig/lkc.h
scripts/kconfig/tests/err_repeated_inc/Kconfig [new file with mode: 0644]
scripts/kconfig/tests/err_repeated_inc/Kconfig.inc1 [new file with mode: 0644]
scripts/kconfig/tests/err_repeated_inc/Kconfig.inc2 [new file with mode: 0644]
scripts/kconfig/tests/err_repeated_inc/Kconfig.inc3 [new file with mode: 0644]
scripts/kconfig/tests/err_repeated_inc/__init__.py [new file with mode: 0644]
scripts/kconfig/tests/err_repeated_inc/expected_stderr [new file with mode: 0644]
scripts/kconfig/util.c

index 6d2c92c6095dd8c247e6c2dd5dd0b56b8ea6a769..a6155422b4a688070a40a88edfedbcacb251da76 100644 (file)
@@ -402,7 +402,7 @@ void zconf_initscan(const char *name)
                exit(1);
        }
 
-       cur_filename = file_lookup(name);
+       cur_filename = file_lookup(name, NULL, 0);
        yylineno = 1;
 }
 
@@ -443,7 +443,7 @@ void zconf_nextfile(const char *name)
        }
 
        yylineno = 1;
-       cur_filename = file_lookup(name);
+       cur_filename = file_lookup(name, cur_filename, cur_lineno);
 }
 
 static void zconf_endfile(void)
index 79898596121563350d2fa63fcf879743b756d003..7e6f6ca299cf1a74e4aed704972bc098616a94b0 100644 (file)
@@ -51,7 +51,8 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
 }
 
 /* util.c */
-const char *file_lookup(const char *name);
+const char *file_lookup(const char *name,
+                       const char *parent_name, int parent_lineno);
 
 /* lexer.l */
 int yylex(void);
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig b/scripts/kconfig/tests/err_repeated_inc/Kconfig
new file mode 100644 (file)
index 0000000..09a88fd
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "Kconfig.inc1"
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc1 b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc1
new file mode 100644 (file)
index 0000000..495dc38
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "Kconfig.inc2"
+source "Kconfig.inc3"
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc2 b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc2
new file mode 100644 (file)
index 0000000..2b630ee
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "Kconfig.inc3"
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc3 b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc3
new file mode 100644 (file)
index 0000000..a4e40e5
--- /dev/null
@@ -0,0 +1 @@
+# SPDX-License-Identifier: GPL-2.0-only
diff --git a/scripts/kconfig/tests/err_repeated_inc/__init__.py b/scripts/kconfig/tests/err_repeated_inc/__init__.py
new file mode 100644 (file)
index 0000000..129d740
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Detect repeated inclusion error.
+
+If repeated inclusion is detected, it should fail with error message.
+"""
+
+def test(conf):
+    assert conf.oldaskconfig() != 0
+    assert conf.stderr_contains('expected_stderr')
diff --git a/scripts/kconfig/tests/err_repeated_inc/expected_stderr b/scripts/kconfig/tests/err_repeated_inc/expected_stderr
new file mode 100644 (file)
index 0000000..95d90d6
--- /dev/null
@@ -0,0 +1,2 @@
+Kconfig.inc1:4: error: Repeated inclusion of Kconfig.inc3
+Kconfig.inc2:3: note: Location of first inclusion of Kconfig.inc3
index 5cdcee144b58126dcfab50fd709be9fc40e99423..0809aa061b6ac0037ea972f46e037711178d12b3 100644 (file)
@@ -18,25 +18,50 @@ static HASHTABLE_DEFINE(file_hashtable, 1U << 11);
 
 struct file {
        struct hlist_node node;
+       struct {
+               const char *name;
+               int lineno;
+       } parent;
        char name[];
 };
 
+static void die_duplicated_include(struct file *file,
+                                  const char *parent, int lineno)
+{
+       fprintf(stderr,
+               "%s:%d: error: repeated inclusion of %s\n"
+               "%s:%d: note: location of first inclusion of %s\n",
+               parent, lineno, file->name,
+               file->parent.name, file->parent.lineno, file->name);
+       exit(1);
+}
+
 /* file already present in list? If not add it */
-const char *file_lookup(const char *name)
+const char *file_lookup(const char *name,
+                       const char *parent_name, int parent_lineno)
 {
+       const char *parent = NULL;
        struct file *file;
        size_t len;
        int hash = hash_str(name);
 
+       if (parent_name)
+               parent = file_lookup(parent_name, NULL, 0);
+
        hash_for_each_possible(file_hashtable, file, node, hash)
-               if (!strcmp(name, file->name))
-                       return file->name;
+               if (!strcmp(name, file->name)) {
+                       if (!parent_name)
+                               return file->name;
+                       die_duplicated_include(file, parent, parent_lineno);
+               }
 
        len = strlen(name);
        file = xmalloc(sizeof(*file) + len + 1);
        memset(file, 0, sizeof(*file));
        memcpy(file->name, name, len);
        file->name[len] = '\0';
+       file->parent.name = parent;
+       file->parent.lineno = parent_lineno;
 
        hash_add(file_hashtable, &file->node, hash);