Merge tag 'kbuild-7.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux

Pull more Kbuild updates from Nathan Chancellor:

 - Link host programs with ld.lld when $(LLVM) is set to match user's
   expectations that LLVM will be used exclusively during the build
   process

 - Fix modpost warnings from static variable name promotion that can
   happen more aggressively with the recently merged distributed ThinLTO
   support

 - Add an optional warning for user-supplied Kconfig values that changed
   after processing, such as out of range values or options that have
   incorrect / missing dependencies

* tag 'kbuild-7.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux:
  kconfig: add optional warnings for changed input values
  modpost: Ignore Clang LTO suffixes in symbol matching
  kbuild: Use ld.lld for linking host programs when LLVM is set
This commit is contained in:
Linus Torvalds
2026-06-25 09:06:12 -07:00
11 changed files with 204 additions and 7 deletions

View File

@@ -59,6 +59,11 @@ Environment variables for ``*config``:
This environment variable makes Kconfig warn about all unrecognized
symbols in the config input.
``KCONFIG_WARN_CHANGED_INPUT``
If set to a non-blank value, Kconfig prints optional warnings for
user-provided values that change after Kconfig resolves dependencies
or applies other constraints such as ranges.
``KCONFIG_WERROR``
If set, Kconfig treats warnings as errors.

View File

@@ -528,6 +528,9 @@ OBJCOPY = $(LLVM_PREFIX)llvm-objcopy$(LLVM_SUFFIX)
OBJDUMP = $(LLVM_PREFIX)llvm-objdump$(LLVM_SUFFIX)
READELF = $(LLVM_PREFIX)llvm-readelf$(LLVM_SUFFIX)
STRIP = $(LLVM_PREFIX)llvm-strip$(LLVM_SUFFIX)
ifeq ($(filter -fuse-ld=% --ld-path=%,$(KBUILD_HOSTLDFLAGS)),)
KBUILD_HOSTLDFLAGS += -fuse-ld=lld
endif
else
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld

View File

@@ -206,6 +206,78 @@ static void conf_message(const char *fmt, ...)
va_end(ap);
}
static void conf_changed_input_warning(const char *s)
{
fputs(s, stderr);
}
static bool conf_warn_changed_input_enabled(void)
{
const char *env = getenv("KCONFIG_WARN_CHANGED_INPUT");
return env && *env;
}
static const char *sym_get_user_value_string(struct symbol *sym)
{
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
switch (sym->def[S_DEF_USER].tri) {
case yes:
return "y";
case mod:
return "m";
default:
return "n";
}
default:
return sym->def[S_DEF_USER].val ?: "";
}
}
static bool sym_user_value_changed(struct symbol *sym)
{
if (!sym_has_value(sym) || sym->type == S_UNKNOWN)
return false;
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
return sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym);
default:
return strcmp(sym_get_user_value_string(sym),
sym_get_string_value(sym));
}
}
static void conf_clear_written_flags(void)
{
struct symbol *sym;
for_all_symbols(sym)
sym->flags &= ~SYMBOL_WRITTEN;
}
static void conf_append_changed_input_warning(struct gstr *gs,
struct symbol *sym,
bool *changed_input_found)
{
if (!sym_user_value_changed(sym))
return;
if (!*changed_input_found) {
str_printf(gs,
"warning: user-provided values changed by Kconfig:\n");
*changed_input_found = true;
}
str_printf(gs, " %s%s: %s -> %s\n",
CONFIG_, sym->name,
sym_get_user_value_string(sym),
sym_get_string_value(sym));
}
const char *conf_get_configname(void)
{
char *name = getenv("KCONFIG_CONFIG");
@@ -759,11 +831,15 @@ int conf_write_defconfig(const char *filename)
{
struct symbol *sym;
struct menu *menu;
struct gstr gs;
FILE *out;
bool warn_changed_input = conf_warn_changed_input_enabled();
bool changed_input_found = false;
out = fopen(filename, "w");
if (!out)
return 1;
gs = str_new();
sym_clear_all_valid();
@@ -772,10 +848,14 @@ int conf_write_defconfig(const char *filename)
sym = menu->sym;
if (!sym || sym_is_choice(sym))
if (!sym || sym_is_choice(sym) || sym->flags & SYMBOL_WRITTEN)
continue;
sym_calc_value(sym);
if (warn_changed_input)
conf_append_changed_input_warning(&gs, sym,
&changed_input_found);
sym->flags |= SYMBOL_WRITTEN;
if (!(sym->flags & SYMBOL_WRITE))
continue;
sym->flags &= ~SYMBOL_WRITE;
@@ -798,6 +878,13 @@ int conf_write_defconfig(const char *filename)
print_symbol_for_dotconfig(out, sym);
}
fclose(out);
conf_clear_written_flags();
if (changed_input_found)
conf_changed_input_warning(str_get(&gs));
str_free(&gs);
return 0;
}
@@ -809,7 +896,10 @@ int conf_write(const char *name)
const char *str;
char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
char *env;
struct gstr gs;
bool need_newline = false;
bool warn_changed_input = conf_warn_changed_input_enabled();
bool changed_input_found = false;
if (!name)
name = conf_get_configname();
@@ -838,6 +928,7 @@ int conf_write(const char *name)
}
if (!out)
return 1;
gs = str_new();
conf_write_heading(out, &comment_style_pound);
@@ -859,13 +950,16 @@ int conf_write(const char *name)
} else if (!sym_is_choice(sym) &&
!(sym->flags & SYMBOL_WRITTEN)) {
sym_calc_value(sym);
if (warn_changed_input)
conf_append_changed_input_warning(&gs, sym,
&changed_input_found);
sym->flags |= SYMBOL_WRITTEN;
if (!(sym->flags & SYMBOL_WRITE))
goto next;
if (need_newline) {
fprintf(out, "\n");
need_newline = false;
}
sym->flags |= SYMBOL_WRITTEN;
print_symbol_for_dotconfig(out, sym);
}
@@ -892,8 +986,12 @@ int conf_write(const char *name)
}
fclose(out);
for_all_symbols(sym)
sym->flags &= ~SYMBOL_WRITTEN;
conf_clear_written_flags();
if (changed_input_found)
conf_changed_input_warning(str_get(&gs));
str_free(&gs);
if (*tmpname) {
if (is_same(name, tmpname)) {

View File

@@ -37,7 +37,8 @@ class Conf:
# runners
def _run_conf(self, mode, dot_config=None, out_file='.config',
interactive=False, in_keys=None, extra_env={}):
interactive=False, in_keys=None, extra_env={},
silent=False):
"""Run text-based Kconfig executable and save the result.
mode: input mode option (--oldaskconfig, --defconfig=<file> etc.)
@@ -48,7 +49,10 @@ class Conf:
extra_env: additional environments
returncode: exit status of the Kconfig executable
"""
command = [CONF_PATH, mode, 'Kconfig']
command = [CONF_PATH]
if silent:
command.append('-s')
command += [mode, 'Kconfig']
# Override 'srctree' environment to make the test as the top directory
extra_env['srctree'] = self._test_dir

View File

@@ -0,0 +1,40 @@
# SPDX-License-Identifier: GPL-2.0
config DEP
bool "DEP"
help
Test dependency symbol for Kconfig warning coverage.
This is used by the warn_changed_input selftest.
It intentionally stays unset in the input fragment.
The test checks how dependent user input is adjusted.
config A
bool "A"
depends on DEP
help
Test bool symbol for changed-input diagnostics.
The input fragment requests this symbol as built-in.
The unmet dependency on DEP forces the final value to n.
The warning should report that downgrade.
config NUM
int "NUM"
range 10 20
help
Test integer symbol for changed-input diagnostics.
The input fragment requests a value outside the allowed range.
Kconfig resolves it to the constrained in-range value.
The warning should report that adjustment.
config DUP
bool "DUP"
depends on DEP
help
Test duplicate-definition handling for changed-input diagnostics.
The input fragment requests this symbol as built-in.
The duplicate definition below must not produce a duplicate warning.
This keeps the warning output stable for repeated menu entries.
config DUP
bool
depends on DEP

View File

@@ -0,0 +1,33 @@
# SPDX-License-Identifier: GPL-2.0
"""
Test optional warnings for user-provided values changed by Kconfig.
Warnings should stay disabled by default, and should only appear when
KCONFIG_WARN_CHANGED_INPUT is enabled.
"""
def test(conf):
assert conf.olddefconfig('config') == 0
assert 'user-provided values changed by Kconfig' not in conf.stderr
assert conf._run_conf('--olddefconfig', dot_config='config',
extra_env={
'KCONFIG_WARN_CHANGED_INPUT': '1',
}) == 0
assert conf.stderr_contains('expected_stderr')
assert conf.config_matches('expected_config')
assert conf._run_conf('--olddefconfig', dot_config='config',
extra_env={
'KCONFIG_WARN_CHANGED_INPUT': '1',
}, silent=True) == 0
assert conf.stderr_contains('expected_stderr')
assert conf._run_conf('--savedefconfig=defconfig', dot_config='config',
out_file='defconfig',
extra_env={
'KCONFIG_WARN_CHANGED_INPUT': '1',
}) == 0
assert conf.stderr_contains('expected_stderr')
assert conf.config_matches('expected_defconfig')

View File

@@ -0,0 +1,3 @@
CONFIG_A=y
CONFIG_NUM=30
CONFIG_DUP=y

View File

@@ -0,0 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
# CONFIG_DEP is not set
CONFIG_NUM=20

View File

@@ -0,0 +1 @@
CONFIG_NUM=20

View File

@@ -0,0 +1,4 @@
warning: user-provided values changed by Kconfig:
CONFIG_A: y -> n
CONFIG_NUM: 30 -> 20
CONFIG_DUP: y -> n

View File

@@ -969,7 +969,7 @@ static int secref_whitelist(const char *fromsec, const char *fromsym,
/* symbols in data sections that may refer to any init/exit sections */
if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
match(fromsym, PATTERNS("*_ops", "*_console")))
match(fromsym, PATTERNS("*_ops", "*_ops.llvm.*", "*_console")))
return 0;
/* Check for pattern 3 */