Kbuild/Kconfig updates for 7.0

Kbuild changes
 ==============
 
 * Drop '*_probe' pattern from modpost section check allowlist, which hid
   legitimate warnings (Johan Hovold)
 
 * Disable -Wtype-limits altogether, instead of enabling at W=2 (Vincent
   Mailhol)
 
 * Improve UAPI testing to skip testing headers that require a libc when
   CONFIG_CC_CAN_LINK is not set, opening up testing of headers with no
   libc dependencies to more environments (Thomas Weißschuh)
 
 * Update gendwarfksyms documentation with required dependencies (Jihan
   LIN)
 
 * Reject invalid LLVM= values to avoid unintentionally falling back to
   system toolchain (Thomas Weißschuh)
 
 * Add a script to help run the kernel build process in a container for
   consistent environments and testing (Guillaume Tucker)
 
 * Simplify kallsyms by getting rid of the relative base (Ard Biesheuvel)
 
 * Performance and usability improvements to scripts/make_fit.py (Simon
   Glass)
 
 * Minor various clean ups and fixes
 
 Kconfig changes
 ===============
 
 * Move XPM icons to individual files, clearing up GTK deprecation
   warnings (Rostislav Krasny)
 
 * Support
 
     depends on FOO if BAR
 
   as syntactic sugar for
 
     depends on FOO || !BAR' (Nicolas Pitre, Graham Roff)
 
 * Refactor merge_config.sh to use awk over shell/sed/grep, dramatically
   speeding up processing large number of config fragments (Anders
   Roxell, Mikko Rapeli)
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQR74yXHMTGczQHYypIdayaRccAalgUCaYpgQwAKCRAdayaRccAa
 liOGAQCqMI42YMLqljFcPu3B/3f43xhDBCXAhquPBIMhbgt+aAEAmmo3uMLHKSRV
 XZDKkq13HMMV3Zlmrn5Xk/tzk+hkwwk=
 =WYl4
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQR74yXHMTGczQHYypIdayaRccAalgUCaY3/8AAKCRAdayaRccAa
 loi3AP4nX5Jd1DHz+F+5ZGIRErtRwVeN6oagegTIi029H6ENFAD/c20+xB7jB+Gi
 XGUytlJS8+I+A43Pv16ZR243OECGyw0=
 =XjYX
 -----END PGP SIGNATURE-----

Merge 7.0 Kbuild changes into kbuild-fixes

kbuild-fixes needs to be based on 6.19 to apply some fixes for

  62089b8048 ("kbuild: rpm-pkg: Generate debuginfo package manually")

which landed in 6.19-rc1 but the new material of 7.0 needs fixes merged
as well.

Signed-off-by: Nathan Chancellor <nathan@kernel.org>
This commit is contained in:
Nathan Chancellor 2026-02-12 11:28:27 -05:00
commit df989b01b5
63 changed files with 1516 additions and 627 deletions

View file

@ -0,0 +1,227 @@
.. SPDX-License-Identifier: GPL-2.0-only
.. Copyright (C) 2025 Guillaume Tucker
====================
Containerized Builds
====================
The ``container`` tool can be used to run any command in the kernel source tree
from within a container. Doing so facilitates reproducing builds across
various platforms, for example when a test bot has reported an issue which
requires a specific version of a compiler or an external test suite. While
this can already be done by users who are familiar with containers, having a
dedicated tool in the kernel tree lowers the barrier to entry by solving common
problems once and for all (e.g. user id management). It also makes it easier
to share an exact command line leading to a particular result. The main use
case is likely to be kernel builds but virtually anything can be run: KUnit,
checkpatch etc. provided a suitable image is available.
Options
=======
Command line syntax::
scripts/container -i IMAGE [OPTION]... CMD...
Available options:
``-e, --env-file ENV_FILE``
Path to an environment file to load in the container.
``-g, --gid GID``
Group id to use inside the container.
``-i, --image IMAGE``
Container image name (required).
``-r, --runtime RUNTIME``
Container runtime name. Supported runtimes: ``docker``, ``podman``.
If not specified, the first one found on the system will be used
i.e. Podman if present, otherwise Docker.
``-s, --shell``
Run the container in an interactive shell.
``-u, --uid UID``
User id to use inside the container.
If the ``-g`` option is not specified, the user id will also be used for
the group id.
``-v, --verbose``
Enable verbose output.
``-h, --help``
Show the help message and exit.
Usage
=====
It's entirely up to the user to choose which image to use and the ``CMD``
arguments are passed directly as an arbitrary command line to run in the
container. The tool will take care of mounting the source tree as the current
working directory and adjust the user and group id as needed.
The container image which would typically include a compiler toolchain is
provided by the user and selected via the ``-i`` option. The container runtime
can be selected with the ``-r`` option, which can be either ``docker`` or
``podman``. If none is specified, the first one found on the system will be
used while giving priority to Podman. Support for other runtimes may be added
later depending on their popularity among users.
By default, commands are run non-interactively. The user can abort a running
container with SIGINT (Ctrl-C). To run commands interactively with a TTY, the
``--shell`` or ``-s`` option can be used. Signals will then be received by the
shell directly rather than the parent ``container`` process. To exit an
interactive shell, use Ctrl-D or ``exit``.
.. note::
The only host requirement aside from a container runtime is Python 3.10 or
later.
.. note::
Out-of-tree builds are not fully supported yet. The ``O=`` option can
however already be used with a relative path inside the source tree to keep
separate build outputs. A workaround to build outside the tree is to use
``mount --bind``, see the examples section further down.
Environment Variables
=====================
Environment variables are not propagated to the container so they have to be
either defined in the image itself or via the ``-e`` option using an
environment file. In some cases it makes more sense to have them defined in
the Containerfile used to create the image. For example, a Clang-only compiler
toolchain image may have ``LLVM=1`` defined.
The local environment file is more useful for user-specific variables added
during development. It is passed as-is to the container runtime so its format
may vary. Typically, it will look like the output of ``env``. For example::
INSTALL_MOD_STRIP=1
SOME_RANDOM_TEXT=One upon a time
Please also note that ``make`` options can still be passed on the command line,
so while this can't be done since the first argument needs to be the
executable::
scripts/container -i docker.io/tuxmake/korg-clang LLVM=1 make # won't work
this will work::
scripts/container -i docker.io/tuxmake/korg-clang make LLVM=1
User IDs
========
This is an area where the behaviour will vary slightly depending on the
container runtime. The goal is to run commands as the user invoking the tool.
With Podman, a namespace is created to map the current user id to a different
one in the container (1000 by default). With Docker, while this is also
possible with recent versions it requires a special feature to be enabled in
the daemon so it's not used here for simplicity. Instead, the container is run
with the current user id directly. In both cases, this will provide the same
file permissions for the kernel source tree mounted as a volume. The only
difference is that when using Docker without a namespace, the user id may not
be the same as the default one set in the image.
Say, we're using an image which sets up a default user with id 1000 and the
current user calling the ``container`` tool has id 1234. The kernel source
tree was checked out by this same user so the files belong to user 1234. With
Podman, the container will be running as user id 1000 with a mapping to id 1234
so that the files from the mounted volume appear to belong to id 1000 inside
the container. With Docker and no namespace, the container will be running
with user id 1234 which can access the files in the volume but not in the user
1000 home directory. This shouldn't be an issue when running commands only in
the kernel tree but it is worth highlighting here as it might matter for
special corner cases.
.. note::
Podman's `Docker compatibility
<https://podman-desktop.io/docs/migrating-from-docker/managing-docker-compatibility>`__
mode to run ``docker`` commands on top of a Podman backend is more complex
and not fully supported yet. As such, Podman will take priority if both
runtimes are available on the system.
Examples
========
The TuxMake project provides a variety of prebuilt container images available
on `Docker Hub <https://hub.docker.com/u/tuxmake>`__. Here's the shortest
example to build a kernel using a TuxMake Clang image::
scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 defconfig
scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 -j$(nproc)
.. note::
When running a command with options within the container, it should be
separated with a double dash ``--`` to not confuse them with the
``container`` tool options. Plain commands with no options don't strictly
require the double dashes e.g.::
scripts/container -i docker.io/tuxmake/korg-clang make mrproper
To run ``checkpatch.pl`` in a ``patches`` directory with a generic Perl image::
scripts/container -i perl:slim-trixie scripts/checkpatch.pl patches/*
As an alternative to the TuxMake images, the examples below refer to
``kernel.org`` images which are based on the `kernel.org compiler toolchains
<https://mirrors.edge.kernel.org/pub/tools/>`__. These aren't (yet) officially
available in any public registry but users can build their own locally instead
using this `experimental repository
<https://gitlab.com/gtucker/korg-containers>`__ by running ``make
PREFIX=kernel.org/``.
To build just ``bzImage`` using Clang::
scripts/container -i kernel.org/clang -- make bzImage -j$(nproc)
Same with GCC 15 as a particular version tag::
scripts/container -i kernel.org/gcc:15 -- make bzImage -j$(nproc)
For an out-of-tree build, a trick is to bind-mount the destination directory to
a relative path inside the source tree::
mkdir -p $HOME/tmp/my-kernel-build
mkdir -p build
sudo mount --bind $HOME/tmp/my-kernel-build build
scripts/container -i kernel.org/gcc -- make mrproper
scripts/container -i kernel.org/gcc -- make O=build defconfig
scripts/container -i kernel.org/gcc -- make O=build -j$(nproc)
To run KUnit in an interactive shell and get the full output::
scripts/container -s -i kernel.org/gcc:kunit -- \
tools/testing/kunit/kunit.py \
run \
--arch=x86_64 \
--cross_compile=x86_64-linux-
To just start an interactive shell::
scripts/container -si kernel.org/gcc bash
To build the HTML documentation, which requires the ``kdocs`` image built with
``make PREFIX=kernel.org/ extra`` as it's not a compiler toolchain::
scripts/container -i kernel.org/kdocs make htmldocs

View file

@ -38,6 +38,7 @@ Documentation/process/debugging/index.rst
gpio-sloppy-logic-analyzer
autofdo
propeller
container
.. only:: subproject and html

View file

@ -14,6 +14,29 @@ selected, **gendwarfksyms** is used instead to calculate symbol versions
from the DWARF debugging information, which contains the necessary
details about the final module ABI.
Dependencies
------------
gendwarfksyms depends on the libelf, libdw, and zlib libraries.
Here are a few examples of how to install these dependencies:
* Arch Linux and derivatives::
sudo pacman --needed -S libelf zlib
* Debian, Ubuntu, and derivatives::
sudo apt install libelf-dev libdw-dev zlib1g-dev
* Fedora and derivatives::
sudo dnf install elfutils-libelf-devel elfutils-devel zlib-devel
* openSUSE and derivatives::
sudo zypper install libelf-devel libdw-devel zlib-devel
Usage
-----

View file

@ -118,7 +118,7 @@ applicable everywhere (see syntax).
This is a shorthand notation for a type definition plus a value.
Optionally dependencies for this default value can be added with "if".
- dependencies: "depends on" <expr>
- dependencies: "depends on" <expr> ["if" <expr>]
This defines a dependency for this menu entry. If multiple
dependencies are defined, they are connected with '&&'. Dependencies
@ -134,6 +134,16 @@ applicable everywhere (see syntax).
bool "foo"
default y
The dependency definition itself may be conditional by appending "if"
followed by an expression. For example::
config FOO
tristate
depends on BAR if BAZ
meaning that FOO is constrained by the value of BAR only if BAZ is
also set.
- reverse dependencies: "select" <symbol> ["if" <expr>]
While normal dependencies reduce the upper limit of a symbol (see
@ -602,8 +612,14 @@ Some drivers are able to optionally use a feature from another module
or build cleanly with that module disabled, but cause a link failure
when trying to use that loadable module from a built-in driver.
The most common way to express this optional dependency in Kconfig logic
uses the slightly counterintuitive::
The recommended way to express this optional dependency in Kconfig logic
uses the conditional form::
config FOO
tristate "Support for foo hardware"
depends on BAR if BAR
This slightly counterintuitive style is also widely used::
config FOO
tristate "Support for foo hardware"

View file

@ -6386,6 +6386,12 @@ S: Supported
F: drivers/video/console/
F: include/linux/console*
CONTAINER BUILD SCRIPT
M: Guillaume Tucker <gtucker@gtucker.io>
S: Maintained
F: Documentation/dev-tools/container.rst
F: scripts/container
CONTEXT TRACKING
M: Frederic Weisbecker <frederic@kernel.org>
M: "Paul E. McKenney" <paulmck@kernel.org>
@ -13683,8 +13689,10 @@ F: scripts/Makefile*
F: scripts/bash-completion/
F: scripts/basic/
F: scripts/clang-tools/
F: scripts/container
F: scripts/dummy-tools/
F: scripts/include/
F: scripts/install.sh
F: scripts/mk*
F: scripts/mod/
F: scripts/package/

View file

@ -295,7 +295,8 @@ no-dot-config-targets := $(clean-targets) \
cscope gtags TAGS tags help% %docs check% coccicheck \
$(version_h) headers headers_% archheaders archscripts \
%asm-generic kernelversion %src-pkg dt_binding_check \
outputmakefile rustavailable rustfmt rustfmtcheck
outputmakefile rustavailable rustfmt rustfmtcheck \
run-command
no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
image_name
single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %/
@ -447,6 +448,8 @@ ifneq ($(filter %/,$(LLVM)),)
LLVM_PREFIX := $(LLVM)
else ifneq ($(filter -%,$(LLVM)),)
LLVM_SUFFIX := $(LLVM)
else ifneq ($(LLVM),1)
$(error Invalid value for LLVM, see Documentation/kbuild/llvm.rst)
endif
HOSTCC = $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
@ -1102,7 +1105,7 @@ KBUILD_CFLAGS += -fno-builtin-wcslen
# change __FILE__ to the relative path to the source directory
ifdef building_out_of_srctree
KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srcroot)/=)
KBUILD_CPPFLAGS += -fmacro-prefix-map=$(srcroot)/=
endif
# include additional Makefiles when needed
@ -1417,6 +1420,10 @@ ifdef CONFIG_HEADERS_INSTALL
prepare: headers
endif
PHONY += usr_gen_init_cpio
usr_gen_init_cpio: scripts_basic
$(Q)$(MAKE) $(build)=usr usr/gen_init_cpio
PHONY += scripts_unifdef
scripts_unifdef: scripts_basic
$(Q)$(MAKE) $(build)=scripts scripts/unifdef
@ -1670,6 +1677,8 @@ distclean: mrproper
# Packaging of the kernel to various formats
# ---------------------------------------------------------------------------
modules-cpio-pkg: usr_gen_init_cpio
%src-pkg: FORCE
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@
%pkg: include/config/kernel.release FORCE

View file

@ -79,6 +79,7 @@ static const char *rel_type(unsigned type)
REL_TYPE(R_MIPS_HIGHEST),
REL_TYPE(R_MIPS_PC21_S2),
REL_TYPE(R_MIPS_PC26_S2),
REL_TYPE(R_MIPS_PC32),
#undef REL_TYPE
};
const char *name = "unknown type rel type name";
@ -522,6 +523,7 @@ static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
case R_MIPS_PC16:
case R_MIPS_PC21_S2:
case R_MIPS_PC26_S2:
case R_MIPS_PC32:
/*
* NONE can be ignored and PC relative relocations don't
* need to be adjusted.

View file

@ -29,6 +29,13 @@ void die(char *fmt, ...);
#define R_MIPS_PC26_S2 61
#endif
/*
* GNU extension that available in glibc only since 2023, not available on musl.
*/
#ifndef R_MIPS_PC32
#define R_MIPS_PC32 248
#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
enum symtype {

View file

@ -123,6 +123,8 @@
#define R_MIPS_LOVENDOR 100
#define R_MIPS_HIVENDOR 127
#define R_MIPS_PC32 248
#define SHN_MIPS_ACCOMON 0xff00 /* Allocated common symbols */
#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */

View file

@ -22,7 +22,6 @@ subdir-ccflags-y += $(call cc-option, -Wstringop-truncation)
# The following turn off the warnings enabled by -Wextra
ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),)
subdir-ccflags-y += -Wno-missing-field-initializers
subdir-ccflags-y += -Wno-type-limits
subdir-ccflags-y += -Wno-shift-negative-value
endif
ifeq ($(findstring 3, $(KBUILD_EXTRA_WARN)),)

View file

@ -17,7 +17,6 @@ subdir-ccflags-y += $(condflags)
# The following turn off the warnings enabled by -Wextra
subdir-ccflags-y += -Wno-missing-field-initializers
subdir-ccflags-y += -Wno-sign-compare
subdir-ccflags-y += -Wno-type-limits
subdir-ccflags-y += -Wno-shift-negative-value
obj-$(CONFIG_BTRFS_FS) := btrfs.o

View file

@ -36,12 +36,6 @@
#define __type_min(T) ((T)((T)-type_max(T)-(T)1))
#define type_min(t) __type_min(typeof(t))
/*
* Avoids triggering -Wtype-limits compilation warning,
* while using unsigned data types to check a < 0.
*/
#define is_non_negative(a) ((a) > 0 || (a) == 0)
#define is_negative(a) (!(is_non_negative(a)))
/*
* Allows for effectively applying __must_check to a macro so we can have
@ -201,9 +195,9 @@ static inline bool __must_check __must_check_overflow(bool overflow)
typeof(d) _d = d; \
unsigned long long _a_full = _a; \
unsigned int _to_shift = \
is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \
_s >= 0 && _s < 8 * sizeof(*d) ? _s : 0; \
*_d = (_a_full << _to_shift); \
(_to_shift != _s || is_negative(*_d) || is_negative(_a) || \
(_to_shift != _s || *_d < 0 || _a < 0 || \
(*_d >> _to_shift) != _a); \
}))

View file

@ -362,7 +362,7 @@ struct hv_kvp_exchg_msg_value {
__u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
__u32 value_u32;
__u64 value_u64;
};
} __attribute__((packed));
} __attribute__((packed));
struct hv_kvp_msg_enumerate {

View file

@ -236,7 +236,7 @@ struct vmmdev_hgcm_function_parameter32 {
/** Relative to the request header. */
__u32 offset;
} page_list;
} u;
} __packed u;
} __packed;
VMMDEV_ASSERT_SIZE(vmmdev_hgcm_function_parameter32, 4 + 8);
@ -251,7 +251,7 @@ struct vmmdev_hgcm_function_parameter64 {
union {
__u64 phys_addr;
__u64 linear_addr;
} u;
} __packed u;
} __packed pointer;
struct {
/** Size of the buffer described by the page list. */

View file

@ -247,7 +247,7 @@ config WERROR
config UAPI_HEADER_TEST
bool "Compile test UAPI headers"
depends on HEADERS_INSTALL && CC_CAN_LINK
depends on HEADERS_INSTALL
help
Compile test headers exported to user-space to ensure they are
self-contained, i.e. compilable as standalone units.

View file

@ -151,8 +151,10 @@ static unsigned int get_symbol_offset(unsigned long pos)
unsigned long kallsyms_sym_address(int idx)
{
/* values are unsigned offsets */
return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
/* non-relocatable 32-bit kernels just embed the value directly */
if (!IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_RELOCATABLE))
return (u32)kallsyms_offsets[idx];
return (unsigned long)offset_to_ptr(kallsyms_offsets + idx);
}
static unsigned int get_symbol_seq(int index)

View file

@ -8,7 +8,6 @@ extern const int kallsyms_offsets[];
extern const u8 kallsyms_names[];
extern const unsigned int kallsyms_num_syms;
extern const unsigned long kallsyms_relative_base;
extern const char kallsyms_token_table[];
extern const u16 kallsyms_token_index[];

View file

@ -242,7 +242,6 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_SYMBOL(kallsyms_token_table);
VMCOREINFO_SYMBOL(kallsyms_token_index);
VMCOREINFO_SYMBOL(kallsyms_offsets);
VMCOREINFO_SYMBOL(kallsyms_relative_base);
#endif /* CONFIG_KALLSYMS */
arch_crash_save_vmcoreinfo();

View file

@ -73,8 +73,6 @@ rustc-llvm-version := $(shell,$(srctree)/scripts/rustc-llvm-version.sh $(RUSTC))
# $(rustc-option,<flag>)
# Return y if the Rust compiler supports <flag>, n otherwise
# Calls to this should be guarded so that they are not evaluated if
# CONFIG_RUST_IS_AVAILABLE is not set.
# If you are testing for unstable features, consider testing RUSTC_VERSION
# instead, as features may have different completeness while available.
rustc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(RUSTC) $(1) --crate-type=rlib /dev/null --out-dir=.tmp_$$ -o .tmp_$$/tmp.rlib)

View file

@ -400,7 +400,7 @@ FIT_COMPRESSION ?= gzip
quiet_cmd_fit = FIT $@
cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
--name '$(UIMAGE_NAME)' \
--name '$(UIMAGE_NAME)' $(FIT_EXTRA_ARGS) \
$(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
$(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
--compress $(FIT_COMPRESSION) -k $< @$(word 2,$^)

View file

@ -201,7 +201,6 @@ quiet_cmd_cpio = CPIO $@
cmd_cpio = $(CONFIG_SHELL) $(srctree)/usr/gen_initramfs.sh -o $@ $<
modules-$(KERNELRELEASE)-$(ARCH).cpio: .tmp_modules_cpio
$(Q)$(MAKE) $(build)=usr usr/gen_init_cpio
$(call cmd,cpio)
PHONY += modules-cpio-pkg

View file

@ -16,7 +16,7 @@ KBUILD_CFLAGS += -Werror=return-type
KBUILD_CFLAGS += -Werror=strict-prototypes
KBUILD_CFLAGS += -Wno-format-security
KBUILD_CFLAGS += -Wno-trigraphs
KBUILD_CFLAGS += $(call cc-option, -Wno-frame-address)
KBUILD_CFLAGS += -Wno-frame-address
KBUILD_CFLAGS += $(call cc-option, -Wno-address-of-packed-member)
KBUILD_CFLAGS += -Wmissing-declarations
KBUILD_CFLAGS += -Wmissing-prototypes
@ -55,6 +55,9 @@ else
KBUILD_CFLAGS += -Wno-main
endif
# Too noisy on range checks and in macros handling both signed and unsigned.
KBUILD_CFLAGS += -Wno-type-limits
# These result in bogus false positives
KBUILD_CFLAGS += $(call cc-option, -Wno-dangling-pointer)
@ -72,7 +75,7 @@ KBUILD_CFLAGS += -Wno-pointer-sign
# In order to make sure new function cast mismatches are not introduced
# in the kernel (to avoid tripping CFI checking), the kernel should be
# globally built with -Wcast-function-type.
KBUILD_CFLAGS += $(call cc-option, -Wcast-function-type)
KBUILD_CFLAGS += -Wcast-function-type
# Currently, disable -Wstringop-overflow for GCC 11, globally.
KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(call cc-option, -Wno-stringop-overflow)
@ -99,7 +102,7 @@ KBUILD_CFLAGS += $(KBUILD_CFLAGS-y) $(CONFIG_CC_IMPLICIT_FALLTHROUGH)
KBUILD_CFLAGS += -Werror=date-time
# enforce correct pointer usage
KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types)
KBUILD_CFLAGS += -Werror=incompatible-pointer-types
# Require designated initializers for all marked structures
KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
@ -116,7 +119,7 @@ ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),)
KBUILD_CFLAGS += -Wmissing-format-attribute
KBUILD_CFLAGS += -Wmissing-include-dirs
KBUILD_CFLAGS += $(call cc-option, -Wunused-const-variable)
KBUILD_CFLAGS += -Wunused-const-variable
KBUILD_CPPFLAGS += -Wundef
KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN1
@ -125,12 +128,12 @@ else
# Some diagnostics enabled by default are noisy.
# Suppress them by using -Wno... except for W=1.
KBUILD_CFLAGS += $(call cc-option, -Wno-unused-but-set-variable)
KBUILD_CFLAGS += $(call cc-option, -Wno-unused-const-variable)
KBUILD_CFLAGS += -Wno-unused-but-set-variable
KBUILD_CFLAGS += -Wno-unused-const-variable
KBUILD_CFLAGS += $(call cc-option, -Wno-packed-not-aligned)
KBUILD_CFLAGS += $(call cc-option, -Wno-format-overflow)
ifdef CONFIG_CC_IS_GCC
KBUILD_CFLAGS += $(call cc-option, -Wno-format-truncation)
KBUILD_CFLAGS += -Wno-format-truncation
endif
KBUILD_CFLAGS += $(call cc-option, -Wno-stringop-truncation)
@ -145,14 +148,11 @@ KBUILD_CFLAGS += -Wno-format
# problematic.
KBUILD_CFLAGS += -Wformat-extra-args -Wformat-invalid-specifier
KBUILD_CFLAGS += -Wformat-zero-length -Wnonnull
# Requires clang-12+.
ifeq ($(call clang-min-version, 120000),y)
KBUILD_CFLAGS += -Wformat-insufficient-args
endif
endif
KBUILD_CFLAGS += $(call cc-option, -Wno-pointer-to-enum-cast)
KBUILD_CFLAGS += -Wno-pointer-to-enum-cast
KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
KBUILD_CFLAGS += $(call cc-option, -Wno-unaligned-access)
KBUILD_CFLAGS += -Wno-unaligned-access
KBUILD_CFLAGS += -Wno-enum-compare-conditional
endif
@ -166,7 +166,7 @@ ifneq ($(findstring 2, $(KBUILD_EXTRA_WARN)),)
KBUILD_CFLAGS += -Wdisabled-optimization
KBUILD_CFLAGS += -Wshadow
KBUILD_CFLAGS += $(call cc-option, -Wlogical-op)
KBUILD_CFLAGS += $(call cc-option, -Wunused-macros)
KBUILD_CFLAGS += -Wunused-macros
KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN2
@ -174,7 +174,6 @@ else
# The following turn off the warnings enabled by -Wextra
KBUILD_CFLAGS += -Wno-missing-field-initializers
KBUILD_CFLAGS += -Wno-type-limits
KBUILD_CFLAGS += -Wno-shift-negative-value
ifdef CONFIG_CC_IS_CLANG

199
scripts/container Executable file
View file

@ -0,0 +1,199 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (C) 2025 Guillaume Tucker
"""Containerized builds"""
import abc
import argparse
import logging
import os
import pathlib
import shutil
import subprocess
import sys
import uuid
class ContainerRuntime(abc.ABC):
"""Base class for a container runtime implementation"""
name = None # Property defined in each implementation class
def __init__(self, args, logger):
self._uid = args.uid or os.getuid()
self._gid = args.gid or args.uid or os.getgid()
self._env_file = args.env_file
self._shell = args.shell
self._logger = logger
@classmethod
def is_present(cls):
"""Determine whether the runtime is present on the system"""
return shutil.which(cls.name) is not None
@abc.abstractmethod
def _do_run(self, image, cmd, container_name):
"""Runtime-specific handler to run a command in a container"""
@abc.abstractmethod
def _do_abort(self, container_name):
"""Runtime-specific handler to abort a running container"""
def run(self, image, cmd):
"""Run a command in a runtime container"""
container_name = str(uuid.uuid4())
self._logger.debug("container: %s", container_name)
try:
return self._do_run(image, cmd, container_name)
except KeyboardInterrupt:
self._logger.error("user aborted")
self._do_abort(container_name)
return 1
class CommonRuntime(ContainerRuntime):
"""Common logic for Docker and Podman"""
def _do_run(self, image, cmd, container_name):
cmdline = [self.name, 'run']
cmdline += self._get_opts(container_name)
cmdline.append(image)
cmdline += cmd
self._logger.debug('command: %s', ' '.join(cmdline))
return subprocess.call(cmdline)
def _get_opts(self, container_name):
opts = [
'--name', container_name,
'--rm',
'--volume', f'{pathlib.Path.cwd()}:/src',
'--workdir', '/src',
]
if self._env_file:
opts += ['--env-file', self._env_file]
if self._shell:
opts += ['--interactive', '--tty']
return opts
def _do_abort(self, container_name):
subprocess.call([self.name, 'kill', container_name])
class DockerRuntime(CommonRuntime):
"""Run a command in a Docker container"""
name = 'docker'
def _get_opts(self, container_name):
return super()._get_opts(container_name) + [
'--user', f'{self._uid}:{self._gid}'
]
class PodmanRuntime(CommonRuntime):
"""Run a command in a Podman container"""
name = 'podman'
def _get_opts(self, container_name):
return super()._get_opts(container_name) + [
'--userns', f'keep-id:uid={self._uid},gid={self._gid}',
]
class Runtimes:
"""List of all supported runtimes"""
runtimes = [PodmanRuntime, DockerRuntime]
@classmethod
def get_names(cls):
"""Get a list of all the runtime names"""
return list(runtime.name for runtime in cls.runtimes)
@classmethod
def get(cls, name):
"""Get a single runtime class matching the given name"""
for runtime in cls.runtimes:
if runtime.name == name:
if not runtime.is_present():
raise ValueError(f"runtime not found: {name}")
return runtime
raise ValueError(f"unknown runtime: {name}")
@classmethod
def find(cls):
"""Find the first runtime present on the system"""
for runtime in cls.runtimes:
if runtime.is_present():
return runtime
raise ValueError("no runtime found")
def _get_logger(verbose):
"""Set up a logger with the appropriate level"""
logger = logging.getLogger('container')
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(
fmt='[container {levelname}] {message}', style='{'
))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG if verbose is True else logging.INFO)
return logger
def main(args):
"""Main entry point for the container tool"""
logger = _get_logger(args.verbose)
try:
cls = Runtimes.get(args.runtime) if args.runtime else Runtimes.find()
except ValueError as ex:
logger.error(ex)
return 1
logger.debug("runtime: %s", cls.name)
logger.debug("image: %s", args.image)
return cls(args, logger).run(args.image, args.cmd)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
'container',
description="See the documentation for more details: "
"https://docs.kernel.org/dev-tools/container.html"
)
parser.add_argument(
'-e', '--env-file',
help="Path to an environment file to load in the container."
)
parser.add_argument(
'-g', '--gid',
help="Group ID to use inside the container."
)
parser.add_argument(
'-i', '--image', required=True,
help="Container image name."
)
parser.add_argument(
'-r', '--runtime', choices=Runtimes.get_names(),
help="Container runtime name. If not specified, the first one found "
"on the system will be used i.e. Podman if present, otherwise Docker."
)
parser.add_argument(
'-s', '--shell', action='store_true',
help="Run the container in an interactive shell."
)
parser.add_argument(
'-u', '--uid',
help="User ID to use inside the container. If the -g option is not "
"specified, the user ID will also be set as the group ID."
)
parser.add_argument(
'-v', '--verbose', action='store_true',
help="Enable verbose output."
)
parser.add_argument(
'cmd', nargs='+',
help="Command to run in the container"
)
sys.exit(main(parser.parse_args(sys.argv[1:])))

4
scripts/dummy-tools/python3 Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
true

View file

@ -46,7 +46,6 @@ struct addr_range {
};
static unsigned long long _text;
static unsigned long long relative_base;
static struct addr_range text_ranges[] = {
{ "_stext", "_etext" },
{ "_sinittext", "_einittext" },
@ -57,6 +56,7 @@ static struct addr_range text_ranges[] = {
static struct sym_entry **table;
static unsigned int table_size, table_cnt;
static int all_symbols;
static int pc_relative;
static int token_profit[0x10000];
@ -280,7 +280,7 @@ static void read_map(const char *in)
static void output_label(const char *label)
{
printf(".globl %s\n", label);
printf("\tALGN\n");
printf("\t.balign 4\n");
printf("%s:\n", label);
}
@ -343,15 +343,6 @@ static void write_src(void)
unsigned int *markers, markers_cnt;
char buf[KSYM_NAME_LEN];
printf("#include <asm/bitsperlong.h>\n");
printf("#if BITS_PER_LONG == 64\n");
printf("#define PTR .quad\n");
printf("#define ALGN .balign 8\n");
printf("#else\n");
printf("#define PTR .long\n");
printf("#define ALGN .balign 4\n");
printf("#endif\n");
printf("\t.section .rodata, \"a\"\n");
output_label("kallsyms_num_syms");
@ -434,32 +425,22 @@ static void write_src(void)
output_label("kallsyms_offsets");
for (i = 0; i < table_cnt; i++) {
/*
* Use the offset relative to the lowest value
* encountered of all relative symbols, and emit
* non-relocatable fixed offsets that will be fixed
* up at runtime.
*/
if (pc_relative) {
long long offset = table[i]->addr - _text;
long long offset;
offset = table[i]->addr - relative_base;
if (offset < 0 || offset > UINT_MAX) {
if (offset < INT_MIN || offset > INT_MAX) {
fprintf(stderr, "kallsyms failure: "
"relative symbol value %#llx out of range\n",
table[i]->addr);
exit(EXIT_FAILURE);
}
printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym);
printf("\t.long\t_text - . + (%d)\t/* %s */\n",
(int)offset, table[i]->sym);
} else {
printf("\t.long\t%#x\t/* %s */\n",
(unsigned int)table[i]->addr, table[i]->sym);
}
}
printf("\n");
output_label("kallsyms_relative_base");
/* Provide proper symbols relocatability by their '_text' relativeness. */
if (_text <= relative_base)
printf("\tPTR\t_text + %#llx\n", relative_base - _text);
else
printf("\tPTR\t_text - %#llx\n", _text - relative_base);
printf("\n");
sort_symbols_by_name();
@ -701,22 +682,12 @@ static void sort_symbols(void)
qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
}
/* find the minimum non-absolute symbol address */
static void record_relative_base(void)
{
/*
* The table is sorted by address.
* Take the first symbol value.
*/
if (table_cnt)
relative_base = table[0]->addr;
}
int main(int argc, char **argv)
{
while (1) {
static const struct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1},
{"pc-relative", no_argument, &pc_relative, 1},
{},
};
@ -734,7 +705,6 @@ int main(int argc, char **argv)
read_map(argv[optind]);
shrink_table();
sort_symbols();
record_relative_base();
optimize_token_table();
write_src();

View file

@ -201,7 +201,7 @@ $(addprefix $(obj)/, mconf.o $(lxdialog)): | $(obj)/mconf-cflags
# qconf: Used for the xconfig target based on Qt
hostprogs += qconf
qconf-cxxobjs := qconf.o qconf-moc.o
qconf-objs := images.o $(common-objs)
qconf-objs := $(common-objs)
HOSTLDLIBS_qconf = $(call read-file, $(obj)/qconf-libs)
HOSTCXXFLAGS_qconf.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags)
@ -219,7 +219,7 @@ targets += qconf-moc.cc
# gconf: Used for the gconfig target based on GTK+
hostprogs += gconf
gconf-objs := gconf.o images.o $(common-objs)
gconf-objs := gconf.o $(common-objs)
HOSTLDLIBS_gconf = $(call read-file, $(obj)/gconf-libs)
HOSTCFLAGS_gconf.o = $(call read-file, $(obj)/gconf-cflags)

View file

@ -5,7 +5,6 @@
#include <stdlib.h>
#include "lkc.h"
#include "images.h"
#include <gtk/gtk.h>
@ -951,12 +950,24 @@ static void fixup_rootmenu(struct menu *menu)
}
/* Main Window Initialization */
static void replace_button_icon(GtkWidget *widget, const char * const xpm[])
static void replace_button_icon(GtkWidget *widget, const char *filename)
{
GdkPixbuf *pixbuf;
GtkWidget *image;
GError *err = NULL;
char *env = getenv(SRCTREE);
gchar *path = g_strconcat(env ? env : g_get_current_dir(), "/scripts/kconfig/icons/", filename, NULL);
pixbuf = gdk_pixbuf_new_from_file(path, &err);
g_free(path);
if (err) {
g_warning("Failed to load icon %s: %s", filename, err->message);
g_error_free(err);
return;
}
pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)xpm);
image = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
@ -1078,17 +1089,17 @@ static void init_main_window(const gchar *glade_file)
single_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button4"));
g_signal_connect(single_btn, "clicked",
G_CALLBACK(on_single_clicked), NULL);
replace_button_icon(single_btn, xpm_single_view);
replace_button_icon(single_btn, "single_view.xpm");
split_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button5"));
g_signal_connect(split_btn, "clicked",
G_CALLBACK(on_split_clicked), NULL);
replace_button_icon(split_btn, xpm_split_view);
replace_button_icon(split_btn, "split_view.xpm");
full_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button6"));
g_signal_connect(full_btn, "clicked",
G_CALLBACK(on_full_clicked), NULL);
replace_button_icon(full_btn, xpm_tree_view);
replace_button_icon(full_btn, "tree_view.xpm");
widget = GTK_WIDGET(gtk_builder_get_object(builder, "button7"));
g_signal_connect(widget, "clicked",
@ -1269,7 +1280,17 @@ static void init_right_tree(void)
g_signal_connect(G_OBJECT(renderer), "edited",
G_CALLBACK(renderer_edited), tree2_w);
pix_menu = gdk_pixbuf_new_from_xpm_data((const char **)xpm_menu);
char *env = getenv(SRCTREE);
gchar *path = g_strconcat(env ? env : g_get_current_dir(), "/scripts/kconfig/icons/menu.xpm", NULL);
GError *err = NULL;
pix_menu = gdk_pixbuf_new_from_file(path, &err);
g_free(path);
if (err) {
g_warning("Failed to load menu icon: %s", err->message);
g_error_free(err);
}
for (i = 0; i < COL_VALUE; i++) {
column = gtk_tree_view_get_column(view, i);

View file

@ -0,0 +1,29 @@
/* XPM */
static char * back_xpm[] = {
"22 22 3 1",
". c None",
"# c #000083",
"a c #838183",
"......................",
"......................",
"......................",
"......................",
"......................",
"...........######a....",
"..#......##########...",
"..##...####......##a..",
"..###.###.........##..",
"..######..........##..",
"..#####...........##..",
"..######..........##..",
"..#######.........##..",
"..########.......##a..",
"...............a###...",
"...............###....",
"......................",
"......................",
"......................",
"......................",
"......................",
"......................"
};

View file

@ -0,0 +1,18 @@
/* XPM */
static char * choice_no_xpm[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .. .. ",
" .... ",
" "
};

View file

@ -0,0 +1,18 @@
/* XPM */
static char * choice_yes_xpm[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" .. .. ",
" .... ",
" "
};

View file

@ -0,0 +1,31 @@
/* XPM */
static char * load_xpm[] = {
"22 22 5 1",
". c None",
"# c #000000",
"c c #838100",
"a c #ffff00",
"b c #ffffff",
"......................",
"......................",
"......................",
"............####....#.",
"...........#....##.##.",
"..................###.",
".................####.",
".####...........#####.",
"#abab##########.......",
"#babababababab#.......",
"#ababababababa#.......",
"#babababababab#.......",
"#ababab###############",
"#babab##cccccccccccc##",
"#abab##cccccccccccc##.",
"#bab##cccccccccccc##..",
"#ab##cccccccccccc##...",
"#b##cccccccccccc##....",
"###cccccccccccc##.....",
"##cccccccccccc##......",
"###############.......",
"......................"
};

View file

@ -0,0 +1,18 @@
/* XPM */
static char * menu_xpm[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "
};

View file

@ -0,0 +1,18 @@
/* XPM */
static char * menuback_xpm[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "
};

View file

@ -0,0 +1,31 @@
/* XPM */
static char * save_xpm[] = {
"22 22 5 1",
". c None",
"# c #000000",
"a c #838100",
"b c #c5c2c5",
"c c #cdb6d5",
"......................",
".####################.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbcbb####.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aaa############aaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaa#############aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
"..##################..",
"......................"
};

View file

@ -0,0 +1,28 @@
/* XPM */
static char * single_view_xpm[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"......................",
"......................"
};

View file

@ -0,0 +1,28 @@
/* XPM */
static char * split_view_xpm[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......................",
"......................"
};

View file

@ -0,0 +1,18 @@
/* XPM */
static char * symbol_mod_xpm[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" . . ",
" .......... ",
" "
};

View file

@ -0,0 +1,18 @@
/* XPM */
static char * symbol_no_xpm[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .......... ",
" "
};

View file

@ -0,0 +1,18 @@
/* XPM */
static char * symbol_yes_xpm[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . . ",
" . .. . ",
" . . .. . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "
};

View file

@ -0,0 +1,28 @@
/* XPM */
static char * tree_view_xpm[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......................",
"......................"
};

View file

@ -1,328 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
*/
#include "images.h"
const char * const xpm_load[] = {
"22 22 5 1",
". c None",
"# c #000000",
"c c #838100",
"a c #ffff00",
"b c #ffffff",
"......................",
"......................",
"......................",
"............####....#.",
"...........#....##.##.",
"..................###.",
".................####.",
".####...........#####.",
"#abab##########.......",
"#babababababab#.......",
"#ababababababa#.......",
"#babababababab#.......",
"#ababab###############",
"#babab##cccccccccccc##",
"#abab##cccccccccccc##.",
"#bab##cccccccccccc##..",
"#ab##cccccccccccc##...",
"#b##cccccccccccc##....",
"###cccccccccccc##.....",
"##cccccccccccc##......",
"###############.......",
"......................"};
const char * const xpm_save[] = {
"22 22 5 1",
". c None",
"# c #000000",
"a c #838100",
"b c #c5c2c5",
"c c #cdb6d5",
"......................",
".####################.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbcbb####.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aaa############aaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaa#############aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
"..##################..",
"......................"};
const char * const xpm_back[] = {
"22 22 3 1",
". c None",
"# c #000083",
"a c #838183",
"......................",
"......................",
"......................",
"......................",
"......................",
"...........######a....",
"..#......##########...",
"..##...####......##a..",
"..###.###.........##..",
"..######..........##..",
"..#####...........##..",
"..######..........##..",
"..#######.........##..",
"..########.......##a..",
"...............a###...",
"...............###....",
"......................",
"......................",
"......................",
"......................",
"......................",
"......................"};
const char * const xpm_tree_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......................",
"......................"};
const char * const xpm_single_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"......................",
"......................"};
const char * const xpm_split_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......................",
"......................"};
const char * const xpm_symbol_no[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .......... ",
" "};
const char * const xpm_symbol_mod[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" . . ",
" .......... ",
" "};
const char * const xpm_symbol_yes[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . . ",
" . .. . ",
" . . .. . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
const char * const xpm_choice_no[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .. .. ",
" .... ",
" "};
const char * const xpm_choice_yes[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" .. .. ",
" .... ",
" "};
const char * const xpm_menu[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
const char * const xpm_menu_inv[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" .......... ",
" .. ...... ",
" .. .... ",
" .. .. ",
" .. .. ",
" .. .... ",
" .. ...... ",
" .......... ",
" .......... ",
" "};
const char * const xpm_menuback[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
const char * const xpm_void[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "};

View file

@ -1,33 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
*/
#ifndef IMAGES_H
#define IMAGES_H
#ifdef __cplusplus
extern "C" {
#endif
extern const char * const xpm_load[];
extern const char * const xpm_save[];
extern const char * const xpm_back[];
extern const char * const xpm_tree_view[];
extern const char * const xpm_single_view[];
extern const char * const xpm_split_view[];
extern const char * const xpm_symbol_no[];
extern const char * const xpm_symbol_mod[];
extern const char * const xpm_symbol_yes[];
extern const char * const xpm_choice_no[];
extern const char * const xpm_choice_yes[];
extern const char * const xpm_menu[];
extern const char * const xpm_menu_inv[];
extern const char * const xpm_menuback[];
extern const char * const xpm_void[];
#ifdef __cplusplus
}
#endif
#endif /* IMAGES_H */

View file

@ -82,7 +82,7 @@ void menu_warn(const struct menu *menu, const char *fmt, ...);
struct menu *menu_add_menu(void);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym, enum menu_type type);
void menu_add_dep(struct expr *dep);
void menu_add_dep(struct expr *dep, struct expr *cond);
void menu_add_visibility(struct expr *dep);
struct property *menu_add_prompt(enum prop_type type, const char *prompt,
struct expr *dep);

View file

@ -127,8 +127,18 @@ static struct expr *rewrite_m(struct expr *e)
return e;
}
void menu_add_dep(struct expr *dep)
void menu_add_dep(struct expr *dep, struct expr *cond)
{
if (cond) {
/*
* We have "depends on X if Y" and we want:
* Y != n --> X
* Y == n --> y
* That simplifies to: (X || (Y == n))
*/
dep = expr_alloc_or(dep,
expr_trans_compare(cond, E_EQUAL, &symbol_no));
}
current_entry->dep = expr_alloc_and(current_entry->dep, dep);
}

View file

@ -16,8 +16,8 @@
set -e
clean_up() {
rm -f $TMP_FILE
rm -f $MERGE_FILE
rm -f "$TMP_FILE"
rm -f "$TMP_FILE.new"
}
usage() {
@ -43,6 +43,10 @@ STRICT=false
CONFIG_PREFIX=${CONFIG_-CONFIG_}
WARNOVERRIDE=echo
if [ -z "$AWK" ]; then
AWK=awk
fi
while true; do
case $1 in
"-n")
@ -117,11 +121,8 @@ 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"
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX)
echo "Using $INITFILE as base"
@ -129,6 +130,8 @@ trap clean_up EXIT
cat $INITFILE > $TMP_FILE
PROCESSED_FILES=""
# Merge files, printing warnings on overridden values
for ORIG_MERGE_FILE in $MERGE_LIST ; do
echo "Merging $ORIG_MERGE_FILE"
@ -136,42 +139,138 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
exit 1
fi
cat $ORIG_MERGE_FILE > $MERGE_FILE
CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE)
for CFG in $CFG_LIST ; do
grep -q -w $CFG $TMP_FILE || continue
PREV_VAL=$(grep -w $CFG $TMP_FILE)
NEW_VAL=$(grep -w $CFG $MERGE_FILE)
BUILTIN_FLAG=false
if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
${WARNOVERRIDE} Previous value: $PREV_VAL
${WARNOVERRIDE} New value: $NEW_VAL
${WARNOVERRIDE} -y passed, will not demote y to m
${WARNOVERRIDE}
BUILTIN_FLAG=true
elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
${WARNOVERRIDE} Previous value: $PREV_VAL
${WARNOVERRIDE} New value: $NEW_VAL
${WARNOVERRIDE}
if [ "$STRICT" = "true" ]; then
# Check for duplicate input files
case " $PROCESSED_FILES " in
*" $ORIG_MERGE_FILE "*)
${WARNOVERRIDE} "WARNING: Input file provided multiple times: $ORIG_MERGE_FILE"
;;
esac
# Use awk for single-pass processing instead of per-symbol grep/sed
if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
-v warnoverride="$WARNOVERRIDE" \
-v strict="$STRICT" \
-v builtin="$BUILTIN" \
-v warnredun="$WARNREDUN" '
BEGIN {
strict_violated = 0
cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
}
# Extract config name from a line, returns "" if not a config line
function get_cfg(line) {
if (match(line, cfg_regex)) {
return substr(line, RSTART, RLENGTH)
} else if (match(line, notset_regex)) {
# Extract CONFIG_FOO from "# CONFIG_FOO is not set"
sub(/^# /, "", line)
sub(/ is not set$/, "", line)
return line
}
return ""
}
function warn_builtin(cfg, prev, new) {
if (warnoverride == "true") return
print cfg ": -y passed, will not demote y to m"
print "Previous value: " prev
print "New value: " new
print ""
}
function warn_redefined(cfg, prev, new) {
if (warnoverride == "true") return
print "Value of " cfg " is redefined by fragment " mergefile ":"
print "Previous value: " prev
print "New value: " new
print ""
}
function warn_redundant(cfg) {
if (warnredun != "true" || warnoverride == "true") return
print "Value of " cfg " is redundant by fragment " mergefile ":"
}
# First pass: read merge file, store all lines and index
FILENAME == ARGV[1] {
mergefile = FILENAME
merge_lines[FNR] = $0
merge_total = FNR
cfg = get_cfg($0)
if (cfg != "") {
merge_cfg[cfg] = $0
merge_cfg_line[cfg] = FNR
}
next
}
# Second pass: process base file (TMP_FILE)
FILENAME == ARGV[2] {
cfg = get_cfg($0)
# Not a config or not in merge file - keep it
if (cfg == "" || !(cfg in merge_cfg)) {
print $0 >> ARGV[3]
next
}
prev_val = $0
new_val = merge_cfg[cfg]
# BUILTIN: do not demote y to m
if (builtin == "true" && new_val ~ /=m$/ && prev_val ~ /=y$/) {
warn_builtin(cfg, prev_val, new_val)
print $0 >> ARGV[3]
skip_merge[merge_cfg_line[cfg]] = 1
next
}
# Values equal - redundant
if (prev_val == new_val) {
warn_redundant(cfg)
next
}
# "=n" is the same as "is not set"
if (prev_val ~ /=n$/ && new_val ~ / is not set$/) {
print $0 >> ARGV[3]
next
}
# Values differ - redefined
warn_redefined(cfg, prev_val, new_val)
if (strict == "true") {
strict_violated = 1
}
}
# output file, skip all lines
FILENAME == ARGV[3] {
nextfile
}
END {
# Newline in case base file lacks trailing newline
print "" >> ARGV[3]
# Append merge file, skipping lines marked for builtin preservation
for (i = 1; i <= merge_total; i++) {
if (!(i in skip_merge)) {
print merge_lines[i] >> ARGV[3]
}
}
if (strict_violated) {
exit 1
}
}' \
"$ORIG_MERGE_FILE" "$TMP_FILE" "$TMP_FILE.new"; then
# awk exited non-zero, strict mode was violated
STRICT_MODE_VIOLATED=true
fi
elif [ "$WARNREDUN" = "true" ]; then
${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
fi
if [ "$BUILTIN_FLAG" = "false" ]; then
sed -i "/$CFG[ =]/d" $TMP_FILE
else
sed -i "/$CFG[ =]/d" $MERGE_FILE
fi
done
# In case the previous file lacks a new line at the end
echo >> $TMP_FILE
cat $MERGE_FILE >> $TMP_FILE
mv "$TMP_FILE.new" "$TMP_FILE"
PROCESSED_FILES="$PROCESSED_FILES $ORIG_MERGE_FILE"
done
if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
echo "The fragment redefined a value and strict mode had been passed."
exit 1
@ -198,16 +297,91 @@ fi
# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
# Check all specified config values took effect (might have missed-dependency issues)
if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
-v warnoverride="$WARNOVERRIDE" \
-v strict="$STRICT" \
-v warnredun="$WARNREDUN" '
BEGIN {
strict_violated = 0
cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
}
# 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
# Extract config name from a line, returns "" if not a config line
function get_cfg(line) {
if (match(line, cfg_regex)) {
return substr(line, RSTART, RLENGTH)
} else if (match(line, notset_regex)) {
# Extract CONFIG_FOO from "# CONFIG_FOO is not set"
sub(/^# /, "", line)
sub(/ is not set$/, "", line)
return line
}
return ""
}
REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true)
if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
echo "Value requested for $CFG not in final .config"
echo "Requested value: $REQUESTED_VAL"
echo "Actual value: $ACTUAL_VAL"
echo ""
fi
done
function warn_mismatch(cfg, merged, final) {
if (warnredun == "true") return
if (final == "" && !(merged ~ / is not set$/ || merged ~ /=n$/)) {
print "WARNING: Value requested for " cfg " not in final .config"
print "Requested value: " merged
print "Actual value: " final
} else if (final == "" && merged ~ / is not set$/) {
# not set, pass
} else if (merged == "" && final != "") {
print "WARNING: " cfg " not in merged config but added in final .config:"
print "Requested value: " merged
print "Actual value: " final
} else {
print "WARNING: " cfg " differs:"
print "Requested value: " merged
print "Actual value: " final
}
}
# First pass: read effective config file, store all lines
FILENAME == ARGV[1] {
cfg = get_cfg($0)
if (cfg != "") {
config_cfg[cfg] = $0
}
next
}
# Second pass: process merged config and compare against effective config
{
cfg = get_cfg($0)
if (cfg == "") next
# strip trailing comment
sub(/[[:space:]]+#.*/, "", $0)
merged_val = $0
final_val = config_cfg[cfg]
if (merged_val == final_val) next
if (merged_val ~ /=n$/ && final_val ~ / is not set$/) next
if (merged_val ~ /=n$/ && final_val == "") next
warn_mismatch(cfg, merged_val, final_val)
if (strict == "true") {
strict_violated = 1
}
}
END {
if (strict_violated) {
exit 1
}
}' \
"$KCONFIG_CONFIG" "$TMP_FILE"; then
# awk exited non-zero, strict mode was violated
STRICT_MODE_VIOLATED=true
fi
if [ "$STRICT" == "true" ] && [ "$STRICT_MODE_VIOLATED" == "true" ]; then
echo "Requested and effective config differ"
exit 1
fi

View file

@ -323,7 +323,7 @@ if_entry: T_IF expr T_EOL
{
printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
menu_add_entry(NULL, M_IF);
menu_add_dep($2);
menu_add_dep($2, NULL);
$$ = menu_add_menu();
};
@ -422,9 +422,9 @@ help: help_start T_HELPTEXT
/* depends option */
depends: T_DEPENDS T_ON expr T_EOL
depends: T_DEPENDS T_ON expr if_expr T_EOL
{
menu_add_dep($3);
menu_add_dep($3, $4);
printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
};

View file

@ -26,8 +26,6 @@
#include "lkc.h"
#include "qconf.h"
#include "images.h"
static QApplication *configApp;
static ConfigSettings *configSettings;
@ -1283,13 +1281,14 @@ ConfigMainWindow::ConfigMainWindow(void)
move(x.toInt(), y.toInt());
// set up icons
ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes));
ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod));
ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no));
ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes));
ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no));
ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu));
ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
QString iconsDir = QString(getenv(SRCTREE) ? getenv(SRCTREE) : QDir::currentPath()) + "/scripts/kconfig/icons/";
ConfigItem::symbolYesIcon = QIcon(QPixmap(iconsDir + "symbol_yes.xpm"));
ConfigItem::symbolModIcon = QIcon(QPixmap(iconsDir + "symbol_mod.xpm"));
ConfigItem::symbolNoIcon = QIcon(QPixmap(iconsDir + "symbol_no.xpm"));
ConfigItem::choiceYesIcon = QIcon(QPixmap(iconsDir + "choice_yes.xpm"));
ConfigItem::choiceNoIcon = QIcon(QPixmap(iconsDir + "choice_no.xpm"));
ConfigItem::menuIcon = QIcon(QPixmap(iconsDir + "menu.xpm"));
ConfigItem::menubackIcon = QIcon(QPixmap(iconsDir + "menuback.xpm"));
QWidget *widget = new QWidget(this);
setCentralWidget(widget);
@ -1312,7 +1311,7 @@ ConfigMainWindow::ConfigMainWindow(void)
configList->setFocus();
backAction = new QAction(QPixmap(xpm_back), "Back", this);
backAction = new QAction(QPixmap(iconsDir + "back.xpm"), "Back", this);
backAction->setShortcut(QKeySequence::Back);
connect(backAction, &QAction::triggered,
this, &ConfigMainWindow::goBack);
@ -1322,12 +1321,12 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(quitAction, &QAction::triggered,
this, &ConfigMainWindow::close);
QAction *loadAction = new QAction(QPixmap(xpm_load), "&Open", this);
QAction *loadAction = new QAction(QPixmap(iconsDir + "load.xpm"), "&Open", this);
loadAction->setShortcut(QKeySequence::Open);
connect(loadAction, &QAction::triggered,
this, &ConfigMainWindow::loadConfig);
saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
saveAction = new QAction(QPixmap(iconsDir + "save.xpm"), "&Save", this);
saveAction->setShortcut(QKeySequence::Save);
connect(saveAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfig);
@ -1344,15 +1343,15 @@ ConfigMainWindow::ConfigMainWindow(void)
searchAction->setShortcut(QKeySequence::Find);
connect(searchAction, &QAction::triggered,
this, &ConfigMainWindow::searchConfig);
singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
singleViewAction = new QAction(QPixmap(iconsDir + "single_view.xpm"), "Single View", this);
singleViewAction->setCheckable(true);
connect(singleViewAction, &QAction::triggered,
this, &ConfigMainWindow::showSingleView);
splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
splitViewAction = new QAction(QPixmap(iconsDir + "split_view.xpm"), "Split View", this);
splitViewAction->setCheckable(true);
connect(splitViewAction, &QAction::triggered,
this, &ConfigMainWindow::showSplitView);
fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
fullViewAction = new QAction(QPixmap(iconsDir + "tree_view.xpm"), "Full View", this);
fullViewAction->setCheckable(true);
connect(fullViewAction, &QAction::triggered,
this, &ConfigMainWindow::showFullView);

View file

@ -415,7 +415,7 @@ foreach my $module (keys(%modules)) {
}
} else {
# Most likely, someone has a custom (binary?) module loaded.
print STDERR "$module config not found!!\n";
print STDERR "$module config not found!\n";
}
}

View file

@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0
# Test Kconfig file for conditional dependencies.
# Enable module support for tristate testing
config MODULES
bool "Enable loadable module support"
modules
default y
config FOO
bool "FOO symbol"
config BAR
bool "BAR symbol"
config TEST_BASIC
bool "Test basic conditional dependency"
depends on FOO if BAR
default y
config TEST_COMPLEX
bool "Test complex conditional dependency"
depends on (FOO && BAR) if (FOO || BAR)
default y
config BAZ
tristate "BAZ symbol"
config TEST_OPTIONAL
tristate "Test simple optional dependency"
depends on BAZ if BAZ
default y

View file

@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
"""
Correctly handle conditional dependencies.
"""
def test(conf):
assert conf.oldconfig('test_config1') == 0
assert conf.config_matches('expected_config1')
assert conf.oldconfig('test_config2') == 0
assert conf.config_matches('expected_config2')
assert conf.oldconfig('test_config3') == 0
assert conf.config_matches('expected_config3')

View file

@ -0,0 +1,11 @@
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
CONFIG_MODULES=y
CONFIG_FOO=y
CONFIG_BAR=y
CONFIG_TEST_BASIC=y
CONFIG_TEST_COMPLEX=y
CONFIG_BAZ=m
CONFIG_TEST_OPTIONAL=m

View file

@ -0,0 +1,9 @@
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
CONFIG_MODULES=y
# CONFIG_FOO is not set
CONFIG_BAR=y
CONFIG_BAZ=y
CONFIG_TEST_OPTIONAL=y

View file

@ -0,0 +1,11 @@
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
CONFIG_MODULES=y
# CONFIG_FOO is not set
# CONFIG_BAR is not set
CONFIG_TEST_BASIC=y
CONFIG_TEST_COMPLEX=y
# CONFIG_BAZ is not set
CONFIG_TEST_OPTIONAL=y

View file

@ -0,0 +1,6 @@
# Basic check that everything can be configured if selected.
CONFIG_FOO=y
CONFIG_BAR=y
CONFIG_BAZ=m
# Ensure that TEST_OPTIONAL=y with BAZ=m is converted to TEST_OPTIONAL=m
CONFIG_TEST_OPTIONAL=y

View file

@ -0,0 +1,7 @@
# If FOO is not selected, then TEST_BASIC should fail the conditional
# dependency since BAR is set.
# TEST_COMPLEX will fail dependency as it depends on both FOO and BAR
# if either of those is selected.
CONFIG_FOO=n
CONFIG_BAR=y
CONFIG_BAZ=y

View file

@ -0,0 +1,6 @@
# If FOO is not selected, but BAR is also not selected, then TEST_BASIC
# should pass since the dependency on FOO is conditional on BAR.
# TEST_COMPLEX should be also set since neither FOO nor BAR are selected
# so it has no dependencies.
CONFIG_FOO=n
CONFIG_BAR=n

View file

@ -143,6 +143,10 @@ kallsyms()
kallsymopt="${kallsymopt} --all-symbols"
fi
if is_enabled CONFIG_64BIT || is_enabled CONFIG_RELOCATABLE; then
kallsymopt="${kallsymopt} --pc-relative"
fi
info KSYMS "${2}.S"
scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S"

View file

@ -10,10 +10,14 @@
Usage:
make_fit.py -A arm64 -n 'Linux-6.6' -O linux
-o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk
@arch/arm64/boot/dts/dtbs-list -E -c gzip
-r /boot/initrd.img-6.14.0-27-generic @arch/arm64/boot/dts/dtbs-list
-E -c gzip
Creates a FIT containing the supplied kernel and a set of devicetree files,
either specified individually or listed in a file (with an '@' prefix).
Creates a FIT containing the supplied kernel, an optional ramdisk, and a set of
devicetree files, either specified individually or listed in a file (with an
'@' prefix).
Use -r to specify an existing ramdisk/initrd file.
Use -E to generate an external FIT (where the data is placed after the
FIT data structure). This allows parsing of the data without loading
@ -29,12 +33,11 @@ looks at the .cmd files produced by the kernel build.
The resulting FIT can be booted by bootloaders which support FIT, such
as U-Boot, Linuxboot, Tianocore, etc.
Note that this tool does not yet support adding a ramdisk / initrd.
"""
import argparse
import collections
import multiprocessing
import os
import subprocess
import sys
@ -48,11 +51,12 @@ import libfdt
CompTool = collections.namedtuple('CompTool', 'ext,tools')
COMP_TOOLS = {
'bzip2': CompTool('.bz2', 'bzip2'),
'bzip2': CompTool('.bz2', 'pbzip2,bzip2'),
'gzip': CompTool('.gz', 'pigz,gzip'),
'lz4': CompTool('.lz4', 'lz4'),
'lzma': CompTool('.lzma', 'lzma'),
'lzma': CompTool('.lzma', 'plzip,lzma'),
'lzo': CompTool('.lzo', 'lzop'),
'xz': CompTool('.xz', 'xz'),
'zstd': CompTool('.zstd', 'zstd'),
}
@ -81,6 +85,8 @@ def parse_args():
help='Specifies the operating system')
parser.add_argument('-k', '--kernel', type=str, required=True,
help='Specifies the (uncompressed) kernel input file (.itk)')
parser.add_argument('-r', '--ramdisk', type=str,
help='Specifies the ramdisk/initrd input file')
parser.add_argument('-v', '--verbose', action='store_true',
help='Enable verbose output')
parser.add_argument('dtbs', type=str, nargs='*',
@ -98,7 +104,7 @@ def setup_fit(fsw, name):
fsw (libfdt.FdtSw): Object to use for writing
name (str): Name of kernel image
"""
fsw.INC_SIZE = 65536
fsw.INC_SIZE = 16 << 20
fsw.finish_reservemap()
fsw.begin_node('')
fsw.property_string('description', f'{name} with devicetree set')
@ -133,7 +139,28 @@ def write_kernel(fsw, data, args):
fsw.property_u32('entry', 0)
def finish_fit(fsw, entries):
def write_ramdisk(fsw, data, args):
"""Write out the ramdisk image
Writes a ramdisk node along with the required properties
Args:
fsw (libfdt.FdtSw): Object to use for writing
data (bytes): Data to write (possibly compressed)
args (Namespace): Contains necessary strings:
arch: FIT architecture, e.g. 'arm64'
fit_os: Operating Systems, e.g. 'linux'
"""
with fsw.add_node('ramdisk'):
fsw.property_string('description', 'Ramdisk')
fsw.property_string('type', 'ramdisk')
fsw.property_string('arch', args.arch)
fsw.property_string('compression', 'none')
fsw.property_string('os', args.os)
fsw.property('data', data)
def finish_fit(fsw, entries, has_ramdisk=False):
"""Finish the FIT ready for use
Writes the /configurations node and subnodes
@ -143,6 +170,7 @@ def finish_fit(fsw, entries):
entries (list of tuple): List of configurations:
str: Description of model
str: Compatible stringlist
has_ramdisk (bool): True if a ramdisk is included in the FIT
"""
fsw.end_node()
seq = 0
@ -154,6 +182,8 @@ def finish_fit(fsw, entries):
fsw.property_string('description', model)
fsw.property('fdt', bytes(''.join(f'fdt-{x}\x00' for x in files), "ascii"))
fsw.property_string('kernel', 'kernel')
if has_ramdisk:
fsw.property_string('ramdisk', 'ramdisk')
fsw.end_node()
@ -179,7 +209,12 @@ def compress_data(inf, compress):
done = False
for tool in comp.tools.split(','):
try:
subprocess.call([tool, '-c'], stdin=inf, stdout=outf)
# Add parallel flags for tools that support them
cmd = [tool]
if tool in ('zstd', 'xz'):
cmd.extend(['-T0']) # Use all available cores
cmd.append('-c')
subprocess.call(cmd, stdin=inf, stdout=outf)
done = True
break
except FileNotFoundError:
@ -191,15 +226,31 @@ def compress_data(inf, compress):
return comp_data
def output_dtb(fsw, seq, fname, arch, compress):
def compress_dtb(fname, compress):
"""Compress a single DTB file
Args:
fname (str): Filename containing the DTB
compress (str): Compression algorithm, e.g. 'gzip'
Returns:
tuple: (str: fname, bytes: compressed_data)
"""
with open(fname, 'rb') as inf:
compressed = compress_data(inf, compress)
return fname, compressed
def output_dtb(fsw, seq, fname, arch, compress, data=None):
"""Write out a single devicetree to the FIT
Args:
fsw (libfdt.FdtSw): Object to use for writing
seq (int): Sequence number (1 for first)
fname (str): Filename containing the DTB
arch: FIT architecture, e.g. 'arm64'
arch (str): FIT architecture, e.g. 'arm64'
compress (str): Compressed algorithm, e.g. 'gzip'
data (bytes): Pre-compressed data (optional)
"""
with fsw.add_node(f'fdt-{seq}'):
fsw.property_string('description', os.path.basename(fname))
@ -207,9 +258,10 @@ def output_dtb(fsw, seq, fname, arch, compress):
fsw.property_string('arch', arch)
fsw.property_string('compression', compress)
if data is None:
with open(fname, 'rb') as inf:
compressed = compress_data(inf, compress)
fsw.property('data', compressed)
data = compress_data(inf, compress)
fsw.property('data', data)
def process_dtb(fname, args):
@ -249,6 +301,73 @@ def process_dtb(fname, args):
return (model, compat, files)
def _process_dtbs(args, fsw, entries, fdts):
"""Process all DTB files and add them to the FIT
Args:
args: Program arguments
fsw: FIT writer object
entries: List to append entries to
fdts: Dictionary of processed DTBs
Returns:
tuple:
Number of files processed
Total size of files processed
"""
seq = 0
size = 0
# First figure out the unique DTB files that need compression
todo = []
file_info = [] # List of (fname, model, compat, files) tuples
for fname in args.dtbs:
# Ignore non-DTB (*.dtb) files
if os.path.splitext(fname)[1] != '.dtb':
continue
try:
(model, compat, files) = process_dtb(fname, args)
except Exception as e:
sys.stderr.write(f'Error processing {fname}:\n')
raise e
file_info.append((fname, model, compat, files))
for fn in files:
if fn not in fdts and fn not in todo:
todo.append(fn)
# Compress all DTBs in parallel
cache = {}
if todo and args.compress != 'none':
if args.verbose:
print(f'Compressing {len(todo)} DTBs...')
with multiprocessing.Pool() as pool:
compress_args = [(fn, args.compress) for fn in todo]
# unpacks each tuple, calls compress_dtb(fn, compress) in parallel
results = pool.starmap(compress_dtb, compress_args)
cache = dict(results)
# Now write all DTBs to the FIT using pre-compressed data
for fname, model, compat, files in file_info:
for fn in files:
if fn not in fdts:
seq += 1
size += os.path.getsize(fn)
output_dtb(fsw, seq, fn, args.arch, args.compress,
cache.get(fn))
fdts[fn] = seq
files_seq = [fdts[fn] for fn in files]
entries.append([model, compat, files_seq])
return seq, size
def build_fit(args):
"""Build the FIT from the provided files and arguments
@ -261,7 +380,6 @@ def build_fit(args):
int: Number of configurations generated
size: Total uncompressed size of data
"""
seq = 0
size = 0
fsw = libfdt.FdtSw()
setup_fit(fsw, args.name)
@ -274,32 +392,23 @@ def build_fit(args):
size += os.path.getsize(args.kernel)
write_kernel(fsw, comp_data, args)
for fname in args.dtbs:
# Ignore non-DTB (*.dtb) files
if os.path.splitext(fname)[1] != '.dtb':
continue
# Handle the ramdisk if provided. Compression is not supported as it is
# already compressed.
if args.ramdisk:
with open(args.ramdisk, 'rb') as inf:
data = inf.read()
size += len(data)
write_ramdisk(fsw, data, args)
try:
(model, compat, files) = process_dtb(fname, args)
except Exception as e:
sys.stderr.write(f"Error processing {fname}:\n")
raise e
count, fdt_size = _process_dtbs(args, fsw, entries, fdts)
size += fdt_size
for fn in files:
if fn not in fdts:
seq += 1
size += os.path.getsize(fn)
output_dtb(fsw, seq, fn, args.arch, args.compress)
fdts[fn] = seq
files_seq = [fdts[fn] for fn in files]
entries.append([model, compat, files_seq])
finish_fit(fsw, entries)
finish_fit(fsw, entries, bool(args.ramdisk))
# Include the kernel itself in the returned file count
return fsw.as_fdt().as_bytearray(), seq + 1, size
fdt = fsw.as_fdt()
fdt.pack()
return fdt.as_bytearray(), count + 1 + bool(args.ramdisk), size
def run_make_fit():

View file

@ -602,6 +602,10 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
/* Special register function linked on all modules during final link of .ko */
if (strstarts(symname, "_restgpr0_") ||
strstarts(symname, "_savegpr0_") ||
strstarts(symname, "_restgpr1_") ||
strstarts(symname, "_savegpr1_") ||
strstarts(symname, "_restfpr_") ||
strstarts(symname, "_savefpr_") ||
strstarts(symname, "_restvr_") ||
strstarts(symname, "_savevr_") ||
strcmp(symname, ".TOC.") == 0)
@ -958,7 +962,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", "*_probe", "*_console")))
match(fromsym, PATTERNS("*_ops", "*_console")))
return 0;
/* Check for pattern 3 */

View file

@ -27,7 +27,6 @@ static bool is_ignored_symbol(const char *name, char type)
* stable symbol list.
*/
"kallsyms_offsets",
"kallsyms_relative_base",
"kallsyms_num_syms",
"kallsyms_names",
"kallsyms_markers",

View file

@ -65,16 +65,101 @@ no-header-test += asm/uctx.h
no-header-test += asm/fbio.h
endif
ifeq ($(SRCARCH),xtensa)
no-header-test += linux/bpf_perf_event.h
endif
# asm-generic/*.h is used by asm/*.h, and should not be included directly
no-header-test += asm-generic/%
# The following are using libc header and types.
#
# Do not add a new header to the list without legitimate reason.
# Please consider to fix the header first.
#
# Sorted alphabetically.
uses-libc += linux/a.out.h
uses-libc += linux/atmbr2684.h
uses-libc += linux/auto_dev-ioctl.h
uses-libc += linux/auto_fs.h
uses-libc += linux/auto_fs4.h
uses-libc += linux/btrfs_tree.h
uses-libc += linux/cec-funcs.h
uses-libc += linux/cec.h
uses-libc += linux/dvb/dmx.h
uses-libc += linux/dvb/video.h
uses-libc += linux/ethtool.h
uses-libc += linux/ethtool_netlink.h
uses-libc += linux/fuse.h
uses-libc += linux/gsmmux.h
uses-libc += linux/icmp.h
uses-libc += linux/idxd.h
uses-libc += linux/if.h
uses-libc += linux/if_arp.h
uses-libc += linux/if_bonding.h
uses-libc += linux/if_pppox.h
uses-libc += linux/if_tunnel.h
uses-libc += linux/input.h
uses-libc += linux/ip6_tunnel.h
uses-libc += linux/joystick.h
uses-libc += linux/llc.h
uses-libc += linux/mctp.h
uses-libc += linux/mdio.h
uses-libc += linux/mii.h
uses-libc += linux/mptcp.h
uses-libc += linux/netdevice.h
uses-libc += linux/netfilter/xt_RATEEST.h
uses-libc += linux/netfilter/xt_hashlimit.h
uses-libc += linux/netfilter/xt_physdev.h
uses-libc += linux/netfilter/xt_rateest.h
uses-libc += linux/netfilter_arp/arp_tables.h
uses-libc += linux/netfilter_arp/arpt_mangle.h
uses-libc += linux/netfilter_bridge.h
uses-libc += linux/netfilter_bridge/ebtables.h
uses-libc += linux/netfilter_ipv4.h
uses-libc += linux/netfilter_ipv4/ip_tables.h
uses-libc += linux/netfilter_ipv6.h
uses-libc += linux/netfilter_ipv6/ip6_tables.h
uses-libc += linux/route.h
uses-libc += linux/shm.h
uses-libc += linux/soundcard.h
uses-libc += linux/string.h
uses-libc += linux/tipc_config.h
uses-libc += linux/uhid.h
uses-libc += linux/uinput.h
uses-libc += linux/vhost.h
uses-libc += linux/vhost_types.h
uses-libc += linux/virtio_ring.h
uses-libc += linux/wireless.h
uses-libc += regulator/regulator.h
uses-libc += scsi/fc/fc_els.h
ifeq ($(SRCARCH),hexagon)
uses-libc += asm/sigcontext.h
endif
ifeq ($(SRCARCH),nios2)
uses-libc += asm/ptrace.h
uses-libc += linux/bpf_perf_event.h
endif
ifeq ($(SRCARCH),s390)
uses-libc += asm/chpid.h
uses-libc += asm/chsc.h
endif
always-y := $(patsubst $(obj)/%.h,%.hdrtest, $(shell find $(obj) -name '*.h' 2>/dev/null))
target-no-libc = $(filter-out $(uses-libc), $*.h)
target-can-compile = $(and $(filter-out $(no-header-test), $*.h), \
$(or $(CONFIG_CC_CAN_LINK), $(target-no-libc)))
# Include the header twice to detect missing include guard.
quiet_cmd_hdrtest = HDRTEST $<
cmd_hdrtest = \
$(CC) $(c_flags) -fsyntax-only -Werror -x c /dev/null \
$(if $(filter-out $(no-header-test), $*.h), -include $< -include $<); \
$(if $(target-no-libc), -nostdinc) \
$(if $(target-can-compile), -include $< -include $<); \
$(PERL) $(src)/headers_check.pl $(obj) $<; \
touch $@

View file

@ -40,7 +40,6 @@ foreach my $file (@files) {
&check_include();
&check_asm_types();
&check_declarations();
# Dropped for now. Too much noise &check_config();
}
close $fh;
}
@ -77,13 +76,6 @@ sub check_declarations
}
}
sub check_config
{
if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
}
}
my $linux_asm_types;
sub check_asm_types
{