Commit ca83c61c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'kbuild-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild

Pull Kbuild updates from Masahiro Yamada:

 - Remove tristate choice support from Kconfig

 - Stop using the PROVIDE() directive in the linker script

 - Reduce the number of links for the combination of CONFIG_KALLSYMS and
   CONFIG_DEBUG_INFO_BTF

 - Enable the warning for symbol reference to .exit.* sections by
   default

 - Fix warnings in RPM package builds

 - Improve scripts/make_fit.py to generate a FIT image with separate
   base DTB and overlays

 - Improve choice value calculation in Kconfig

 - Fix conditional prompt behavior in choice in Kconfig

 - Remove support for the uncommon EMAIL environment variable in Debian
   package builds

 - Remove support for the uncommon "name <email>" form for the DEBEMAIL
   environment variable

 - Raise the minimum supported GNU Make version to 4.0

 - Remove stale code for the absolute kallsyms

 - Move header files commonly used for host programs to scripts/include/

 - Introduce the pacman-pkg target to generate a pacman package used in
   Arch Linux

 - Clean up Kconfig

* tag 'kbuild-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild: (65 commits)
  kbuild: doc: gcc to CC change
  kallsyms: change sym_entry::percpu_absolute to bool type
  kallsyms: unify seq and start_pos fields of struct sym_entry
  kallsyms: add more original symbol type/name in comment lines
  kallsyms: use \t instead of a tab in printf()
  kallsyms: avoid repeated calculation of array size for markers
  kbuild: add script and target to generate pacman package
  modpost: use generic macros for hash table implementation
  kbuild: move some helper headers from scripts/kconfig/ to scripts/include/
  Makefile: add comment to discourage tools/* addition for kernel builds
  kbuild: clean up scripts/remove-stale-files
  kconfig: recursive checks drop file/lineno
  kbuild: rpm-pkg: introduce a simple changelog section for kernel.spec
  kallsyms: get rid of code for absolute kallsyms
  kbuild: Create INSTALL_PATH directory if it does not exist
  kbuild: Abort make on install failures
  kconfig: remove 'e1' and 'e2' macros from expression deduplication
  kconfig: remove SYMBOL_CHOICEVAL flag
  kconfig: add const qualifiers to several function arguments
  kconfig: call expr_eliminate_yn() at least once in expr_eliminate_dups()
  ...
parents 643af93f 13c239a2
...@@ -92,6 +92,12 @@ modules.order ...@@ -92,6 +92,12 @@ modules.order
# #
/tar-install/ /tar-install/
#
# pacman files (make pacman-pkg)
#
/PKGBUILD
/pacman/
# #
# We don't want to ignore the following even if they are dot-files # We don't want to ignore the following even if they are dot-files
# #
......
...@@ -409,16 +409,9 @@ choices:: ...@@ -409,16 +409,9 @@ choices::
"endchoice" "endchoice"
This defines a choice group and accepts any of the above attributes as This defines a choice group and accepts any of the above attributes as
options. A choice can only be of type bool or tristate. If no type is options.
specified for a choice, its type will be determined by the type of
the first choice element in the group or remain unknown if none of the A choice only allows a single config entry to be selected.
choice elements have a type specified, as well.
While a boolean choice only allows a single config entry to be
selected, a tristate choice also allows any number of config entries
to be set to 'm'. This can be used if multiple drivers for a single
hardware exists and only a single driver can be compiled/loaded into
the kernel, but all drivers can be compiled as modules.
comment:: comment::
......
...@@ -578,7 +578,7 @@ cc-option ...@@ -578,7 +578,7 @@ cc-option
Note: cc-option uses KBUILD_CFLAGS for $(CC) options Note: cc-option uses KBUILD_CFLAGS for $(CC) options
cc-option-yn cc-option-yn
cc-option-yn is used to check if gcc supports a given option cc-option-yn is used to check if $(CC) supports a given option
and return "y" if supported, otherwise "n". and return "y" if supported, otherwise "n".
Example:: Example::
...@@ -596,7 +596,7 @@ cc-option-yn ...@@ -596,7 +596,7 @@ cc-option-yn
Note: cc-option-yn uses KBUILD_CFLAGS for $(CC) options Note: cc-option-yn uses KBUILD_CFLAGS for $(CC) options
cc-disable-warning cc-disable-warning
cc-disable-warning checks if gcc supports a given warning and returns cc-disable-warning checks if $(CC) supports a given warning and returns
the commandline switch to disable it. This special function is needed, the commandline switch to disable it. This special function is needed,
because gcc 4.4 and later accept any unknown -Wno-* option and only because gcc 4.4 and later accept any unknown -Wno-* option and only
warn about it if there is another warning in the source file. warn about it if there is another warning in the source file.
...@@ -606,7 +606,7 @@ cc-disable-warning ...@@ -606,7 +606,7 @@ cc-disable-warning
KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
In the above example, -Wno-unused-but-set-variable will be added to In the above example, -Wno-unused-but-set-variable will be added to
KBUILD_CFLAGS only if gcc really accepts it. KBUILD_CFLAGS only if $(CC) really accepts it.
gcc-min-version gcc-min-version
gcc-min-version tests if the value of $(CONFIG_GCC_VERSION) is greater than gcc-min-version tests if the value of $(CONFIG_GCC_VERSION) is greater than
......
...@@ -33,7 +33,7 @@ GNU C 5.1 gcc --version ...@@ -33,7 +33,7 @@ GNU C 5.1 gcc --version
Clang/LLVM (optional) 13.0.1 clang --version Clang/LLVM (optional) 13.0.1 clang --version
Rust (optional) 1.78.0 rustc --version Rust (optional) 1.78.0 rustc --version
bindgen (optional) 0.65.1 bindgen --version bindgen (optional) 0.65.1 bindgen --version
GNU make 3.82 make --version GNU make 4.0 make --version
bash 4.2 bash --version bash 4.2 bash --version
binutils 2.25 ld -v binutils 2.25 ld -v
flex 2.5.35 flex --version flex 2.5.35 flex --version
...@@ -112,7 +112,7 @@ It depends on ``libclang``. ...@@ -112,7 +112,7 @@ It depends on ``libclang``.
Make Make
---- ----
You will need GNU make 3.82 or later to build the kernel. You will need GNU make 4.0 or later to build the kernel.
Bash Bash
---- ----
......
...@@ -12117,6 +12117,7 @@ F: scripts/Makefile* ...@@ -12117,6 +12117,7 @@ F: scripts/Makefile*
F: scripts/basic/ F: scripts/basic/
F: scripts/clang-tools/ F: scripts/clang-tools/
F: scripts/dummy-tools/ F: scripts/dummy-tools/
F: scripts/include/
F: scripts/mk* F: scripts/mk*
F: scripts/mod/ F: scripts/mod/
F: scripts/package/ F: scripts/package/
...@@ -12172,6 +12173,13 @@ F: include/uapi/linux/nfsd/ ...@@ -12172,6 +12173,13 @@ F: include/uapi/linux/nfsd/
F: include/uapi/linux/sunrpc/ F: include/uapi/linux/sunrpc/
F: net/sunrpc/ F: net/sunrpc/
KERNEL PACMAN PACKAGING (in addition to generic KERNEL BUILD)
M: Thomas Weißschuh <linux@weissschuh.net>
R: Christian Heusel <christian@heusel.eu>
R: Nathan Chancellor <nathan@kernel.org>
S: Maintained
F: scripts/package/PKGBUILD
KERNEL REGRESSIONS KERNEL REGRESSIONS
M: Thorsten Leemhuis <linux@leemhuis.info> M: Thorsten Leemhuis <linux@leemhuis.info>
L: regressions@lists.linux.dev L: regressions@lists.linux.dev
......
...@@ -11,8 +11,8 @@ NAME = Baby Opossum Posse ...@@ -11,8 +11,8 @@ NAME = Baby Opossum Posse
# Comments in this file are targeted only to the developer, do not # Comments in this file are targeted only to the developer, do not
# expect to learn how to build the kernel reading this file. # expect to learn how to build the kernel reading this file.
ifeq ($(filter undefine,$(.FEATURES)),) ifeq ($(filter output-sync,$(.FEATURES)),)
$(error GNU Make >= 3.82 is required. Your Make version is $(MAKE_VERSION)) $(error GNU Make >= 4.0 is required. Your Make version is $(MAKE_VERSION))
endif endif
$(if $(filter __%, $(MAKECMDGOALS)), \ $(if $(filter __%, $(MAKECMDGOALS)), \
...@@ -93,15 +93,7 @@ endif ...@@ -93,15 +93,7 @@ endif
# If the user is running make -s (silent mode), suppress echoing of # If the user is running make -s (silent mode), suppress echoing of
# commands # commands
# make-4.0 (and later) keep single letter options in the 1st word of MAKEFLAGS. ifneq ($(findstring s,$(firstword -$(MAKEFLAGS))),)
ifeq ($(filter 3.%,$(MAKE_VERSION)),)
short-opts := $(firstword -$(MAKEFLAGS))
else
short-opts := $(filter-out --%,$(MAKEFLAGS))
endif
ifneq ($(findstring s,$(short-opts)),)
quiet=silent_ quiet=silent_
override KBUILD_VERBOSE := override KBUILD_VERBOSE :=
endif endif
...@@ -201,14 +193,6 @@ ifneq ($(words $(subst :, ,$(abs_srctree))), 1) ...@@ -201,14 +193,6 @@ ifneq ($(words $(subst :, ,$(abs_srctree))), 1)
$(error source directory cannot contain spaces or colons) $(error source directory cannot contain spaces or colons)
endif endif
ifneq ($(filter 3.%,$(MAKE_VERSION)),)
# 'MAKEFLAGS += -rR' does not immediately become effective for GNU Make 3.x
# We need to invoke sub-make to avoid implicit rules in the top Makefile.
need-sub-make := 1
# Cancel implicit rules for this Makefile.
$(this-makefile): ;
endif
export sub_make_done := 1 export sub_make_done := 1
endif # sub_make_done endif # sub_make_done
...@@ -474,8 +458,10 @@ export rust_common_flags := --edition=2021 \ ...@@ -474,8 +458,10 @@ export rust_common_flags := --edition=2021 \
-Dclippy::no_mangle_with_rust_abi \ -Dclippy::no_mangle_with_rust_abi \
-Wclippy::dbg_macro -Wclippy::dbg_macro
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS) KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \
KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS) $(HOSTCFLAGS) -I $(srctree)/scripts/include
KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS) \
-I $(srctree)/scripts/include
KBUILD_HOSTRUSTFLAGS := $(rust_common_flags) -O -Cstrip=debuginfo \ KBUILD_HOSTRUSTFLAGS := $(rust_common_flags) -O -Cstrip=debuginfo \
-Zallow-features= $(HOSTRUSTFLAGS) -Zallow-features= $(HOSTRUSTFLAGS)
KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS) KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
...@@ -1344,6 +1330,12 @@ prepare: tools/bpf/resolve_btfids ...@@ -1344,6 +1330,12 @@ prepare: tools/bpf/resolve_btfids
endif endif
endif endif
# The tools build system is not a part of Kbuild and tends to introduce
# its own unique issues. If you need to integrate a new tool into Kbuild,
# please consider locating that tool outside the tools/ tree and using the
# standard Kbuild "hostprogs" syntax instead of adding a new tools/* entry
# here. See Documentation/kbuild/makefiles.rst for details.
PHONY += resolve_btfids_clean PHONY += resolve_btfids_clean
resolve_btfids_O = $(abspath $(objtree))/tools/bpf/resolve_btfids resolve_btfids_O = $(abspath $(objtree))/tools/bpf/resolve_btfids
...@@ -1497,7 +1489,7 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \ ...@@ -1497,7 +1489,7 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \
# Directories & files removed with 'make mrproper' # Directories & files removed with 'make mrproper'
MRPROPER_FILES += include/config include/generated \ MRPROPER_FILES += include/config include/generated \
arch/$(SRCARCH)/include/generated .objdiff \ arch/$(SRCARCH)/include/generated .objdiff \
debian snap tar-install \ debian snap tar-install PKGBUILD pacman \
.config .config.old .version \ .config .config.old .version \
Module.symvers \ Module.symvers \
certs/signing_key.pem \ certs/signing_key.pem \
......
...@@ -1483,7 +1483,8 @@ config ARM_ATAG_DTB_COMPAT ...@@ -1483,7 +1483,8 @@ config ARM_ATAG_DTB_COMPAT
from the ATAG list and store it at run time into the appended DTB. from the ATAG list and store it at run time into the appended DTB.
choice choice
prompt "Kernel command line type" if ARM_ATAG_DTB_COMPAT prompt "Kernel command line type"
depends on ARM_ATAG_DTB_COMPAT
default ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER default ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER
config ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER config ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER
...@@ -1512,7 +1513,8 @@ config CMDLINE ...@@ -1512,7 +1513,8 @@ config CMDLINE
memory size and the root device (e.g., mem=64M root=/dev/nfs). memory size and the root device (e.g., mem=64M root=/dev/nfs).
choice choice
prompt "Kernel command line type" if CMDLINE != "" prompt "Kernel command line type"
depends on CMDLINE != ""
default CMDLINE_FROM_BOOTLOADER default CMDLINE_FROM_BOOTLOADER
config CMDLINE_FROM_BOOTLOADER config CMDLINE_FROM_BOOTLOADER
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
if [ "$(basename $2)" = "zImage" ]; then if [ "$(basename $2)" = "zImage" ]; then
# Compressed install # Compressed install
echo "Installing compressed kernel" echo "Installing compressed kernel"
......
...@@ -2290,7 +2290,8 @@ config CMDLINE ...@@ -2290,7 +2290,8 @@ config CMDLINE
root device (e.g. root=/dev/nfs). root device (e.g. root=/dev/nfs).
choice choice
prompt "Kernel command line type" if CMDLINE != "" prompt "Kernel command line type"
depends on CMDLINE != ""
default CMDLINE_FROM_BOOTLOADER default CMDLINE_FROM_BOOTLOADER
help help
Choose how the kernel will handle the provided default kernel Choose how the kernel will handle the provided default kernel
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
if [ "$(basename $2)" = "Image.gz" ] || [ "$(basename $2)" = "vmlinuz.efi" ] if [ "$(basename $2)" = "Image.gz" ] || [ "$(basename $2)" = "vmlinuz.efi" ]
then then
# Compressed install # Compressed install
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old mv $4/vmlinuz $4/vmlinuz.old
fi fi
......
...@@ -2927,7 +2927,8 @@ config BUILTIN_DTB ...@@ -2927,7 +2927,8 @@ config BUILTIN_DTB
bool bool
choice choice
prompt "Kernel appended dtb support" if USE_OF prompt "Kernel appended dtb support"
depends on USE_OF
default MIPS_NO_APPENDED_DTB default MIPS_NO_APPENDED_DTB
config MIPS_NO_APPENDED_DTB config MIPS_NO_APPENDED_DTB
...@@ -2968,7 +2969,8 @@ choice ...@@ -2968,7 +2969,8 @@ choice
endchoice endchoice
choice choice
prompt "Kernel command line type" if !CMDLINE_OVERRIDE prompt "Kernel command line type"
depends on !CMDLINE_OVERRIDE
default MIPS_CMDLINE_FROM_DTB if USE_OF && !ATH79 && !MACH_INGENIC && \ default MIPS_CMDLINE_FROM_DTB if USE_OF && !ATH79 && !MACH_INGENIC && \
!MACH_LOONGSON64 && !MIPS_MALTA && \ !MACH_LOONGSON64 && !MIPS_MALTA && \
!CAVIUM_OCTEON_SOC !CAVIUM_OCTEON_SOC
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old mv $4/vmlinuz $4/vmlinuz.old
fi fi
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
if [ "$(basename $2)" = "vmlinuz" ]; then if [ "$(basename $2)" = "vmlinuz" ]; then
# Compressed install # Compressed install
echo "Installing compressed kernel" echo "Installing compressed kernel"
......
...@@ -964,7 +964,8 @@ config CMDLINE ...@@ -964,7 +964,8 @@ config CMDLINE
most cases you will need to specify the root device here. most cases you will need to specify the root device here.
choice choice
prompt "Kernel command line type" if CMDLINE != "" prompt "Kernel command line type"
depends on CMDLINE != ""
default CMDLINE_FROM_BOOTLOADER default CMDLINE_FROM_BOOTLOADER
config CMDLINE_FROM_BOOTLOADER config CMDLINE_FROM_BOOTLOADER
......
...@@ -960,7 +960,8 @@ config CMDLINE ...@@ -960,7 +960,8 @@ config CMDLINE
line here and choose how the kernel should use it later on. line here and choose how the kernel should use it later on.
choice choice
prompt "Built-in command line usage" if CMDLINE != "" prompt "Built-in command line usage"
depends on CMDLINE != ""
default CMDLINE_FALLBACK default CMDLINE_FALLBACK
help help
Choose how the kernel will handle the provided built-in command Choose how the kernel will handle the provided built-in command
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
case "${2##*/}" in case "${2##*/}" in
# Compressed install # Compressed install
Image.*|vmlinuz.efi) Image.*|vmlinuz.efi)
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
echo "Warning: '${INSTALLKERNEL}' command not available - additional " \ echo "Warning: '${INSTALLKERNEL}' command not available - additional " \
"bootloader config required" >&2 "bootloader config required" >&2
if [ -f "$4/vmlinuz-$1" ]; then mv -- "$4/vmlinuz-$1" "$4/vmlinuz-$1.old"; fi if [ -f "$4/vmlinuz-$1" ]; then mv -- "$4/vmlinuz-$1" "$4/vmlinuz-$1.old"; fi
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old mv $4/vmlinuz $4/vmlinuz.old
fi fi
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
# $3 - kernel map file # $3 - kernel map file
# $4 - default install path (blank if root directory) # $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old mv $4/vmlinuz $4/vmlinuz.old
fi fi
......
...@@ -151,8 +151,9 @@ config JFFS2_RUBIN ...@@ -151,8 +151,9 @@ config JFFS2_RUBIN
RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
choice choice
prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS prompt "JFFS2 default compression mode"
default JFFS2_CMODE_PRIORITY default JFFS2_CMODE_PRIORITY
depends on JFFS2_COMPRESSION_OPTIONS
depends on JFFS2_FS depends on JFFS2_FS
help help
You can set here the default compression mode of JFFS2 from You can set here the default compression mode of JFFS2 from
......
...@@ -442,30 +442,11 @@ ...@@ -442,30 +442,11 @@
#endif #endif
#endif #endif
/*
* Some symbol definitions will not exist yet during the first pass of the
* link, but are guaranteed to exist in the final link. Provide preliminary
* definitions that will be superseded in the final link to avoid having to
* rely on weak external linkage, which requires a GOT when used in position
* independent code.
*/
#define PRELIMINARY_SYMBOL_DEFINITIONS \
PROVIDE(kallsyms_addresses = .); \
PROVIDE(kallsyms_offsets = .); \
PROVIDE(kallsyms_names = .); \
PROVIDE(kallsyms_num_syms = .); \
PROVIDE(kallsyms_relative_base = .); \
PROVIDE(kallsyms_token_table = .); \
PROVIDE(kallsyms_token_index = .); \
PROVIDE(kallsyms_markers = .); \
PROVIDE(kallsyms_seqs_of_names = .);
/* /*
* Read only Data * Read only Data
*/ */
#define RO_DATA(align) \ #define RO_DATA(align) \
. = ALIGN((align)); \ . = ALIGN((align)); \
PRELIMINARY_SYMBOL_DEFINITIONS \
.rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \
__start_rodata = .; \ __start_rodata = .; \
*(.rodata) *(.rodata.*) \ *(.rodata) *(.rodata.*) \
......
...@@ -1803,24 +1803,6 @@ config KALLSYMS_ABSOLUTE_PERCPU ...@@ -1803,24 +1803,6 @@ config KALLSYMS_ABSOLUTE_PERCPU
depends on KALLSYMS depends on KALLSYMS
default X86_64 && SMP default X86_64 && SMP
config KALLSYMS_BASE_RELATIVE
bool
depends on KALLSYMS
default y
help
Instead of emitting them as absolute values in the native word size,
emit the symbol references in the kallsyms table as 32-bit entries,
each containing a relative value in the range [base, base + U32_MAX]
or, when KALLSYMS_ABSOLUTE_PERCPU is in effect, each containing either
an absolute value in the range [0, S32_MAX] or a relative value in the
range [base, base + S32_MAX], where base is the lowest relative symbol
address encountered in the image.
On 64-bit builds, this reduces the size of the address table by 50%,
but more importantly, it results in entries whose values are build
time constants, and no relocation pass is required at runtime to fix
up the entries based on the runtime load address of the kernel.
# end of the "standard kernel features (expert users)" menu # end of the "standard kernel features (expert users)" menu
config ARCH_HAS_MEMBARRIER_CALLBACKS config ARCH_HAS_MEMBARRIER_CALLBACKS
......
...@@ -52,7 +52,7 @@ CFLAGS_version.o := -include $(obj)/utsversion-tmp.h ...@@ -52,7 +52,7 @@ CFLAGS_version.o := -include $(obj)/utsversion-tmp.h
# Build version-timestamp.c with final UTS_VERSION # Build version-timestamp.c with final UTS_VERSION
# #
include/generated/utsversion.h: build-version-auto = $(shell $(src)/build-version) include/generated/utsversion.h: build-version-auto = $(shell $(srctree)/scripts/build-version)
include/generated/utsversion.h: build-timestamp-auto = $(shell LC_ALL=C date) include/generated/utsversion.h: build-timestamp-auto = $(shell LC_ALL=C date)
include/generated/utsversion.h: FORCE include/generated/utsversion.h: FORCE
$(call filechk,uts_version) $(call filechk,uts_version)
......
...@@ -148,9 +148,6 @@ static unsigned int get_symbol_offset(unsigned long pos) ...@@ -148,9 +148,6 @@ static unsigned int get_symbol_offset(unsigned long pos)
unsigned long kallsyms_sym_address(int idx) unsigned long kallsyms_sym_address(int idx)
{ {
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
return kallsyms_addresses[idx];
/* values are unsigned offsets if --absolute-percpu is not in effect */ /* values are unsigned offsets if --absolute-percpu is not in effect */
if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU)) if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
return kallsyms_relative_base + (u32)kallsyms_offsets[idx]; return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
...@@ -325,7 +322,7 @@ static unsigned long get_symbol_pos(unsigned long addr, ...@@ -325,7 +322,7 @@ static unsigned long get_symbol_pos(unsigned long addr,
unsigned long symbol_start = 0, symbol_end = 0; unsigned long symbol_start = 0, symbol_end = 0;
unsigned long i, low, high, mid; unsigned long i, low, high, mid;
/* Do a binary search on the sorted kallsyms_addresses array. */ /* Do a binary search on the sorted kallsyms_offsets array. */
low = 0; low = 0;
high = kallsyms_num_syms; high = kallsyms_num_syms;
......
...@@ -4,12 +4,6 @@ ...@@ -4,12 +4,6 @@
#include <linux/types.h> #include <linux/types.h>
/*
* These will be re-linked against their real values during the second link
* stage. Preliminary values must be provided in the linker script using the
* PROVIDE() directive so that the first link stage can complete successfully.
*/
extern const unsigned long kallsyms_addresses[];
extern const int kallsyms_offsets[]; extern const int kallsyms_offsets[];
extern const u8 kallsyms_names[]; extern const u8 kallsyms_names[];
......
...@@ -216,12 +216,8 @@ static int __init crash_save_vmcoreinfo_init(void) ...@@ -216,12 +216,8 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_SYMBOL(kallsyms_num_syms); VMCOREINFO_SYMBOL(kallsyms_num_syms);
VMCOREINFO_SYMBOL(kallsyms_token_table); VMCOREINFO_SYMBOL(kallsyms_token_table);
VMCOREINFO_SYMBOL(kallsyms_token_index); VMCOREINFO_SYMBOL(kallsyms_token_index);
#ifdef CONFIG_KALLSYMS_BASE_RELATIVE
VMCOREINFO_SYMBOL(kallsyms_offsets); VMCOREINFO_SYMBOL(kallsyms_offsets);
VMCOREINFO_SYMBOL(kallsyms_relative_base); VMCOREINFO_SYMBOL(kallsyms_relative_base);
#else
VMCOREINFO_SYMBOL(kallsyms_addresses);
#endif /* CONFIG_KALLSYMS_BASE_RELATIVE */
#endif /* CONFIG_KALLSYMS */ #endif /* CONFIG_KALLSYMS */
arch_crash_save_vmcoreinfo(); arch_crash_save_vmcoreinfo();
......
...@@ -68,7 +68,7 @@ kbuild-file = $(or $(wildcard $(src)/Kbuild),$(src)/Makefile) ...@@ -68,7 +68,7 @@ kbuild-file = $(or $(wildcard $(src)/Kbuild),$(src)/Makefile)
# Read a file, replacing newlines with spaces # Read a file, replacing newlines with spaces
# #
# Make 4.2 or later can read a file by using its builtin function. # Make 4.2 or later can read a file by using its builtin function.
ifneq ($(filter-out 3.% 4.0 4.1, $(MAKE_VERSION)),) ifneq ($(filter-out 4.0 4.1, $(MAKE_VERSION)),)
read-file = $(subst $(newline),$(space),$(file < $1)) read-file = $(subst $(newline),$(space),$(file < $1))
else else
read-file = $(shell cat $1 2>/dev/null) read-file = $(shell cat $1 2>/dev/null)
......
...@@ -409,12 +409,16 @@ cmd_dtc = $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; ...@@ -409,12 +409,16 @@ cmd_dtc = $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ;
DT_CHECK_CMD = $(DT_CHECKER) $(DT_CHECKER_FLAGS) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) DT_CHECK_CMD = $(DT_CHECKER) $(DT_CHECKER_FLAGS) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA)
# NOTE:
# Do not replace $(filter %.dtb %.dtbo, $^) with $(real-prereqs). When a single
# DTB is turned into a multi-blob DTB, $^ will contain header file dependencies
# recorded in the .*.cmd file.
ifneq ($(CHECK_DTBS),) ifneq ($(CHECK_DTBS),)
quiet_cmd_fdtoverlay = DTOVLCH $@ quiet_cmd_fdtoverlay = DTOVLCH $@
cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(real-prereqs) ; $(DT_CHECK_CMD) $@ || true cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(filter %.dtb %.dtbo, $^) ; $(DT_CHECK_CMD) $@ || true
else else
quiet_cmd_fdtoverlay = DTOVL $@ quiet_cmd_fdtoverlay = DTOVL $@
cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(real-prereqs) cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(filter %.dtb %.dtbo, $^)
endif endif
$(multi-dtb-y): FORCE $(multi-dtb-y): FORCE
...@@ -529,6 +533,7 @@ quiet_cmd_fit = FIT $@ ...@@ -529,6 +533,7 @@ quiet_cmd_fit = FIT $@
cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \ cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
--name '$(UIMAGE_NAME)' \ --name '$(UIMAGE_NAME)' \
$(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \ $(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
$(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
--compress $(FIT_COMPRESSION) -k $< @$(word 2,$^) --compress $(FIT_COMPRESSION) -k $< @$(word 2,$^)
# XZ # XZ
......
...@@ -141,6 +141,19 @@ snap-pkg: ...@@ -141,6 +141,19 @@ snap-pkg:
cd $(objtree)/snap && \ cd $(objtree)/snap && \
snapcraft --target-arch=$(UTS_MACHINE) snapcraft --target-arch=$(UTS_MACHINE)
# pacman-pkg
# ---------------------------------------------------------------------------
PHONY += pacman-pkg
pacman-pkg:
@ln -srf $(srctree)/scripts/package/PKGBUILD $(objtree)/PKGBUILD
+objtree="$(realpath $(objtree))" \
BUILDDIR="$(realpath $(objtree))/pacman" \
CARCH="$(UTS_MACHINE)" \
KBUILD_MAKEFLAGS="$(MAKEFLAGS)" \
KBUILD_REVISION="$(shell $(srctree)/scripts/build-version)" \
makepkg $(MAKEPKGOPTS)
# dir-pkg tar*-pkg - tarball targets # dir-pkg tar*-pkg - tarball targets
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
...@@ -221,6 +234,7 @@ help: ...@@ -221,6 +234,7 @@ help:
@echo ' bindeb-pkg - Build only the binary kernel deb package' @echo ' bindeb-pkg - Build only the binary kernel deb package'
@echo ' snap-pkg - Build only the binary kernel snap package' @echo ' snap-pkg - Build only the binary kernel snap package'
@echo ' (will connect to external hosts)' @echo ' (will connect to external hosts)'
@echo ' pacman-pkg - Build only the binary kernel pacman package'
@echo ' dir-pkg - Build the kernel as a plain directory structure' @echo ' dir-pkg - Build the kernel as a plain directory structure'
@echo ' tar-pkg - Build the kernel as an uncompressed tarball' @echo ' tar-pkg - Build the kernel as an uncompressed tarball'
@echo ' targz-pkg - Build the kernel as a gzip compressed tarball' @echo ' targz-pkg - Build the kernel as a gzip compressed tarball'
......
...@@ -127,6 +127,29 @@ static inline void list_del(struct list_head *entry) ...@@ -127,6 +127,29 @@ static inline void list_del(struct list_head *entry)
entry->prev = LIST_POISON2; entry->prev = LIST_POISON2;
} }
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del_entry(list);
list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del_entry(list);
list_add_tail(list, head);
}
/** /**
* list_is_head - tests whether @list is the list @head * list_is_head - tests whether @list is the list @head
* @list: the entry to test * @list: the entry to test
...@@ -166,6 +189,17 @@ static inline int list_empty(const struct list_head *head) ...@@ -166,6 +189,17 @@ static inline int list_empty(const struct list_head *head)
#define list_first_entry(ptr, type, member) \ #define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member) list_entry((ptr)->next, type, member)
/**
* list_last_entry - get the last element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_last_entry(ptr, type, member) \
list_entry((ptr)->prev, type, member)
/** /**
* list_next_entry - get the next element in list * list_next_entry - get the next element in list
* @pos: the type * to cursor * @pos: the type * to cursor
...@@ -174,6 +208,14 @@ static inline int list_empty(const struct list_head *head) ...@@ -174,6 +208,14 @@ static inline int list_empty(const struct list_head *head)
#define list_next_entry(pos, member) \ #define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member) list_entry((pos)->member.next, typeof(*(pos)), member)
/**
* list_prev_entry - get the prev element in list
* @pos: the type * to cursor
* @member: the name of the list_head within the struct.
*/
#define list_prev_entry(pos, member) \
list_entry((pos)->member.prev, typeof(*(pos)), member)
/** /**
* list_entry_is_head - test if the entry points to the head of the list * list_entry_is_head - test if the entry points to the head of the list
* @pos: the type * to cursor * @pos: the type * to cursor
...@@ -194,6 +236,17 @@ static inline int list_empty(const struct list_head *head) ...@@ -194,6 +236,17 @@ static inline int list_empty(const struct list_head *head)
!list_entry_is_head(pos, head, member); \ !list_entry_is_head(pos, head, member); \
pos = list_next_entry(pos, member)) pos = list_next_entry(pos, member))
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_last_entry(head, typeof(*pos), member); \
!list_entry_is_head(pos, head, member); \
pos = list_prev_entry(pos, member))
/** /**
* list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry * list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry
* @pos: the type * to use as a loop cursor. * @pos: the type * to use as a loop cursor.
......
...@@ -20,6 +20,10 @@ do ...@@ -20,6 +20,10 @@ do
fi fi
done done
if [ -n "${INSTALL_PATH}" ] && ! [ -e "${INSTALL_PATH}" ]; then
mkdir -p "${INSTALL_PATH}"
fi
# User/arch may have a custom install script # User/arch may have a custom install script
for file in "${HOME}/bin/${INSTALLKERNEL}" \ for file in "${HOME}/bin/${INSTALLKERNEL}" \
"/sbin/${INSTALLKERNEL}" \ "/sbin/${INSTALLKERNEL}" \
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* of the GNU General Public License, incorporated herein by reference. * of the GNU General Public License, incorporated herein by reference.
* *
* Usage: kallsyms [--all-symbols] [--absolute-percpu] * Usage: kallsyms [--all-symbols] [--absolute-percpu]
* [--base-relative] [--lto-clang] in.map > out.S * [--lto-clang] in.map > out.S
* *
* Table compression uses all the unused char codes on the symbols and * Table compression uses all the unused char codes on the symbols and
* maps these to the most used substrings (tokens). For instance, it might * maps these to the most used substrings (tokens). For instance, it might
...@@ -36,8 +36,7 @@ struct sym_entry { ...@@ -36,8 +36,7 @@ struct sym_entry {
unsigned long long addr; unsigned long long addr;
unsigned int len; unsigned int len;
unsigned int seq; unsigned int seq;
unsigned int start_pos; bool percpu_absolute;
unsigned int percpu_absolute;
unsigned char sym[]; unsigned char sym[];
}; };
...@@ -63,7 +62,6 @@ static struct sym_entry **table; ...@@ -63,7 +62,6 @@ static struct sym_entry **table;
static unsigned int table_size, table_cnt; static unsigned int table_size, table_cnt;
static int all_symbols; static int all_symbols;
static int absolute_percpu; static int absolute_percpu;
static int base_relative;
static int lto_clang; static int lto_clang;
static int token_profit[0x10000]; static int token_profit[0x10000];
...@@ -76,7 +74,7 @@ static unsigned char best_table_len[256]; ...@@ -76,7 +74,7 @@ static unsigned char best_table_len[256];
static void usage(void) static void usage(void)
{ {
fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] " fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] "
"[--base-relative] [--lto-clang] in.map > out.S\n"); "[--lto-clang] in.map > out.S\n");
exit(1); exit(1);
} }
...@@ -183,7 +181,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len) ...@@ -183,7 +181,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
sym->len = len; sym->len = len;
sym->sym[0] = type; sym->sym[0] = type;
strcpy(sym_name(sym), name); strcpy(sym_name(sym), name);
sym->percpu_absolute = 0; sym->percpu_absolute = false;
return sym; return sym;
} }
...@@ -259,12 +257,6 @@ static void shrink_table(void) ...@@ -259,12 +257,6 @@ static void shrink_table(void)
} }
} }
table_cnt = pos; table_cnt = pos;
/* When valid symbol is not registered, exit to error */
if (!table_cnt) {
fprintf(stderr, "No valid symbol.\n");
exit(1);
}
} }
static void read_map(const char *in) static void read_map(const char *in)
...@@ -285,7 +277,7 @@ static void read_map(const char *in) ...@@ -285,7 +277,7 @@ static void read_map(const char *in)
if (!sym) if (!sym)
continue; continue;
sym->start_pos = table_cnt; sym->seq = table_cnt;
if (table_cnt >= table_size) { if (table_cnt >= table_size) {
table_size += 10000; table_size += 10000;
...@@ -347,7 +339,7 @@ static int expand_symbol(const unsigned char *data, int len, char *result) ...@@ -347,7 +339,7 @@ static int expand_symbol(const unsigned char *data, int len, char *result)
return total; return total;
} }
static int symbol_absolute(const struct sym_entry *s) static bool symbol_absolute(const struct sym_entry *s)
{ {
return s->percpu_absolute; return s->percpu_absolute;
} }
...@@ -400,7 +392,7 @@ static void write_src(void) ...@@ -400,7 +392,7 @@ static void write_src(void)
{ {
unsigned int i, k, off; unsigned int i, k, off;
unsigned int best_idx[256]; unsigned int best_idx[256];
unsigned int *markers; unsigned int *markers, markers_cnt;
char buf[KSYM_NAME_LEN]; char buf[KSYM_NAME_LEN];
printf("#include <asm/bitsperlong.h>\n"); printf("#include <asm/bitsperlong.h>\n");
...@@ -420,7 +412,8 @@ static void write_src(void) ...@@ -420,7 +412,8 @@ static void write_src(void)
/* table of offset markers, that give the offset in the compressed stream /* table of offset markers, that give the offset in the compressed stream
* every 256 symbols */ * every 256 symbols */
markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256)); markers_cnt = (table_cnt + 255) / 256;
markers = malloc(sizeof(*markers) * markers_cnt);
if (!markers) { if (!markers) {
fprintf(stderr, "kallsyms failure: " fprintf(stderr, "kallsyms failure: "
"unable to allocate required memory\n"); "unable to allocate required memory\n");
...@@ -462,21 +455,19 @@ static void write_src(void) ...@@ -462,21 +455,19 @@ static void write_src(void)
} }
for (k = 0; k < table[i]->len; k++) for (k = 0; k < table[i]->len; k++)
printf(", 0x%02x", table[i]->sym[k]); printf(", 0x%02x", table[i]->sym[k]);
printf("\n");
}
printf("\n");
/* /*
* Now that we wrote out the compressed symbol names, restore the * Now that we wrote out the compressed symbol name, restore the
* original names, which are needed in some of the later steps. * original name and print it in the comment.
*/ */
for (i = 0; i < table_cnt; i++) {
expand_symbol(table[i]->sym, table[i]->len, buf); expand_symbol(table[i]->sym, table[i]->len, buf);
strcpy((char *)table[i]->sym, buf); strcpy((char *)table[i]->sym, buf);
printf("\t/* %s */\n", table[i]->sym);
} }
printf("\n");
output_label("kallsyms_markers"); output_label("kallsyms_markers");
for (i = 0; i < ((table_cnt + 255) >> 8); i++) for (i = 0; i < markers_cnt; i++)
printf("\t.long\t%u\n", markers[i]); printf("\t.long\t%u\n", markers[i]);
printf("\n"); printf("\n");
...@@ -497,54 +488,43 @@ static void write_src(void) ...@@ -497,54 +488,43 @@ static void write_src(void)
printf("\t.short\t%d\n", best_idx[i]); printf("\t.short\t%d\n", best_idx[i]);
printf("\n"); printf("\n");
if (!base_relative) output_label("kallsyms_offsets");
output_label("kallsyms_addresses");
else
output_label("kallsyms_offsets");
for (i = 0; i < table_cnt; i++) { for (i = 0; i < table_cnt; i++) {
if (base_relative) { /*
/* * Use the offset relative to the lowest value
* Use the offset relative to the lowest value * encountered of all relative symbols, and emit
* encountered of all relative symbols, and emit * non-relocatable fixed offsets that will be fixed
* non-relocatable fixed offsets that will be fixed * up at runtime.
* up at runtime. */
*/
long long offset; long long offset;
int overflow; int overflow;
if (!absolute_percpu) { if (!absolute_percpu) {
offset = table[i]->addr - relative_base; offset = table[i]->addr - relative_base;
overflow = (offset < 0 || offset > UINT_MAX); overflow = (offset < 0 || offset > UINT_MAX);
} else if (symbol_absolute(table[i])) { } else if (symbol_absolute(table[i])) {
offset = table[i]->addr; offset = table[i]->addr;
overflow = (offset < 0 || offset > INT_MAX); overflow = (offset < 0 || offset > INT_MAX);
} else {
offset = relative_base - table[i]->addr - 1;
overflow = (offset < INT_MIN || offset >= 0);
}
if (overflow) {
fprintf(stderr, "kallsyms failure: "
"%s symbol value %#llx out of range in relative mode\n",
symbol_absolute(table[i]) ? "absolute" : "relative",
table[i]->addr);
exit(EXIT_FAILURE);
}
printf("\t.long\t%#x /* %s */\n", (int)offset, table[i]->sym);
} else if (!symbol_absolute(table[i])) {
output_address(table[i]->addr);
} else { } else {
printf("\tPTR\t%#llx\n", table[i]->addr); offset = relative_base - table[i]->addr - 1;
overflow = (offset < INT_MIN || offset >= 0);
}
if (overflow) {
fprintf(stderr, "kallsyms failure: "
"%s symbol value %#llx out of range in relative mode\n",
symbol_absolute(table[i]) ? "absolute" : "relative",
table[i]->addr);
exit(EXIT_FAILURE);
} }
printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym);
} }
printf("\n"); printf("\n");
if (base_relative) { output_label("kallsyms_relative_base");
output_label("kallsyms_relative_base"); output_address(relative_base);
output_address(relative_base); printf("\n");
printf("\n");
}
if (lto_clang) if (lto_clang)
for (i = 0; i < table_cnt; i++) for (i = 0; i < table_cnt; i++)
...@@ -553,10 +533,11 @@ static void write_src(void) ...@@ -553,10 +533,11 @@ static void write_src(void)
sort_symbols_by_name(); sort_symbols_by_name();
output_label("kallsyms_seqs_of_names"); output_label("kallsyms_seqs_of_names");
for (i = 0; i < table_cnt; i++) for (i = 0; i < table_cnt; i++)
printf("\t.byte 0x%02x, 0x%02x, 0x%02x\n", printf("\t.byte 0x%02x, 0x%02x, 0x%02x\t/* %s */\n",
(unsigned char)(table[i]->seq >> 16), (unsigned char)(table[i]->seq >> 16),
(unsigned char)(table[i]->seq >> 8), (unsigned char)(table[i]->seq >> 8),
(unsigned char)(table[i]->seq >> 0)); (unsigned char)(table[i]->seq >> 0),
table[i]->sym);
printf("\n"); printf("\n");
} }
...@@ -780,7 +761,7 @@ static int compare_symbols(const void *a, const void *b) ...@@ -780,7 +761,7 @@ static int compare_symbols(const void *a, const void *b)
return wa - wb; return wa - wb;
/* sort by initial order, so that other symbols are left undisturbed */ /* sort by initial order, so that other symbols are left undisturbed */
return sa->start_pos - sb->start_pos; return sa->seq - sb->seq;
} }
static void sort_symbols(void) static void sort_symbols(void)
...@@ -800,7 +781,7 @@ static void make_percpus_absolute(void) ...@@ -800,7 +781,7 @@ static void make_percpus_absolute(void)
* versions of this tool. * versions of this tool.
*/ */
table[i]->sym[0] = 'A'; table[i]->sym[0] = 'A';
table[i]->percpu_absolute = 1; table[i]->percpu_absolute = true;
} }
} }
...@@ -826,7 +807,6 @@ int main(int argc, char **argv) ...@@ -826,7 +807,6 @@ int main(int argc, char **argv)
static const struct option long_options[] = { static const struct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1}, {"all-symbols", no_argument, &all_symbols, 1},
{"absolute-percpu", no_argument, &absolute_percpu, 1}, {"absolute-percpu", no_argument, &absolute_percpu, 1},
{"base-relative", no_argument, &base_relative, 1},
{"lto-clang", no_argument, &lto_clang, 1}, {"lto-clang", no_argument, &lto_clang, 1},
{}, {},
}; };
...@@ -847,8 +827,7 @@ int main(int argc, char **argv) ...@@ -847,8 +827,7 @@ int main(int argc, char **argv)
if (absolute_percpu) if (absolute_percpu)
make_percpus_absolute(); make_percpus_absolute();
sort_symbols(); sort_symbols();
if (base_relative) record_relative_base();
record_relative_base();
optimize_token_table(); optimize_token_table();
write_src(); write_src();
......
...@@ -114,51 +114,54 @@ static void set_randconfig_seed(void) ...@@ -114,51 +114,54 @@ static void set_randconfig_seed(void)
srand(seed); srand(seed);
} }
static bool randomize_choice_values(struct symbol *csym) /**
* randomize_choice_values - randomize choice block
*
* @choice: menu entry for the choice
*/
static void randomize_choice_values(struct menu *choice)
{ {
struct property *prop; struct menu *menu;
struct symbol *sym; int x;
struct expr *e; int cnt = 0;
int cnt, def;
/* /*
* If choice is mod then we may have more items selected * First, count the number of symbols to randomize. If sym_has_value()
* and if no then no-one. * is true, it was specified by KCONFIG_ALLCONFIG. It needs to be
* In both cases stop. * respected.
*/ */
if (csym->curr.tri != yes) menu_for_each_sub_entry(menu, choice) {
return false; struct symbol *sym = menu->sym;
prop = sym_get_choice_prop(csym); if (sym && !sym_has_value(sym))
cnt++;
}
/* count entries in choice block */ while (cnt > 0) {
cnt = 0; x = rand() % cnt;
expr_list_for_each_sym(prop->expr, e, sym)
cnt++;
/* menu_for_each_sub_entry(menu, choice) {
* find a random value and set it to yes, struct symbol *sym = menu->sym;
* set the rest to no so we have only one set
*/ if (sym && !sym_has_value(sym))
def = rand() % cnt; x--;
cnt = 0; if (x < 0) {
expr_list_for_each_sym(prop->expr, e, sym) { sym->def[S_DEF_USER].tri = yes;
if (def == cnt++) { sym->flags |= SYMBOL_DEF_USER;
sym->def[S_DEF_USER].tri = yes; /*
csym->def[S_DEF_USER].val = sym; * Move the selected item to the _tail_ because
} else { * this needs to have a lower priority than the
sym->def[S_DEF_USER].tri = no; * user input from KCONFIG_ALLCONFIG.
*/
list_move_tail(&sym->choice_link,
&choice->choice_members);
break;
}
} }
sym->flags |= SYMBOL_DEF_USER; cnt--;
/* clear VALID to get value calculated */
sym->flags &= ~SYMBOL_VALID;
} }
csym->flags |= SYMBOL_DEF_USER;
/* clear VALID to get value calculated */
csym->flags &= ~SYMBOL_VALID;
return true;
} }
enum conf_def_mode { enum conf_def_mode {
...@@ -169,9 +172,9 @@ enum conf_def_mode { ...@@ -169,9 +172,9 @@ enum conf_def_mode {
def_random def_random
}; };
static bool conf_set_all_new_symbols(enum conf_def_mode mode) static void conf_set_all_new_symbols(enum conf_def_mode mode)
{ {
struct symbol *sym, *csym; struct menu *menu;
int cnt; int cnt;
/* /*
* can't go as the default in switch-case below, otherwise gcc whines * can't go as the default in switch-case below, otherwise gcc whines
...@@ -180,7 +183,6 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) ...@@ -180,7 +183,6 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
int pby = 50; /* probability of bool = y */ int pby = 50; /* probability of bool = y */
int pty = 33; /* probability of tristate = y */ int pty = 33; /* probability of tristate = y */
int ptm = 33; /* probability of tristate = m */ int ptm = 33; /* probability of tristate = m */
bool has_changed = false;
if (mode == def_random) { if (mode == def_random) {
int n, p[3]; int n, p[3];
...@@ -227,79 +229,51 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) ...@@ -227,79 +229,51 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
} }
} }
for_all_symbols(sym) { menu_for_each_entry(menu) {
if (sym_has_value(sym) || sym->flags & SYMBOL_VALID) struct symbol *sym = menu->sym;
continue; tristate val;
switch (sym_get_type(sym)) {
case S_BOOLEAN:
case S_TRISTATE:
has_changed = true;
switch (mode) {
case def_yes:
sym->def[S_DEF_USER].tri = yes;
break;
case def_mod:
sym->def[S_DEF_USER].tri = mod;
break;
case def_no:
sym->def[S_DEF_USER].tri = no;
break;
case def_random:
sym->def[S_DEF_USER].tri = no;
cnt = rand() % 100;
if (sym->type == S_TRISTATE) {
if (cnt < pty)
sym->def[S_DEF_USER].tri = yes;
else if (cnt < pty + ptm)
sym->def[S_DEF_USER].tri = mod;
} else if (cnt < pby)
sym->def[S_DEF_USER].tri = yes;
break;
default:
continue;
}
if (!(sym_is_choice(sym) && mode == def_random))
sym->flags |= SYMBOL_DEF_USER;
break;
default:
break;
}
}
sym_clear_all_valid(); if (!sym || !menu->prompt || sym_has_value(sym) ||
(sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
sym_is_choice_value(sym))
continue;
/* if (sym_is_choice(sym)) {
* We have different type of choice blocks. if (mode == def_random)
* If curr.tri equals to mod then we can select several randomize_choice_values(menu);
* choice symbols in one block. continue;
* In this case we do nothing.
* If curr.tri equals yes then only one symbol can be
* selected in a choice block and we set it to yes,
* and the rest to no.
*/
if (mode != def_random) {
for_all_symbols(csym) {
if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
sym_is_choice_value(csym))
csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
} }
}
for_all_symbols(csym) { switch (mode) {
if (sym_has_value(csym) || !sym_is_choice(csym)) case def_yes:
val = yes;
break;
case def_mod:
val = mod;
break;
case def_no:
val = no;
break;
case def_random:
val = no;
cnt = rand() % 100;
if (sym->type == S_TRISTATE) {
if (cnt < pty)
val = yes;
else if (cnt < pty + ptm)
val = mod;
} else if (cnt < pby) {
val = yes;
}
break;
default:
continue; continue;
sym_calc_value(csym);
if (mode == def_random)
has_changed |= randomize_choice_values(csym);
else {
set_all_choice_values(csym);
has_changed = true;
} }
sym->def[S_DEF_USER].tri = val;
sym->flags |= SYMBOL_DEF_USER;
} }
return has_changed; sym_clear_all_valid();
} }
static void conf_rewrite_tristates(tristate old_val, tristate new_val) static void conf_rewrite_tristates(tristate old_val, tristate new_val)
...@@ -448,39 +422,15 @@ static int conf_sym(struct menu *menu) ...@@ -448,39 +422,15 @@ static int conf_sym(struct menu *menu)
static void conf_choice(struct menu *menu) static void conf_choice(struct menu *menu)
{ {
struct symbol *sym, *def_sym; struct symbol *def_sym;
struct menu *child; struct menu *child;
bool is_new; bool is_new = false;
sym = menu->sym;
is_new = !sym_has_value(sym);
if (sym_is_changeable(sym)) {
conf_sym(menu);
sym_calc_value(sym);
switch (sym_get_tristate_value(sym)) {
case no:
case mod:
return;
case yes:
break;
}
} else {
switch (sym_get_tristate_value(sym)) {
case no:
return;
case mod:
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
return;
case yes:
break;
}
}
while (1) { while (1) {
int cnt, def; int cnt, def;
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
def_sym = sym_get_choice_value(sym); def_sym = sym_calc_choice(menu);
cnt = def = 0; cnt = def = 0;
line[0] = 0; line[0] = 0;
for (child = menu->list; child; child = child->next) { for (child = menu->list; child; child = child->next) {
...@@ -498,8 +448,10 @@ static void conf_choice(struct menu *menu) ...@@ -498,8 +448,10 @@ static void conf_choice(struct menu *menu)
printf("%*c", indent, ' '); printf("%*c", indent, ' ');
printf(" %d. %s (%s)", cnt, menu_get_prompt(child), printf(" %d. %s (%s)", cnt, menu_get_prompt(child),
child->sym->name); child->sym->name);
if (!sym_has_value(child->sym)) if (!sym_has_value(child->sym)) {
is_new = true;
printf(" (NEW)"); printf(" (NEW)");
}
printf("\n"); printf("\n");
} }
printf("%*schoice", indent - 1, ""); printf("%*schoice", indent - 1, "");
...@@ -549,7 +501,7 @@ static void conf_choice(struct menu *menu) ...@@ -549,7 +501,7 @@ static void conf_choice(struct menu *menu)
print_help(child); print_help(child);
continue; continue;
} }
sym_set_tristate_value(child->sym, yes); choice_set_value(menu, child->sym);
return; return;
} }
} }
...@@ -596,9 +548,7 @@ static void conf(struct menu *menu) ...@@ -596,9 +548,7 @@ static void conf(struct menu *menu)
if (sym_is_choice(sym)) { if (sym_is_choice(sym)) {
conf_choice(menu); conf_choice(menu);
if (sym->curr.tri != mod) return;
return;
goto conf_childs;
} }
switch (sym->type) { switch (sym->type) {
...@@ -630,10 +580,7 @@ static void check_conf(struct menu *menu) ...@@ -630,10 +580,7 @@ static void check_conf(struct menu *menu)
return; return;
sym = menu->sym; sym = menu->sym;
if (sym && !sym_has_value(sym) && if (sym && !sym_has_value(sym) && sym_is_changeable(sym)) {
(sym_is_changeable(sym) ||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) {
switch (input_mode) { switch (input_mode) {
case listnewconfig: case listnewconfig:
if (sym->name) if (sym->name)
...@@ -849,8 +796,7 @@ int main(int ac, char **av) ...@@ -849,8 +796,7 @@ int main(int ac, char **av)
conf_set_all_new_symbols(def_default); conf_set_all_new_symbols(def_default);
break; break;
case randconfig: case randconfig:
/* Really nothing to do in this loop */ conf_set_all_new_symbols(def_random);
while (conf_set_all_new_symbols(def_random)) ;
break; break;
case defconfig: case defconfig:
conf_set_all_new_symbols(def_default); conf_set_all_new_symbols(def_default);
......
...@@ -382,10 +382,7 @@ int conf_read_simple(const char *name, int def) ...@@ -382,10 +382,7 @@ int conf_read_simple(const char *name, int def)
def_flags = SYMBOL_DEF << def; def_flags = SYMBOL_DEF << def;
for_all_symbols(sym) { for_all_symbols(sym) {
sym->flags |= SYMBOL_CHANGED;
sym->flags &= ~(def_flags|SYMBOL_VALID); sym->flags &= ~(def_flags|SYMBOL_VALID);
if (sym_is_choice(sym))
sym->flags |= def_flags;
switch (sym->type) { switch (sym->type) {
case S_INT: case S_INT:
case S_HEX: case S_HEX:
...@@ -399,6 +396,8 @@ int conf_read_simple(const char *name, int def) ...@@ -399,6 +396,8 @@ int conf_read_simple(const char *name, int def)
} }
while (getline_stripped(&line, &line_asize, in) != -1) { while (getline_stripped(&line, &line_asize, in) != -1) {
struct menu *choice;
conf_lineno++; conf_lineno++;
if (!line[0]) /* blank line */ if (!line[0]) /* blank line */
...@@ -460,25 +459,14 @@ int conf_read_simple(const char *name, int def) ...@@ -460,25 +459,14 @@ int conf_read_simple(const char *name, int def)
if (conf_set_sym_val(sym, def, def_flags, val)) if (conf_set_sym_val(sym, def, def_flags, val))
continue; continue;
if (sym && sym_is_choice_value(sym)) { /*
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); * If this is a choice member, give it the highest priority.
switch (sym->def[def].tri) { * If conflicting CONFIG options are given from an input file,
case no: * the last one wins.
break; */
case mod: choice = sym_get_choice_menu(sym);
if (cs->def[def].tri == yes) { if (choice)
conf_warning("%s creates inconsistent choice state", sym->name); list_move(&sym->choice_link, &choice->choice_members);
cs->flags &= ~def_flags;
}
break;
case yes:
if (cs->def[def].tri != no)
conf_warning("override: %s changes choice state", sym->name);
cs->def[def].val = sym;
break;
}
cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
}
} }
free(line); free(line);
fclose(in); fclose(in);
...@@ -489,7 +477,6 @@ int conf_read_simple(const char *name, int def) ...@@ -489,7 +477,6 @@ int conf_read_simple(const char *name, int def)
int conf_read(const char *name) int conf_read(const char *name)
{ {
struct symbol *sym; struct symbol *sym;
int conf_unsaved = 0;
conf_set_changed(false); conf_set_changed(false);
...@@ -520,23 +507,11 @@ int conf_read(const char *name) ...@@ -520,23 +507,11 @@ int conf_read(const char *name)
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
/* no previous value and not saved */ /* no previous value and not saved */
continue; continue;
conf_unsaved++; conf_set_changed(true);
/* maybe print value in verbose mode... */ /* maybe print value in verbose mode... */
} }
for_all_symbols(sym) { if (conf_warnings)
if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
/* Reset values of generates values, so they'll appear
* as new, if they should become visible, but that
* doesn't quite work if the Kconfig and the saved
* configuration disagree.
*/
if (sym->visible == no && !conf_unsaved)
sym->flags &= ~SYMBOL_DEF_USER;
}
}
if (conf_warnings || conf_unsaved)
conf_set_changed(true); conf_set_changed(true);
return 0; return 0;
...@@ -784,35 +759,31 @@ int conf_write_defconfig(const char *filename) ...@@ -784,35 +759,31 @@ int conf_write_defconfig(const char *filename)
struct menu *choice; struct menu *choice;
sym = menu->sym; sym = menu->sym;
if (sym && !sym_is_choice(sym)) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE))
continue;
sym->flags &= ~SYMBOL_WRITE;
/* If we cannot change the symbol - skip */
if (!sym_is_changeable(sym))
continue;
/* If symbol equals to default value - skip */
if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
continue;
/* if (!sym || sym_is_choice(sym))
* If symbol is a choice value and equals to the continue;
* default for a choice - skip.
*/ sym_calc_value(sym);
choice = sym_get_choice_menu(sym); if (!(sym->flags & SYMBOL_WRITE))
if (choice) { continue;
struct symbol *ds; sym->flags &= ~SYMBOL_WRITE;
/* Skip unchangeable symbols */
ds = sym_choice_default(choice->sym); if (!sym_is_changeable(sym))
if (sym == ds) { continue;
if ((sym->type == S_BOOLEAN) && /* Skip symbols that are equal to the default */
sym_get_tristate_value(sym) == yes) if (!strcmp(sym_get_string_value(sym), sym_get_string_default(sym)))
continue; continue;
}
} /* Skip choice values that are equal to the default */
print_symbol_for_dotconfig(out, sym); choice = sym_get_choice_menu(sym);
if (choice) {
struct symbol *ds;
ds = sym_choice_default(choice);
if (sym == ds && sym_get_tristate_value(sym) == yes)
continue;
} }
print_symbol_for_dotconfig(out, sym);
} }
fclose(out); fclose(out);
return 0; return 0;
...@@ -1141,16 +1112,14 @@ int conf_write_autoconf(int overwrite) ...@@ -1141,16 +1112,14 @@ int conf_write_autoconf(int overwrite)
} }
static bool conf_changed; static bool conf_changed;
static void (*conf_changed_callback)(void); static void (*conf_changed_callback)(bool);
void conf_set_changed(bool val) void conf_set_changed(bool val)
{ {
bool changed = conf_changed != val; if (conf_changed_callback && conf_changed != val)
conf_changed_callback(val);
conf_changed = val; conf_changed = val;
if (conf_changed_callback && changed)
conf_changed_callback();
} }
bool conf_get_changed(void) bool conf_get_changed(void)
...@@ -1158,27 +1127,7 @@ bool conf_get_changed(void) ...@@ -1158,27 +1127,7 @@ bool conf_get_changed(void)
return conf_changed; return conf_changed;
} }
void conf_set_changed_callback(void (*fn)(void)) void conf_set_changed_callback(void (*fn)(bool))
{ {
conf_changed_callback = fn; conf_changed_callback = fn;
} }
void set_all_choice_values(struct symbol *csym)
{
struct property *prop;
struct symbol *sym;
struct expr *e;
prop = sym_get_choice_prop(csym);
/*
* Set all non-assinged choice values to no
*/
expr_list_for_each_sym(prop->expr, e, sym) {
if (!sym_has_value(sym))
sym->def[S_DEF_USER].tri = no;
}
csym->flags |= SYMBOL_DEF_USER;
/* clear VALID to get value calculated */
csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
}
...@@ -90,7 +90,6 @@ struct expr *expr_copy(const struct expr *org) ...@@ -90,7 +90,6 @@ struct expr *expr_copy(const struct expr *org)
break; break;
case E_AND: case E_AND:
case E_OR: case E_OR:
case E_LIST:
e->left.expr = expr_copy(org->left.expr); e->left.expr = expr_copy(org->left.expr);
e->right.expr = expr_copy(org->right.expr); e->right.expr = expr_copy(org->right.expr);
break; break;
...@@ -136,9 +135,6 @@ void expr_free(struct expr *e) ...@@ -136,9 +135,6 @@ void expr_free(struct expr *e)
static int trans_count; static int trans_count;
#define e1 (*ep1)
#define e2 (*ep2)
/* /*
* expr_eliminate_eq() helper. * expr_eliminate_eq() helper.
* *
...@@ -151,38 +147,38 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e ...@@ -151,38 +147,38 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
{ {
/* Recurse down to leaves */ /* Recurse down to leaves */
if (e1->type == type) { if ((*ep1)->type == type) {
__expr_eliminate_eq(type, &e1->left.expr, &e2); __expr_eliminate_eq(type, &(*ep1)->left.expr, ep2);
__expr_eliminate_eq(type, &e1->right.expr, &e2); __expr_eliminate_eq(type, &(*ep1)->right.expr, ep2);
return; return;
} }
if (e2->type == type) { if ((*ep2)->type == type) {
__expr_eliminate_eq(type, &e1, &e2->left.expr); __expr_eliminate_eq(type, ep1, &(*ep2)->left.expr);
__expr_eliminate_eq(type, &e1, &e2->right.expr); __expr_eliminate_eq(type, ep1, &(*ep2)->right.expr);
return; return;
} }
/* e1 and e2 are leaves. Compare them. */ /* *ep1 and *ep2 are leaves. Compare them. */
if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && if ((*ep1)->type == E_SYMBOL && (*ep2)->type == E_SYMBOL &&
e1->left.sym == e2->left.sym && (*ep1)->left.sym == (*ep2)->left.sym &&
(e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) ((*ep1)->left.sym == &symbol_yes || (*ep1)->left.sym == &symbol_no))
return; return;
if (!expr_eq(e1, e2)) if (!expr_eq(*ep1, *ep2))
return; return;
/* e1 and e2 are equal leaves. Prepare them for elimination. */ /* *ep1 and *ep2 are equal leaves. Prepare them for elimination. */
trans_count++; trans_count++;
expr_free(e1); expr_free(e2); expr_free(*ep1); expr_free(*ep2);
switch (type) { switch (type) {
case E_OR: case E_OR:
e1 = expr_alloc_symbol(&symbol_no); *ep1 = expr_alloc_symbol(&symbol_no);
e2 = expr_alloc_symbol(&symbol_no); *ep2 = expr_alloc_symbol(&symbol_no);
break; break;
case E_AND: case E_AND:
e1 = expr_alloc_symbol(&symbol_yes); *ep1 = expr_alloc_symbol(&symbol_yes);
e2 = expr_alloc_symbol(&symbol_yes); *ep2 = expr_alloc_symbol(&symbol_yes);
break; break;
default: default:
; ;
...@@ -220,29 +216,26 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e ...@@ -220,29 +216,26 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
*/ */
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{ {
if (!e1 || !e2) if (!*ep1 || !*ep2)
return; return;
switch (e1->type) { switch ((*ep1)->type) {
case E_OR: case E_OR:
case E_AND: case E_AND:
__expr_eliminate_eq(e1->type, ep1, ep2); __expr_eliminate_eq((*ep1)->type, ep1, ep2);
default: default:
; ;
} }
if (e1->type != e2->type) switch (e2->type) { if ((*ep1)->type != (*ep2)->type) switch ((*ep2)->type) {
case E_OR: case E_OR:
case E_AND: case E_AND:
__expr_eliminate_eq(e2->type, ep1, ep2); __expr_eliminate_eq((*ep2)->type, ep1, ep2);
default: default:
; ;
} }
e1 = expr_eliminate_yn(e1); *ep1 = expr_eliminate_yn(*ep1);
e2 = expr_eliminate_yn(e2); *ep2 = expr_eliminate_yn(*ep2);
} }
#undef e1
#undef e2
/* /*
* Returns true if 'e1' and 'e2' are equal, after minor simplification. Two * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
* &&/|| expressions are considered equal if every operand in one expression * &&/|| expressions are considered equal if every operand in one expression
...@@ -286,7 +279,6 @@ int expr_eq(struct expr *e1, struct expr *e2) ...@@ -286,7 +279,6 @@ int expr_eq(struct expr *e1, struct expr *e2)
expr_free(e2); expr_free(e2);
trans_count = old_count; trans_count = old_count;
return res; return res;
case E_LIST:
case E_RANGE: case E_RANGE:
case E_NONE: case E_NONE:
/* panic */; /* panic */;
...@@ -566,59 +558,55 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2) ...@@ -566,59 +558,55 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
*/ */
static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
{ {
#define e1 (*ep1)
#define e2 (*ep2)
struct expr *tmp; struct expr *tmp;
/* Recurse down to leaves */ /* Recurse down to leaves */
if (e1->type == type) { if ((*ep1)->type == type) {
expr_eliminate_dups1(type, &e1->left.expr, &e2); expr_eliminate_dups1(type, &(*ep1)->left.expr, ep2);
expr_eliminate_dups1(type, &e1->right.expr, &e2); expr_eliminate_dups1(type, &(*ep1)->right.expr, ep2);
return; return;
} }
if (e2->type == type) { if ((*ep2)->type == type) {
expr_eliminate_dups1(type, &e1, &e2->left.expr); expr_eliminate_dups1(type, ep1, &(*ep2)->left.expr);
expr_eliminate_dups1(type, &e1, &e2->right.expr); expr_eliminate_dups1(type, ep1, &(*ep2)->right.expr);
return; return;
} }
/* e1 and e2 are leaves. Compare and process them. */ /* *ep1 and *ep2 are leaves. Compare and process them. */
if (e1 == e2) if (*ep1 == *ep2)
return; return;
switch (e1->type) { switch ((*ep1)->type) {
case E_OR: case E_AND: case E_OR: case E_AND:
expr_eliminate_dups1(e1->type, &e1, &e1); expr_eliminate_dups1((*ep1)->type, ep1, ep1);
default: default:
; ;
} }
switch (type) { switch (type) {
case E_OR: case E_OR:
tmp = expr_join_or(e1, e2); tmp = expr_join_or(*ep1, *ep2);
if (tmp) { if (tmp) {
expr_free(e1); expr_free(e2); expr_free(*ep1); expr_free(*ep2);
e1 = expr_alloc_symbol(&symbol_no); *ep1 = expr_alloc_symbol(&symbol_no);
e2 = tmp; *ep2 = tmp;
trans_count++; trans_count++;
} }
break; break;
case E_AND: case E_AND:
tmp = expr_join_and(e1, e2); tmp = expr_join_and(*ep1, *ep2);
if (tmp) { if (tmp) {
expr_free(e1); expr_free(e2); expr_free(*ep1); expr_free(*ep2);
e1 = expr_alloc_symbol(&symbol_yes); *ep1 = expr_alloc_symbol(&symbol_yes);
e2 = tmp; *ep2 = tmp;
trans_count++; trans_count++;
} }
break; break;
default: default:
; ;
} }
#undef e1
#undef e2
} }
/* /*
...@@ -639,7 +627,7 @@ struct expr *expr_eliminate_dups(struct expr *e) ...@@ -639,7 +627,7 @@ struct expr *expr_eliminate_dups(struct expr *e)
return e; return e;
oldcount = trans_count; oldcount = trans_count;
while (1) { do {
trans_count = 0; trans_count = 0;
switch (e->type) { switch (e->type) {
case E_OR: case E_AND: case E_OR: case E_AND:
...@@ -647,11 +635,8 @@ struct expr *expr_eliminate_dups(struct expr *e) ...@@ -647,11 +635,8 @@ struct expr *expr_eliminate_dups(struct expr *e)
default: default:
; ;
} }
if (!trans_count)
/* No simplifications done in this pass. We're done */
break;
e = expr_eliminate_yn(e); e = expr_eliminate_yn(e);
} } while (trans_count); /* repeat until we get no more simplifications */
trans_count = oldcount; trans_count = oldcount;
return e; return e;
} }
...@@ -676,7 +661,6 @@ struct expr *expr_transform(struct expr *e) ...@@ -676,7 +661,6 @@ struct expr *expr_transform(struct expr *e)
case E_LTH: case E_LTH:
case E_UNEQUAL: case E_UNEQUAL:
case E_SYMBOL: case E_SYMBOL:
case E_LIST:
break; break;
default: default:
e->left.expr = expr_transform(e->left.expr); e->left.expr = expr_transform(e->left.expr);
...@@ -947,7 +931,6 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb ...@@ -947,7 +931,6 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
break; break;
case E_SYMBOL: case E_SYMBOL:
return expr_alloc_comp(type, e->left.sym, sym); return expr_alloc_comp(type, e->left.sym, sym);
case E_LIST:
case E_RANGE: case E_RANGE:
case E_NONE: case E_NONE:
/* panic */; /* panic */;
...@@ -1083,29 +1066,27 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2) ...@@ -1083,29 +1066,27 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
case E_GTH: case E_GTH:
if (t2 == E_EQUAL || t2 == E_UNEQUAL) if (t2 == E_EQUAL || t2 == E_UNEQUAL)
return 1; return 1;
/* fallthrough */
case E_EQUAL: case E_EQUAL:
case E_UNEQUAL: case E_UNEQUAL:
if (t2 == E_NOT) if (t2 == E_NOT)
return 1; return 1;
/* fallthrough */
case E_NOT: case E_NOT:
if (t2 == E_AND) if (t2 == E_AND)
return 1; return 1;
/* fallthrough */
case E_AND: case E_AND:
if (t2 == E_OR) if (t2 == E_OR)
return 1; return 1;
case E_OR: /* fallthrough */
if (t2 == E_LIST)
return 1;
case E_LIST:
if (t2 == 0)
return 1;
default: default:
return -1; break;
} }
return 0; return 0;
} }
void expr_print(struct expr *e, void expr_print(const struct expr *e,
void (*fn)(void *, struct symbol *, const char *), void (*fn)(void *, struct symbol *, const char *),
void *data, int prevtoken) void *data, int prevtoken)
{ {
...@@ -1171,13 +1152,6 @@ void expr_print(struct expr *e, ...@@ -1171,13 +1152,6 @@ void expr_print(struct expr *e,
fn(data, NULL, " && "); fn(data, NULL, " && ");
expr_print(e->right.expr, fn, data, E_AND); expr_print(e->right.expr, fn, data, E_AND);
break; break;
case E_LIST:
fn(data, e->right.sym, e->right.sym->name);
if (e->left.expr) {
fn(data, NULL, " ^ ");
expr_print(e->left.expr, fn, data, E_LIST);
}
break;
case E_RANGE: case E_RANGE:
fn(data, NULL, "["); fn(data, NULL, "[");
fn(data, e->left.sym, e->left.sym->name); fn(data, e->left.sym, e->left.sym->name);
...@@ -1237,7 +1211,7 @@ static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *s ...@@ -1237,7 +1211,7 @@ static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *s
str_printf(gs, " [=%s]", sym_str); str_printf(gs, " [=%s]", sym_str);
} }
void expr_gstr_print(struct expr *e, struct gstr *gs) void expr_gstr_print(const struct expr *e, struct gstr *gs)
{ {
expr_print(e, expr_print_gstr_helper, gs, E_NONE); expr_print(e, expr_print_gstr_helper, gs, E_NONE);
} }
......
...@@ -12,12 +12,11 @@ extern "C" { ...@@ -12,12 +12,11 @@ extern "C" {
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include "list_types.h"
#ifndef __cplusplus #ifndef __cplusplus
#include <stdbool.h> #include <stdbool.h>
#endif #endif
#include "list_types.h" #include <list_types.h>
typedef enum tristate { typedef enum tristate {
no, mod, yes no, mod, yes
...@@ -26,7 +25,7 @@ typedef enum tristate { ...@@ -26,7 +25,7 @@ typedef enum tristate {
enum expr_type { enum expr_type {
E_NONE, E_OR, E_AND, E_NOT, E_NONE, E_OR, E_AND, E_NOT,
E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ, E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ,
E_LIST, E_SYMBOL, E_RANGE E_SYMBOL, E_RANGE
}; };
union expr_data { union expr_data {
...@@ -43,9 +42,6 @@ struct expr { ...@@ -43,9 +42,6 @@ struct expr {
#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) #define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
#define EXPR_NOT(dep) (2-(dep)) #define EXPR_NOT(dep) (2-(dep))
#define expr_list_for_each_sym(l, e, s) \
for (e = (l); e && (s = e->right.sym); e = e->left.expr)
struct expr_value { struct expr_value {
struct expr *expr; struct expr *expr;
tristate tri; tristate tri;
...@@ -73,6 +69,8 @@ enum { ...@@ -73,6 +69,8 @@ enum {
* Represents a configuration symbol. * Represents a configuration symbol.
* *
* Choices are represented as a special kind of symbol with null name. * Choices are represented as a special kind of symbol with null name.
*
* @choice_link: linked to menu::choice_members
*/ */
struct symbol { struct symbol {
/* link node for the hash table */ /* link node for the hash table */
...@@ -110,6 +108,8 @@ struct symbol { ...@@ -110,6 +108,8 @@ struct symbol {
/* config entries associated with this symbol */ /* config entries associated with this symbol */
struct list_head menus; struct list_head menus;
struct list_head choice_link;
/* SYMBOL_* flags */ /* SYMBOL_* flags */
int flags; int flags;
...@@ -130,10 +130,8 @@ struct symbol { ...@@ -130,10 +130,8 @@ struct symbol {
#define SYMBOL_CONST 0x0001 /* symbol is const */ #define SYMBOL_CONST 0x0001 /* symbol is const */
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ #define SYMBOL_CHECK 0x0008 /* used during dependency checking */
#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ #define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
#define SYMBOL_CHANGED 0x0400 /* ? */
#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */ #define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
#define SYMBOL_WARNED 0x8000 /* warning has been issued */ #define SYMBOL_WARNED 0x8000 /* warning has been issued */
...@@ -145,9 +143,6 @@ struct symbol { ...@@ -145,9 +143,6 @@ struct symbol {
#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
/* choice values need to be set before calculating this symbol value */
#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
#define SYMBOL_MAXLENGTH 256 #define SYMBOL_MAXLENGTH 256
/* A property represent the config options that can be associated /* A property represent the config options that can be associated
...@@ -170,7 +165,6 @@ enum prop_type { ...@@ -170,7 +165,6 @@ enum prop_type {
P_COMMENT, /* text associated with a comment */ P_COMMENT, /* text associated with a comment */
P_MENU, /* prompt associated with a menu or menuconfig symbol */ P_MENU, /* prompt associated with a menu or menuconfig symbol */
P_DEFAULT, /* default y */ P_DEFAULT, /* default y */
P_CHOICE, /* choice value */
P_SELECT, /* select BAR */ P_SELECT, /* select BAR */
P_IMPLY, /* imply BAR */ P_IMPLY, /* imply BAR */
P_RANGE, /* range 7..100 (for a symbol) */ P_RANGE, /* range 7..100 (for a symbol) */
...@@ -184,7 +178,7 @@ struct property { ...@@ -184,7 +178,7 @@ struct property {
struct expr_value visible; struct expr_value visible;
struct expr *expr; /* the optional conditional part of the property */ struct expr *expr; /* the optional conditional part of the property */
struct menu *menu; /* the menu the property are associated with struct menu *menu; /* the menu the property are associated with
* valid for: P_SELECT, P_RANGE, P_CHOICE, * valid for: P_SELECT, P_RANGE,
* P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
const char *filename; /* what file was this property defined */ const char *filename; /* what file was this property defined */
int lineno; /* what lineno was this property defined */ int lineno; /* what lineno was this property defined */
...@@ -194,7 +188,6 @@ struct property { ...@@ -194,7 +188,6 @@ struct property {
for (st = sym->prop; st; st = st->next) \ for (st = sym->prop; st; st = st->next) \
if (st->type == (tok)) if (st->type == (tok))
#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) #define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
#define for_all_prompts(sym, st) \ #define for_all_prompts(sym, st) \
for (st = sym->prop; st; st = st->next) \ for (st = sym->prop; st; st = st->next) \
if (st->text) if (st->text)
...@@ -204,6 +197,8 @@ struct property { ...@@ -204,6 +197,8 @@ struct property {
* for all front ends). Each symbol, menu, etc. defined in the Kconfig files * for all front ends). Each symbol, menu, etc. defined in the Kconfig files
* gets a node. A symbol defined in multiple locations gets one node at each * gets a node. A symbol defined in multiple locations gets one node at each
* location. * location.
*
* @choice_members: list of choice members with priority.
*/ */
struct menu { struct menu {
/* The next menu node at the same level */ /* The next menu node at the same level */
...@@ -223,6 +218,8 @@ struct menu { ...@@ -223,6 +218,8 @@ struct menu {
struct list_head link; /* link to symbol::menus */ struct list_head link; /* link to symbol::menus */
struct list_head choice_members;
/* /*
* The prompt associated with the node. This holds the prompt for a * The prompt associated with the node. This holds the prompt for a
* symbol as well as the text for a menu or comment, along with the * symbol as well as the text for a menu or comment, along with the
...@@ -292,11 +289,11 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb ...@@ -292,11 +289,11 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
void expr_fprint(struct expr *e, FILE *out); void expr_fprint(struct expr *e, FILE *out);
struct gstr; /* forward */ struct gstr; /* forward */
void expr_gstr_print(struct expr *e, struct gstr *gs); void expr_gstr_print(const struct expr *e, struct gstr *gs);
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
tristate pr_type, const char *title); tristate pr_type, const char *title);
static inline int expr_is_yes(struct expr *e) static inline int expr_is_yes(const struct expr *e)
{ {
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
} }
......
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1 cflags=$1
libs=$2 libs=$2
......
...@@ -65,9 +65,6 @@ static void display_list(void); ...@@ -65,9 +65,6 @@ static void display_list(void);
static void display_tree(struct menu *menu); static void display_tree(struct menu *menu);
static void display_tree_part(void); static void display_tree_part(void);
static void update_tree(struct menu *src, GtkTreeIter * dst); static void update_tree(struct menu *src, GtkTreeIter * dst);
static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
static gchar **fill_row(struct menu *menu);
static void conf_changed(void);
static void replace_button_icon(GladeXML *xml, GdkDrawable *window, static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
GtkStyle *style, gchar *btn_name, gchar **xpm) GtkStyle *style, gchar *btn_name, gchar **xpm)
...@@ -87,6 +84,12 @@ static void replace_button_icon(GladeXML *xml, GdkDrawable *window, ...@@ -87,6 +84,12 @@ static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
gtk_tool_button_set_icon_widget(button, image); gtk_tool_button_set_icon_widget(button, image);
} }
static void conf_changed(bool dirty)
{
gtk_widget_set_sensitive(save_btn, dirty);
gtk_widget_set_sensitive(save_menu_item, dirty);
}
/* Main Window Initialization */ /* Main Window Initialization */
static void init_main_window(const gchar *glade_file) static void init_main_window(const gchar *glade_file)
{ {
...@@ -1051,7 +1054,7 @@ static gchar **fill_row(struct menu *menu) ...@@ -1051,7 +1054,7 @@ static gchar **fill_row(struct menu *menu)
if (sym_is_choice(sym)) { // parse childs for getting final value if (sym_is_choice(sym)) { // parse childs for getting final value
struct menu *child; struct menu *child;
struct symbol *def_sym = sym_get_choice_value(sym); struct symbol *def_sym = sym_calc_choice(menu);
struct menu *def_menu = NULL; struct menu *def_menu = NULL;
for (child = menu->list; child; child = child->next) { for (child = menu->list; child; child = child->next) {
...@@ -1064,12 +1067,10 @@ static gchar **fill_row(struct menu *menu) ...@@ -1064,12 +1067,10 @@ static gchar **fill_row(struct menu *menu)
row[COL_VALUE] = row[COL_VALUE] =
g_strdup(menu_get_prompt(def_menu)); g_strdup(menu_get_prompt(def_menu));
if (sym_get_type(sym) == S_BOOLEAN) { row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); return row;
return row;
}
} }
if (sym->flags & SYMBOL_CHOICEVAL) if (sym_is_choice_value(sym))
row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
stype = sym_get_type(sym); stype = sym_get_type(sym);
...@@ -1447,10 +1448,3 @@ int main(int ac, char *av[]) ...@@ -1447,10 +1448,3 @@ int main(int ac, char *av[])
return 0; return 0;
} }
static void conf_changed(void)
{
bool changed = conf_get_changed();
gtk_widget_set_sensitive(save_btn, changed);
gtk_widget_set_sensitive(save_menu_item, changed);
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#ifndef INTERNAL_H #ifndef INTERNAL_H
#define INTERNAL_H #define INTERNAL_H
#include "hashtable.h" #include <hashtable.h>
#define SYMBOL_HASHSIZE (1U << 14) #define SYMBOL_HASHSIZE (1U << 14)
......
...@@ -40,7 +40,6 @@ void zconf_nextfile(const char *name); ...@@ -40,7 +40,6 @@ void zconf_nextfile(const char *name);
/* confdata.c */ /* confdata.c */
extern struct gstr autoconf_cmd; extern struct gstr autoconf_cmd;
const char *conf_get_configname(void); const char *conf_get_configname(void);
void set_all_choice_values(struct symbol *csym);
/* confdata.c and expr.c */ /* confdata.c and expr.c */
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
...@@ -76,7 +75,7 @@ struct gstr str_new(void); ...@@ -76,7 +75,7 @@ struct gstr str_new(void);
void str_free(struct gstr *gs); void str_free(struct gstr *gs);
void str_append(struct gstr *gs, const char *s); void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...); void str_printf(struct gstr *gs, const char *fmt, ...);
char *str_get(struct gstr *gs); char *str_get(const struct gstr *gs);
/* menu.c */ /* menu.c */
struct menu *menu_next(struct menu *menu, struct menu *root); struct menu *menu_next(struct menu *menu, struct menu *root);
...@@ -85,13 +84,14 @@ struct menu *menu_next(struct menu *menu, struct menu *root); ...@@ -85,13 +84,14 @@ struct menu *menu_next(struct menu *menu, struct menu *root);
#define menu_for_each_entry(menu) \ #define menu_for_each_entry(menu) \
menu_for_each_sub_entry(menu, &rootmenu) menu_for_each_sub_entry(menu, &rootmenu)
void _menu_init(void); void _menu_init(void);
void menu_warn(struct menu *menu, const char *fmt, ...); void menu_warn(const struct menu *menu, const char *fmt, ...);
struct menu *menu_add_menu(void); struct menu *menu_add_menu(void);
void menu_end_menu(void); void menu_end_menu(void);
void menu_add_entry(struct symbol *sym); void menu_add_entry(struct symbol *sym);
void menu_add_dep(struct expr *dep); void menu_add_dep(struct expr *dep);
void menu_add_visibility(struct expr *dep); void menu_add_visibility(struct expr *dep);
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); struct property *menu_add_prompt(enum prop_type type, const char *prompt,
struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
void menu_finalize(void); void menu_finalize(void);
...@@ -101,8 +101,8 @@ extern struct menu rootmenu; ...@@ -101,8 +101,8 @@ extern struct menu rootmenu;
bool menu_is_empty(struct menu *menu); bool menu_is_empty(struct menu *menu);
bool menu_is_visible(struct menu *menu); bool menu_is_visible(struct menu *menu);
bool menu_has_prompt(struct menu *menu); bool menu_has_prompt(const struct menu *menu);
const char *menu_get_prompt(struct menu *menu); const char *menu_get_prompt(const struct menu *menu);
struct menu *menu_get_parent_menu(struct menu *menu); struct menu *menu_get_parent_menu(struct menu *menu);
int get_jump_key_char(void); int get_jump_key_char(void);
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
...@@ -110,35 +110,27 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help); ...@@ -110,35 +110,27 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help);
/* symbol.c */ /* symbol.c */
void sym_clear_all_valid(void); void sym_clear_all_valid(void);
struct symbol *sym_choice_default(struct symbol *sym); struct symbol *sym_choice_default(struct menu *choice);
struct symbol *sym_calc_choice(struct menu *choice);
struct property *sym_get_range_prop(struct symbol *sym); struct property *sym_get_range_prop(struct symbol *sym);
const char *sym_get_string_default(struct symbol *sym); const char *sym_get_string_default(struct symbol *sym);
struct symbol *sym_check_deps(struct symbol *sym); struct symbol *sym_check_deps(struct symbol *sym);
struct symbol *prop_get_symbol(struct property *prop); struct symbol *prop_get_symbol(const struct property *prop);
static inline tristate sym_get_tristate_value(struct symbol *sym) static inline tristate sym_get_tristate_value(const struct symbol *sym)
{ {
return sym->curr.tri; return sym->curr.tri;
} }
static inline bool sym_is_choice(const struct symbol *sym)
static inline struct symbol *sym_get_choice_value(struct symbol *sym)
{
return (struct symbol *)sym->curr.val;
}
static inline bool sym_is_choice(struct symbol *sym)
{ {
/* A choice is a symbol with no name */ /* A choice is a symbol with no name */
return sym->name == NULL; return sym->name == NULL;
} }
static inline bool sym_is_choice_value(struct symbol *sym) bool sym_is_choice_value(const struct symbol *sym);
{
return sym->flags & SYMBOL_CHOICEVAL ? true : false;
}
static inline bool sym_has_value(struct symbol *sym) static inline bool sym_has_value(const struct symbol *sym)
{ {
return sym->flags & SYMBOL_DEF_USER ? true : false; return sym->flags & SYMBOL_DEF_USER ? true : false;
} }
......
...@@ -13,7 +13,7 @@ int conf_write(const char *name); ...@@ -13,7 +13,7 @@ int conf_write(const char *name);
int conf_write_autoconf(int overwrite); int conf_write_autoconf(int overwrite);
void conf_set_changed(bool val); void conf_set_changed(bool val);
bool conf_get_changed(void); bool conf_get_changed(void);
void conf_set_changed_callback(void (*fn)(void)); void conf_set_changed_callback(void (*fn)(bool));
void conf_set_message_callback(void (*fn)(const char *s)); void conf_set_message_callback(void (*fn)(const char *s));
bool conf_errors(void); bool conf_errors(void);
...@@ -25,21 +25,23 @@ struct symbol ** sym_re_search(const char *pattern); ...@@ -25,21 +25,23 @@ struct symbol ** sym_re_search(const char *pattern);
const char * sym_type_name(enum symbol_type type); const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym); void sym_calc_value(struct symbol *sym);
bool sym_dep_errors(void); bool sym_dep_errors(void);
enum symbol_type sym_get_type(struct symbol *sym); enum symbol_type sym_get_type(const struct symbol *sym);
bool sym_tristate_within_range(struct symbol *sym,tristate tri); bool sym_tristate_within_range(const struct symbol *sym, tristate tri);
bool sym_set_tristate_value(struct symbol *sym,tristate tri); bool sym_set_tristate_value(struct symbol *sym,tristate tri);
void choice_set_value(struct menu *choice, struct symbol *sym);
tristate sym_toggle_tristate_value(struct symbol *sym); tristate sym_toggle_tristate_value(struct symbol *sym);
bool sym_string_valid(struct symbol *sym, const char *newval); bool sym_string_valid(struct symbol *sym, const char *newval);
bool sym_string_within_range(struct symbol *sym, const char *str); bool sym_string_within_range(struct symbol *sym, const char *str);
bool sym_set_string_value(struct symbol *sym, const char *newval); bool sym_set_string_value(struct symbol *sym, const char *newval);
bool sym_is_changeable(struct symbol *sym); bool sym_is_changeable(const struct symbol *sym);
struct property * sym_get_choice_prop(struct symbol *sym); struct menu *sym_get_choice_menu(const struct symbol *sym);
struct menu *sym_get_choice_menu(struct symbol *sym);
const char * sym_get_string_value(struct symbol *sym); const char * sym_get_string_value(struct symbol *sym);
const char * prop_get_type_name(enum prop_type type); const char * prop_get_type_name(enum prop_type type);
/* expr.c */ /* expr.c */
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); void expr_print(const struct expr *e,
void (*fn)(void *, struct symbol *, const char *),
void *data, int prevtoken);
#endif /* LKC_PROTO_H */ #endif /* LKC_PROTO_H */
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1 cflags=$1
libs=$2 libs=$2
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include "list.h" #include <list.h>
#include "lkc.h" #include "lkc.h"
#include "lxdialog/dialog.h" #include "lxdialog/dialog.h"
#include "mnconf-common.h" #include "mnconf-common.h"
...@@ -514,7 +514,7 @@ static void build_conf(struct menu *menu) ...@@ -514,7 +514,7 @@ static void build_conf(struct menu *menu)
type = sym_get_type(sym); type = sym_get_type(sym);
if (sym_is_choice(sym)) { if (sym_is_choice(sym)) {
struct symbol *def_sym = sym_get_choice_value(sym); struct symbol *def_sym = sym_calc_choice(menu);
struct menu *def_menu = NULL; struct menu *def_menu = NULL;
child_count++; child_count++;
...@@ -523,28 +523,14 @@ static void build_conf(struct menu *menu) ...@@ -523,28 +523,14 @@ static void build_conf(struct menu *menu)
def_menu = child; def_menu = child;
} }
val = sym_get_tristate_value(sym); item_make(" ");
if (sym_is_changeable(sym)) { item_set_tag(def_menu ? 't' : ':');
switch (val) { item_set_data(menu);
case yes: ch = '*'; break;
case mod: ch = 'M'; break;
default: ch = ' '; break;
}
item_make("<%c>", ch);
item_set_tag('t');
item_set_data(menu);
} else {
item_make(" ");
item_set_tag(def_menu ? 't' : ':');
item_set_data(menu);
}
item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
if (val == yes) { if (def_menu)
if (def_menu) item_add_str(" (%s) --->", menu_get_prompt(def_menu));
item_add_str(" (%s) --->", menu_get_prompt(def_menu)); return;
return;
}
} else { } else {
if (menu == current_menu) { if (menu == current_menu) {
item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
...@@ -614,7 +600,7 @@ static void conf_choice(struct menu *menu) ...@@ -614,7 +600,7 @@ static void conf_choice(struct menu *menu)
struct menu *child; struct menu *child;
struct symbol *active; struct symbol *active;
active = sym_get_choice_value(menu->sym); active = sym_calc_choice(menu);
while (1) { while (1) {
int res; int res;
int selected; int selected;
...@@ -633,7 +619,7 @@ static void conf_choice(struct menu *menu) ...@@ -633,7 +619,7 @@ static void conf_choice(struct menu *menu)
item_set_data(child); item_set_data(child);
if (child->sym == active) if (child->sym == active)
item_set_selected(1); item_set_selected(1);
if (child->sym == sym_get_choice_value(menu->sym)) if (child->sym == sym_calc_choice(menu))
item_set_tag('X'); item_set_tag('X');
} }
dialog_clear(); dialog_clear();
...@@ -650,7 +636,7 @@ static void conf_choice(struct menu *menu) ...@@ -650,7 +636,7 @@ static void conf_choice(struct menu *menu)
if (!child->sym) if (!child->sym)
break; break;
sym_set_tristate_value(child->sym, yes); choice_set_value(menu, child->sym);
} }
return; return;
case 1: case 1:
...@@ -814,7 +800,7 @@ static void conf(struct menu *menu, struct menu *active_menu) ...@@ -814,7 +800,7 @@ static void conf(struct menu *menu, struct menu *active_menu)
conf(submenu, NULL); conf(submenu, NULL);
break; break;
case 't': case 't':
if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) if (sym_is_choice(sym))
conf_choice(submenu); conf_choice(submenu);
else if (submenu->prompt->type == P_MENU) else if (submenu->prompt->type == P_MENU)
conf(submenu, NULL); conf(submenu, NULL);
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <list.h>
#include "lkc.h" #include "lkc.h"
#include "internal.h" #include "internal.h"
#include "list.h"
static const char nohelp_text[] = "There is no help available for this option."; static const char nohelp_text[] = "There is no help available for this option.";
...@@ -38,7 +38,7 @@ struct menu *menu_next(struct menu *menu, struct menu *root) ...@@ -38,7 +38,7 @@ struct menu *menu_next(struct menu *menu, struct menu *root)
return menu->next; return menu->next;
} }
void menu_warn(struct menu *menu, const char *fmt, ...) void menu_warn(const struct menu *menu, const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
...@@ -48,7 +48,7 @@ void menu_warn(struct menu *menu, const char *fmt, ...) ...@@ -48,7 +48,7 @@ void menu_warn(struct menu *menu, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
static void prop_warn(struct property *prop, const char *fmt, ...) static void prop_warn(const struct property *prop, const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
...@@ -175,7 +175,7 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr, ...@@ -175,7 +175,7 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
return prop; return prop;
} }
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct property *menu_add_prompt(enum prop_type type, const char *prompt,
struct expr *dep) struct expr *dep)
{ {
struct property *prop = menu_add_prop(type, NULL, dep); struct property *prop = menu_add_prop(type, NULL, dep);
...@@ -306,7 +306,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) ...@@ -306,7 +306,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
struct menu *menu, *last_menu; struct menu *menu, *last_menu;
struct symbol *sym; struct symbol *sym;
struct property *prop; struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2, **ep; struct expr *basedep, *dep, *dep2;
sym = parent->sym; sym = parent->sym;
if (parent->list) { if (parent->list) {
...@@ -315,35 +315,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) ...@@ -315,35 +315,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
* and propagate parent dependencies before moving on. * and propagate parent dependencies before moving on.
*/ */
bool is_choice = false;
if (sym && sym_is_choice(sym))
is_choice = true;
if (is_choice) {
if (sym->type == S_UNKNOWN) {
/* find the first choice value to find out choice type */
current_entry = parent;
for (menu = parent->list; menu; menu = menu->next) {
if (menu->sym && menu->sym->type != S_UNKNOWN) {
menu_set_type(menu->sym->type);
break;
}
}
}
/*
* Use the choice itself as the parent dependency of
* the contained items. This turns the mode of the
* choice into an upper bound on the visibility of the
* choice value symbols.
*/
parentdep = expr_alloc_symbol(sym);
} else {
/* Menu node for 'menu', 'if' */
parentdep = parent->dep;
}
/* For each child menu node... */ /* For each child menu node... */
for (menu = parent->list; menu; menu = menu->next) { for (menu = parent->list; menu; menu = menu->next) {
/* /*
...@@ -352,7 +323,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) ...@@ -352,7 +323,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
*/ */
basedep = rewrite_m(menu->dep); basedep = rewrite_m(menu->dep);
basedep = expr_transform(basedep); basedep = expr_transform(basedep);
basedep = expr_alloc_and(expr_copy(parentdep), basedep); basedep = expr_alloc_and(expr_copy(parent->dep), basedep);
basedep = expr_eliminate_dups(basedep); basedep = expr_eliminate_dups(basedep);
menu->dep = basedep; menu->dep = basedep;
...@@ -416,15 +387,12 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) ...@@ -416,15 +387,12 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
} }
} }
if (is_choice)
expr_free(parentdep);
/* /*
* Recursively process children in the same fashion before * Recursively process children in the same fashion before
* moving on * moving on
*/ */
for (menu = parent->list; menu; menu = menu->next) for (menu = parent->list; menu; menu = menu->next)
_menu_finalize(menu, is_choice); _menu_finalize(menu, sym && sym_is_choice(sym));
} else if (!inside_choice && sym) { } else if (!inside_choice && sym) {
/* /*
* Automatic submenu creation. If sym is a symbol and A, B, C, * Automatic submenu creation. If sym is a symbol and A, B, C,
...@@ -499,34 +467,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) ...@@ -499,34 +467,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
} }
for (menu = parent->list; menu; menu = menu->next) { for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) &&
menu->sym && !sym_is_choice_value(menu->sym)) {
current_entry = menu;
menu->sym->flags |= SYMBOL_CHOICEVAL;
/* Non-tristate choice values of tristate choices must
* depend on the choice being set to Y. The choice
* values' dependencies were propagated to their
* properties above, so the change here must be re-
* propagated.
*/
if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
menu->dep = expr_alloc_and(basedep, menu->dep);
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
prop->visible.expr = expr_alloc_and(expr_copy(basedep),
prop->visible.expr);
}
}
menu_add_symbol(P_CHOICE, sym, NULL);
prop = sym_get_choice_prop(sym);
for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
;
*ep = expr_alloc_one(E_LIST, NULL);
(*ep)->right.sym = menu->sym;
}
/* /*
* This code serves two purposes: * This code serves two purposes:
* *
...@@ -575,17 +515,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) ...@@ -575,17 +515,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
sym_check_prop(sym); sym_check_prop(sym);
sym->flags |= SYMBOL_WARNED; sym->flags |= SYMBOL_WARNED;
} }
/*
* For choices, add a reverse dependency (corresponding to a select) of
* '<visibility> && m'. This prevents the user from setting the choice
* mode to 'n' when the choice is visible.
*/
if (sym && sym_is_choice(sym) && parent->prompt) {
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
expr_alloc_and(parent->prompt->visible.expr,
expr_alloc_symbol(&symbol_mod)));
}
} }
void menu_finalize(void) void menu_finalize(void)
...@@ -593,7 +522,7 @@ void menu_finalize(void) ...@@ -593,7 +522,7 @@ void menu_finalize(void)
_menu_finalize(&rootmenu, false); _menu_finalize(&rootmenu, false);
} }
bool menu_has_prompt(struct menu *menu) bool menu_has_prompt(const struct menu *menu)
{ {
if (!menu->prompt) if (!menu->prompt)
return false; return false;
...@@ -618,7 +547,6 @@ bool menu_is_empty(struct menu *menu) ...@@ -618,7 +547,6 @@ bool menu_is_empty(struct menu *menu)
bool menu_is_visible(struct menu *menu) bool menu_is_visible(struct menu *menu)
{ {
struct menu *child;
struct symbol *sym; struct symbol *sym;
tristate visible; tristate visible;
...@@ -637,24 +565,10 @@ bool menu_is_visible(struct menu *menu) ...@@ -637,24 +565,10 @@ bool menu_is_visible(struct menu *menu)
} else } else
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
if (visible != no) return visible != no;
return true;
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
for (child = menu->list; child; child = child->next) {
if (menu_is_visible(child)) {
if (sym)
sym->flags |= SYMBOL_DEF_USER;
return true;
}
}
return false;
} }
const char *menu_get_prompt(struct menu *menu) const char *menu_get_prompt(const struct menu *menu)
{ {
if (menu->prompt) if (menu->prompt)
return menu->prompt->text; return menu->prompt->text;
...@@ -675,13 +589,14 @@ struct menu *menu_get_parent_menu(struct menu *menu) ...@@ -675,13 +589,14 @@ struct menu *menu_get_parent_menu(struct menu *menu)
return menu; return menu;
} }
static void get_def_str(struct gstr *r, struct menu *menu) static void get_def_str(struct gstr *r, const struct menu *menu)
{ {
str_printf(r, "Defined at %s:%d\n", str_printf(r, "Defined at %s:%d\n",
menu->filename, menu->lineno); menu->filename, menu->lineno);
} }
static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) static void get_dep_str(struct gstr *r, const struct expr *expr,
const char *prefix)
{ {
if (!expr_is_yes(expr)) { if (!expr_is_yes(expr)) {
str_append(r, prefix); str_append(r, prefix);
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <list.h>
#include "expr.h" #include "expr.h"
#include "list.h"
#include "mnconf-common.h" #include "mnconf-common.h"
int jump_key_char; int jump_key_char;
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <stddef.h> #include <stddef.h>
#include <list_types.h>
struct search_data { struct search_data {
struct list_head *head; struct list_head *head;
struct menu *target; struct menu *target;
......
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1 cflags=$1
libs=$2 libs=$2
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <strings.h> #include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include "list.h" #include <list.h>
#include "lkc.h" #include "lkc.h"
#include "mnconf-common.h" #include "mnconf-common.h"
#include "nconf.h" #include "nconf.h"
...@@ -815,7 +815,7 @@ static void build_conf(struct menu *menu) ...@@ -815,7 +815,7 @@ static void build_conf(struct menu *menu)
type = sym_get_type(sym); type = sym_get_type(sym);
if (sym_is_choice(sym)) { if (sym_is_choice(sym)) {
struct symbol *def_sym = sym_get_choice_value(sym); struct symbol *def_sym = sym_calc_choice(menu);
struct menu *def_menu = NULL; struct menu *def_menu = NULL;
child_count++; child_count++;
...@@ -825,30 +825,13 @@ static void build_conf(struct menu *menu) ...@@ -825,30 +825,13 @@ static void build_conf(struct menu *menu)
} }
val = sym_get_tristate_value(sym); val = sym_get_tristate_value(sym);
if (sym_is_changeable(sym)) { item_make(menu, def_menu ? 't' : ':', " ");
switch (val) {
case yes:
ch = '*';
break;
case mod:
ch = 'M';
break;
default:
ch = ' ';
break;
}
item_make(menu, 't', "<%c>", ch);
} else {
item_make(menu, def_menu ? 't' : ':', " ");
}
item_add_str("%*c%s", indent + 1, item_add_str("%*c%s", indent + 1,
' ', menu_get_prompt(menu)); ' ', menu_get_prompt(menu));
if (val == yes) { if (def_menu)
if (def_menu) item_add_str(" (%s) --->", menu_get_prompt(def_menu));
item_add_str(" (%s) --->", menu_get_prompt(def_menu)); return;
return;
}
} else { } else {
if (menu == current_menu) { if (menu == current_menu) {
item_make(menu, ':', item_make(menu, ':',
...@@ -1191,8 +1174,7 @@ static void selected_conf(struct menu *menu, struct menu *active_menu) ...@@ -1191,8 +1174,7 @@ static void selected_conf(struct menu *menu, struct menu *active_menu)
conf(submenu); conf(submenu);
break; break;
case 't': case 't':
if (sym_is_choice(sym) && if (sym_is_choice(sym))
sym_get_tristate_value(sym) == yes)
conf_choice(submenu); conf_choice(submenu);
else if (submenu->prompt && else if (submenu->prompt &&
submenu->prompt->type == P_MENU) submenu->prompt->type == P_MENU)
...@@ -1257,7 +1239,7 @@ static void conf_choice(struct menu *menu) ...@@ -1257,7 +1239,7 @@ static void conf_choice(struct menu *menu)
.pattern = "", .pattern = "",
}; };
active = sym_get_choice_value(menu->sym); active = sym_calc_choice(menu);
/* this is mostly duplicated from the conf() function. */ /* this is mostly duplicated from the conf() function. */
while (!global_exit) { while (!global_exit) {
reset_menu(); reset_menu();
...@@ -1266,7 +1248,7 @@ static void conf_choice(struct menu *menu) ...@@ -1266,7 +1248,7 @@ static void conf_choice(struct menu *menu)
if (!show_all_items && !menu_is_visible(child)) if (!show_all_items && !menu_is_visible(child))
continue; continue;
if (child->sym == sym_get_choice_value(menu->sym)) if (child->sym == sym_calc_choice(menu))
item_make(child, ':', "<X> %s", item_make(child, ':', "<X> %s",
menu_get_prompt(child)); menu_get_prompt(child));
else if (child->sym) else if (child->sym)
...@@ -1349,7 +1331,7 @@ static void conf_choice(struct menu *menu) ...@@ -1349,7 +1331,7 @@ static void conf_choice(struct menu *menu)
case ' ': case ' ':
case 10: case 10:
case KEY_RIGHT: case KEY_RIGHT:
sym_set_tristate_value(child->sym, yes); choice_set_value(menu, child->sym);
return; return;
case 'h': case 'h':
case '?': case '?':
......
...@@ -28,9 +28,7 @@ static void zconf_error(const char *err, ...); ...@@ -28,9 +28,7 @@ static void zconf_error(const char *err, ...);
static bool zconf_endtoken(const char *tokenname, static bool zconf_endtoken(const char *tokenname,
const char *expected_tokenname); const char *expected_tokenname);
struct menu *current_menu, *current_entry; struct menu *current_menu, *current_entry, *current_choice;
static bool inside_choice = false;
%} %}
...@@ -90,7 +88,7 @@ static bool inside_choice = false; ...@@ -90,7 +88,7 @@ static bool inside_choice = false;
%type <symbol> nonconst_symbol %type <symbol> nonconst_symbol
%type <symbol> symbol %type <symbol> symbol
%type <type> type logic_type default %type <type> type default
%type <expr> expr %type <expr> expr
%type <expr> if_expr %type <expr> if_expr
%type <string> end %type <string> end
...@@ -147,12 +145,21 @@ config_entry_start: T_CONFIG nonconst_symbol T_EOL ...@@ -147,12 +145,21 @@ config_entry_start: T_CONFIG nonconst_symbol T_EOL
config_stmt: config_entry_start config_option_list config_stmt: config_entry_start config_option_list
{ {
if (inside_choice) { if (current_choice) {
if (!current_entry->prompt) { if (!current_entry->prompt) {
fprintf(stderr, "%s:%d: error: choice member must have a prompt\n", fprintf(stderr, "%s:%d: error: choice member must have a prompt\n",
current_entry->filename, current_entry->lineno); current_entry->filename, current_entry->lineno);
yynerrs++; yynerrs++;
} }
if (current_entry->sym->type != S_BOOLEAN) {
fprintf(stderr, "%s:%d: error: choice member must be bool\n",
current_entry->filename, current_entry->lineno);
yynerrs++;
}
list_add_tail(&current_entry->sym->choice_link,
&current_choice->choice_members);
} }
printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
...@@ -234,7 +241,9 @@ choice: T_CHOICE T_EOL ...@@ -234,7 +241,9 @@ choice: T_CHOICE T_EOL
struct symbol *sym = sym_lookup(NULL, 0); struct symbol *sym = sym_lookup(NULL, 0);
menu_add_entry(sym); menu_add_entry(sym);
menu_add_expr(P_CHOICE, NULL, NULL); menu_set_type(S_BOOLEAN);
INIT_LIST_HEAD(&current_entry->choice_members);
printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno); printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
}; };
...@@ -248,12 +257,12 @@ choice_entry: choice choice_option_list ...@@ -248,12 +257,12 @@ choice_entry: choice choice_option_list
$$ = menu_add_menu(); $$ = menu_add_menu();
inside_choice = true; current_choice = current_entry;
}; };
choice_end: end choice_end: end
{ {
inside_choice = false; current_choice = NULL;
if (zconf_endtoken($1, "choice")) { if (zconf_endtoken($1, "choice")) {
menu_end_menu(); menu_end_menu();
...@@ -277,10 +286,10 @@ choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL ...@@ -277,10 +286,10 @@ choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
}; };
choice_option: logic_type prompt_stmt_opt T_EOL choice_option: T_BOOL T_WORD_QUOTE if_expr T_EOL
{ {
menu_set_type($1); menu_add_prompt(P_PROMPT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1); printd(DEBUG_PARSE, "%s:%d:bool\n", cur_filename, cur_lineno);
}; };
choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
...@@ -290,15 +299,12 @@ choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL ...@@ -290,15 +299,12 @@ choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
}; };
type: type:
logic_type T_BOOL { $$ = S_BOOLEAN; }
| T_TRISTATE { $$ = S_TRISTATE; }
| T_INT { $$ = S_INT; } | T_INT { $$ = S_INT; }
| T_HEX { $$ = S_HEX; } | T_HEX { $$ = S_HEX; }
| T_STRING { $$ = S_STRING; } | T_STRING { $$ = S_STRING; }
logic_type:
T_BOOL { $$ = S_BOOLEAN; }
| T_TRISTATE { $$ = S_TRISTATE; }
default: default:
T_DEFAULT { $$ = S_UNKNOWN; } T_DEFAULT { $$ = S_UNKNOWN; }
| T_DEF_BOOL { $$ = S_BOOLEAN; } | T_DEF_BOOL { $$ = S_BOOLEAN; }
...@@ -483,7 +489,7 @@ assign_val: ...@@ -483,7 +489,7 @@ assign_val:
* *
* Return: -1 if an error is found, 0 otherwise. * Return: -1 if an error is found, 0 otherwise.
*/ */
static int choice_check_sanity(struct menu *menu) static int choice_check_sanity(const struct menu *menu)
{ {
struct property *prop; struct property *prop;
int ret = 0; int ret = 0;
...@@ -638,7 +644,7 @@ static void print_quoted_string(FILE *out, const char *str) ...@@ -638,7 +644,7 @@ static void print_quoted_string(FILE *out, const char *str)
putc('"', out); putc('"', out);
} }
static void print_symbol(FILE *out, struct menu *menu) static void print_symbol(FILE *out, const struct menu *menu)
{ {
struct symbol *sym = menu->sym; struct symbol *sym = menu->sym;
struct property *prop; struct property *prop;
...@@ -689,9 +695,6 @@ static void print_symbol(FILE *out, struct menu *menu) ...@@ -689,9 +695,6 @@ static void print_symbol(FILE *out, struct menu *menu)
} }
fputc('\n', out); fputc('\n', out);
break; break;
case P_CHOICE:
fputs(" #choice value\n", out);
break;
case P_SELECT: case P_SELECT:
fputs( " select ", out); fputs( " select ", out);
expr_fprint(prop->expr, out); expr_fprint(prop->expr, out);
......
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "array_size.h" #include <array_size.h>
#include <list.h>
#include "internal.h" #include "internal.h"
#include "list.h"
#include "lkc.h" #include "lkc.h"
#include "preprocess.h" #include "preprocess.h"
......
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1 cflags=$1
libs=$2 libs=$2
bin=$3 bin=$3
......
...@@ -147,7 +147,7 @@ void ConfigItem::updateMenu(void) ...@@ -147,7 +147,7 @@ void ConfigItem::updateMenu(void)
expr = sym_get_tristate_value(sym); expr = sym_get_tristate_value(sym);
switch (expr) { switch (expr) {
case yes: case yes:
if (sym_is_choice_value(sym) && type == S_BOOLEAN) if (sym_is_choice_value(sym))
setIcon(promptColIdx, choiceYesIcon); setIcon(promptColIdx, choiceYesIcon);
else else
setIcon(promptColIdx, symbolYesIcon); setIcon(promptColIdx, symbolYesIcon);
...@@ -1101,14 +1101,6 @@ QString ConfigInfoView::debug_info(struct symbol *sym) ...@@ -1101,14 +1101,6 @@ QString ConfigInfoView::debug_info(struct symbol *sym)
&stream, E_NONE); &stream, E_NONE);
stream << "<br>"; stream << "<br>";
break; break;
case P_CHOICE:
if (sym_is_choice(sym)) {
stream << "choice: ";
expr_print(prop->expr, expr_print_help,
&stream, E_NONE);
stream << "<br>";
}
break;
default: default:
stream << "unknown property: "; stream << "unknown property: ";
stream << prop_get_type_name(prop->type); stream << prop_get_type_name(prop->type);
...@@ -1397,8 +1389,6 @@ ConfigMainWindow::ConfigMainWindow(void) ...@@ -1397,8 +1389,6 @@ ConfigMainWindow::ConfigMainWindow(void)
conf_set_changed_callback(conf_changed); conf_set_changed_callback(conf_changed);
// Set saveAction's initial state
conf_changed();
configname = xstrdup(conf_get_configname()); configname = xstrdup(conf_get_configname());
QAction *saveAsAction = new QAction("Save &As...", this); QAction *saveAsAction = new QAction("Save &As...", this);
...@@ -1851,10 +1841,10 @@ void ConfigMainWindow::saveSettings(void) ...@@ -1851,10 +1841,10 @@ void ConfigMainWindow::saveSettings(void)
configSettings->writeSizes("/split2", split2->sizes()); configSettings->writeSizes("/split2", split2->sizes());
} }
void ConfigMainWindow::conf_changed(void) void ConfigMainWindow::conf_changed(bool dirty)
{ {
if (saveAction) if (saveAction)
saveAction->setEnabled(conf_get_changed()); saveAction->setEnabled(dirty);
} }
void fixup_rootmenu(struct menu *menu) void fixup_rootmenu(struct menu *menu)
...@@ -1904,7 +1894,6 @@ int main(int ac, char** av) ...@@ -1904,7 +1894,6 @@ int main(int ac, char** av)
conf_parse(name); conf_parse(name);
fixup_rootmenu(&rootmenu); fixup_rootmenu(&rootmenu);
conf_read(NULL);
//zconfdump(stdout); //zconfdump(stdout);
configApp = new QApplication(ac, av); configApp = new QApplication(ac, av);
...@@ -1916,6 +1905,9 @@ int main(int ac, char** av) ...@@ -1916,6 +1905,9 @@ int main(int ac, char** av)
//zconfdump(stdout); //zconfdump(stdout);
configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
conf_read(NULL);
v->show(); v->show();
configApp->exec(); configApp->exec();
......
...@@ -239,7 +239,7 @@ class ConfigMainWindow : public QMainWindow { ...@@ -239,7 +239,7 @@ class ConfigMainWindow : public QMainWindow {
char *configname; char *configname;
static QAction *saveAction; static QAction *saveAction;
static void conf_changed(void); static void conf_changed(bool);
public: public:
ConfigMainWindow(void); ConfigMainWindow(void);
public slots: public slots:
......
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
config MODULES
bool "Enable loadable module support"
modules
default y
choice choice
prompt "boolean choice" prompt "boolean choice"
default BOOL_CHOICE1 default BOOL_CHOICE1
...@@ -16,15 +11,3 @@ config BOOL_CHOICE1 ...@@ -16,15 +11,3 @@ config BOOL_CHOICE1
bool "choice 1" bool "choice 1"
endchoice endchoice
choice
prompt "tristate choice"
default TRI_CHOICE1
config TRI_CHOICE0
tristate "choice 0"
config TRI_CHOICE1
tristate "choice 1"
endchoice
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
""" """
Basic choice tests. Basic choice tests.
The handling of 'choice' is a bit complicated part in Kconfig.
The behavior of 'y' choice is intuitive. If choice values are tristate,
the choice can be 'm' where each value can be enabled independently.
""" """
...@@ -14,11 +9,6 @@ def test_oldask0(conf): ...@@ -14,11 +9,6 @@ def test_oldask0(conf):
assert conf.stdout_contains('oldask0_expected_stdout') assert conf.stdout_contains('oldask0_expected_stdout')
def test_oldask1(conf):
assert conf.oldaskconfig('oldask1_config') == 0
assert conf.stdout_contains('oldask1_expected_stdout')
def test_allyes(conf): def test_allyes(conf):
assert conf.allyesconfig() == 0 assert conf.allyesconfig() == 0
assert conf.config_contains('allyes_expected_config') assert conf.config_contains('allyes_expected_config')
......
CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set # CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y CONFIG_BOOL_CHOICE1=y
# CONFIG_TRI_CHOICE0 is not set
# CONFIG_TRI_CHOICE1 is not set
CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set # CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y CONFIG_BOOL_CHOICE1=y
CONFIG_TRI_CHOICE0=m
CONFIG_TRI_CHOICE1=m
# CONFIG_MODULES is not set
# CONFIG_BOOL_CHOICE0 is not set # CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y CONFIG_BOOL_CHOICE1=y
# CONFIG_TRI_CHOICE0 is not set
CONFIG_TRI_CHOICE1=y
CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set # CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y CONFIG_BOOL_CHOICE1=y
# CONFIG_TRI_CHOICE0 is not set
CONFIG_TRI_CHOICE1=y
Enable loadable module support (MODULES) [Y/n/?] (NEW)
boolean choice boolean choice
1. choice 0 (BOOL_CHOICE0) (NEW) 1. choice 0 (BOOL_CHOICE0) (NEW)
> 2. choice 1 (BOOL_CHOICE1) (NEW) > 2. choice 1 (BOOL_CHOICE1) (NEW)
choice[1-2?]: choice[1-2?]:
tristate choice [M/y/?] (NEW)
choice 0 (TRI_CHOICE0) [N/m/?] (NEW)
choice 1 (TRI_CHOICE1) [N/m/?] (NEW)
Enable loadable module support (MODULES) [N/y/?]
boolean choice
1. choice 0 (BOOL_CHOICE0) (NEW)
> 2. choice 1 (BOOL_CHOICE1) (NEW)
choice[1-2?]:
tristate choice
1. choice 0 (TRI_CHOICE0) (NEW)
> 2. choice 1 (TRI_CHOICE1) (NEW)
choice[1-2?]:
# SPDX-License-Identifier: GPL-2.0
config MODULES
def_bool y
modules
config DEP
tristate
default m
choice
prompt "Tristate Choice"
config CHOICE0
tristate "Choice 0"
config CHOICE1
tristate "Choice 1"
depends on DEP
endchoice
# SPDX-License-Identifier: GPL-2.0
"""
Hide tristate choice values with mod dependency in y choice.
If tristate choice values depend on symbols set to 'm', they should be
hidden when the choice containing them is changed from 'm' to 'y'
(i.e. exclusive choice).
Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
"""
def test(conf):
assert conf.oldaskconfig('config', 'y') == 0
assert conf.config_contains('expected_config')
assert conf.stdout_contains('expected_stdout')
Tristate Choice [M/y/?] y
Tristate Choice
> 1. Choice 0 (CHOICE0)
choice[1]: 1
Kconfig:5:error: recursive dependency detected! error: recursive dependency detected!
Kconfig:5: symbol A depends on A symbol A depends on A
For a resolution refer to Documentation/kbuild/kconfig-language.rst For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations" subsection "Kconfig recursive dependency limitations"
Kconfig:11:error: recursive dependency detected! error: recursive dependency detected!
Kconfig:11: symbol B is selected by B symbol B is selected by B
For a resolution refer to Documentation/kbuild/kconfig-language.rst For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations" subsection "Kconfig recursive dependency limitations"
Kconfig:17:error: recursive dependency detected! error: recursive dependency detected!
Kconfig:17: symbol C1 depends on C2 symbol C1 depends on C2
Kconfig:21: symbol C2 depends on C1 symbol C2 depends on C1
For a resolution refer to Documentation/kbuild/kconfig-language.rst For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations" subsection "Kconfig recursive dependency limitations"
Kconfig:27:error: recursive dependency detected! error: recursive dependency detected!
Kconfig:27: symbol D1 depends on D2 symbol D1 depends on D2
Kconfig:32: symbol D2 is selected by D1 symbol D2 is selected by D1
For a resolution refer to Documentation/kbuild/kconfig-language.rst For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations" subsection "Kconfig recursive dependency limitations"
Kconfig:37:error: recursive dependency detected! error: recursive dependency detected!
Kconfig:37: symbol E1 depends on E2 symbol E1 depends on E2
Kconfig:42: symbol E2 is implied by E1 symbol E2 is implied by E1
For a resolution refer to Documentation/kbuild/kconfig-language.rst For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations" subsection "Kconfig recursive dependency limitations"
Kconfig:49:error: recursive dependency detected! error: recursive dependency detected!
Kconfig:49: symbol F1 default value contains F2 symbol F1 default value contains F2
Kconfig:51: symbol F2 depends on F1 symbol F2 depends on F1
For a resolution refer to Documentation/kbuild/kconfig-language.rst For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations" subsection "Kconfig recursive dependency limitations"
Kconfig:60:error: recursive dependency detected! error: recursive dependency detected!
Kconfig:60: symbol G depends on G symbol G depends on G
For a resolution refer to Documentation/kbuild/kconfig-language.rst For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations" subsection "Kconfig recursive dependency limitations"
# SPDX-License-Identifier: GPL-2.0
config MODULES
def_bool y
modules
choice
prompt "Choice"
config CHOICE_VAL0
tristate "Choice 0"
config CHOIVE_VAL1
tristate "Choice 1"
endchoice
choice
prompt "Another choice"
depends on CHOICE_VAL0
config DUMMY
bool "dummy"
endchoice
# SPDX-License-Identifier: GPL-2.0
"""
Do not affect user-assigned choice value by another choice.
Handling of state flags for choices is complecated. In old days,
the defconfig result of a choice could be affected by another choice
if those choices interact by 'depends on', 'select', etc.
Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
"""
def test(conf):
assert conf.defconfig('defconfig') == 0
assert conf.config_contains('expected_config')
CONFIG_MODULES=y
CONFIG_CHOICE_VAL0=y
# CONFIG_CHOIVE_VAL1 is not set
CONFIG_DUMMY=y
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "hashtable.h" #include <hashtable.h>
#include "lkc.h" #include "lkc.h"
unsigned int strhash(const char *s) unsigned int strhash(const char *s)
...@@ -98,7 +98,7 @@ void str_printf(struct gstr *gs, const char *fmt, ...) ...@@ -98,7 +98,7 @@ void str_printf(struct gstr *gs, const char *fmt, ...)
} }
/* Retrieve value of growable string */ /* Retrieve value of growable string */
char *str_get(struct gstr *gs) char *str_get(const struct gstr *gs)
{ {
return gs->s; return gs->s;
} }
......
...@@ -45,7 +45,6 @@ info() ...@@ -45,7 +45,6 @@ info()
# Link of vmlinux # Link of vmlinux
# ${1} - output file # ${1} - output file
# ${2}, ${3}, ... - optional extra .o files
vmlinux_link() vmlinux_link()
{ {
local output=${1} local output=${1}
...@@ -90,7 +89,7 @@ vmlinux_link() ...@@ -90,7 +89,7 @@ vmlinux_link()
ldflags="${ldflags} ${wl}--script=${objtree}/${KBUILD_LDS}" ldflags="${ldflags} ${wl}--script=${objtree}/${KBUILD_LDS}"
# The kallsyms linking does not need debug symbols included. # The kallsyms linking does not need debug symbols included.
if [ "$output" != "${output#.tmp_vmlinux.kallsyms}" ] ; then if [ -n "${strip_debug}" ] ; then
ldflags="${ldflags} ${wl}--strip-debug" ldflags="${ldflags} ${wl}--strip-debug"
fi fi
...@@ -101,15 +100,15 @@ vmlinux_link() ...@@ -101,15 +100,15 @@ vmlinux_link()
${ld} ${ldflags} -o ${output} \ ${ld} ${ldflags} -o ${output} \
${wl}--whole-archive ${objs} ${wl}--no-whole-archive \ ${wl}--whole-archive ${objs} ${wl}--no-whole-archive \
${wl}--start-group ${libs} ${wl}--end-group \ ${wl}--start-group ${libs} ${wl}--end-group \
$@ ${ldlibs} ${kallsymso} ${btf_vmlinux_bin_o} ${ldlibs}
} }
# generate .BTF typeinfo from DWARF debuginfo # generate .BTF typeinfo from DWARF debuginfo
# ${1} - vmlinux image # ${1} - vmlinux image
# ${2} - file to dump raw BTF data into
gen_btf() gen_btf()
{ {
local pahole_ver local pahole_ver
local btf_data=${1}.btf.o
if ! [ -x "$(command -v ${PAHOLE})" ]; then if ! [ -x "$(command -v ${PAHOLE})" ]; then
echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available" echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available"
...@@ -122,18 +121,16 @@ gen_btf() ...@@ -122,18 +121,16 @@ gen_btf()
return 1 return 1
fi fi
vmlinux_link ${1} info BTF "${btf_data}"
info "BTF" ${2}
LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1} LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}
# Create ${2} which contains just .BTF section but no symbols. Add # Create ${btf_data} which contains just .BTF section but no symbols. Add
# SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
# deletes all symbols including __start_BTF and __stop_BTF, which will # deletes all symbols including __start_BTF and __stop_BTF, which will
# be redefined in the linker script. Add 2>/dev/null to suppress GNU # be redefined in the linker script. Add 2>/dev/null to suppress GNU
# objcopy warnings: "empty loadable segment detected at ..." # objcopy warnings: "empty loadable segment detected at ..."
${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \ ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \
--strip-all ${1} ${2} 2>/dev/null --strip-all ${1} "${btf_data}" 2>/dev/null
# Change e_type to ET_REL so that it can be used to link final vmlinux. # Change e_type to ET_REL so that it can be used to link final vmlinux.
# GNU ld 2.35+ and lld do not allow an ET_EXEC input. # GNU ld 2.35+ and lld do not allow an ET_EXEC input.
if is_enabled CONFIG_CPU_BIG_ENDIAN; then if is_enabled CONFIG_CPU_BIG_ENDIAN; then
...@@ -141,10 +138,12 @@ gen_btf() ...@@ -141,10 +138,12 @@ gen_btf()
else else
et_rel='\1\0' et_rel='\1\0'
fi fi
printf "${et_rel}" | dd of=${2} conv=notrunc bs=1 seek=16 status=none printf "${et_rel}" | dd of="${btf_data}" conv=notrunc bs=1 seek=16 status=none
btf_vmlinux_bin_o=${btf_data}
} }
# Create ${2} .S file with all symbols from the ${1} object file # Create ${2}.o file with all symbols from the ${1} object file
kallsyms() kallsyms()
{ {
local kallsymopt; local kallsymopt;
...@@ -157,35 +156,27 @@ kallsyms() ...@@ -157,35 +156,27 @@ kallsyms()
kallsymopt="${kallsymopt} --absolute-percpu" kallsymopt="${kallsymopt} --absolute-percpu"
fi fi
if is_enabled CONFIG_KALLSYMS_BASE_RELATIVE; then
kallsymopt="${kallsymopt} --base-relative"
fi
if is_enabled CONFIG_LTO_CLANG; then if is_enabled CONFIG_LTO_CLANG; then
kallsymopt="${kallsymopt} --lto-clang" kallsymopt="${kallsymopt} --lto-clang"
fi fi
info KSYMS ${2} info KSYMS "${2}.S"
scripts/kallsyms ${kallsymopt} ${1} > ${2} scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S"
info AS "${2}.o"
${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} -c -o "${2}.o" "${2}.S"
kallsymso=${2}.o
} }
# Perform one step in kallsyms generation, including temporary linking of # Perform kallsyms for the given temporary vmlinux.
# vmlinux. sysmap_and_kallsyms()
kallsyms_step()
{ {
kallsymso_prev=${kallsymso} mksysmap "${1}" "${1}.syms"
kallsyms_vmlinux=.tmp_vmlinux.kallsyms${1} kallsyms "${1}.syms" "${1}.kallsyms"
kallsymso=${kallsyms_vmlinux}.o
kallsyms_S=${kallsyms_vmlinux}.S
vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o}
mksysmap ${kallsyms_vmlinux} ${kallsyms_vmlinux}.syms
kallsyms ${kallsyms_vmlinux}.syms ${kallsyms_S}
info AS ${kallsymso} kallsyms_sysmap=${1}.syms
${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
-c -o ${kallsymso} ${kallsyms_S}
} }
# Create map file with all symbols from ${1} # Create map file with all symbols from ${1}
...@@ -223,26 +214,40 @@ fi ...@@ -223,26 +214,40 @@ fi
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o
btf_vmlinux_bin_o="" btf_vmlinux_bin_o=
kallsymso=
strip_debug=
if is_enabled CONFIG_KALLSYMS; then
kallsyms /dev/null .tmp_vmlinux0.kallsyms
fi
if is_enabled CONFIG_KALLSYMS || is_enabled CONFIG_DEBUG_INFO_BTF; then
# The kallsyms linking does not need debug symbols, but the BTF does.
if ! is_enabled CONFIG_DEBUG_INFO_BTF; then
strip_debug=1
fi
vmlinux_link .tmp_vmlinux1
fi
if is_enabled CONFIG_DEBUG_INFO_BTF; then if is_enabled CONFIG_DEBUG_INFO_BTF; then
btf_vmlinux_bin_o=.btf.vmlinux.bin.o if ! gen_btf .tmp_vmlinux1; then
if ! gen_btf .tmp_vmlinux.btf $btf_vmlinux_bin_o ; then
echo >&2 "Failed to generate BTF for vmlinux" echo >&2 "Failed to generate BTF for vmlinux"
echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF" echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
exit 1 exit 1
fi fi
fi fi
kallsymso=""
kallsymso_prev=""
kallsyms_vmlinux=""
if is_enabled CONFIG_KALLSYMS; then if is_enabled CONFIG_KALLSYMS; then
# kallsyms support # kallsyms support
# Generate section listing all symbols and add it into vmlinux # Generate section listing all symbols and add it into vmlinux
# It's a three step process: # It's a four step process:
# 0) Generate a dummy __kallsyms with empty symbol list.
# 1) Link .tmp_vmlinux.kallsyms1 so it has all symbols and sections, # 1) Link .tmp_vmlinux.kallsyms1 so it has all symbols and sections,
# but __kallsyms is empty. # with a dummy __kallsyms.
# Running kallsyms on that gives us .tmp_kallsyms1.o with # Running kallsyms on that gives us .tmp_kallsyms1.o with
# the right size # the right size
# 2) Link .tmp_vmlinux.kallsyms2 so it now has a __kallsyms section of # 2) Link .tmp_vmlinux.kallsyms2 so it now has a __kallsyms section of
...@@ -261,19 +266,25 @@ if is_enabled CONFIG_KALLSYMS; then ...@@ -261,19 +266,25 @@ if is_enabled CONFIG_KALLSYMS; then
# a) Verify that the System.map from vmlinux matches the map from # a) Verify that the System.map from vmlinux matches the map from
# ${kallsymso}. # ${kallsymso}.
kallsyms_step 1 # The kallsyms linking does not need debug symbols included.
kallsyms_step 2 strip_debug=1
# step 3 sysmap_and_kallsyms .tmp_vmlinux1
size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso_prev}) size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso})
vmlinux_link .tmp_vmlinux2
sysmap_and_kallsyms .tmp_vmlinux2
size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso}) size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso})
if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
kallsyms_step 3 vmlinux_link .tmp_vmlinux3
sysmap_and_kallsyms .tmp_vmlinux3
fi fi
fi fi
vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} strip_debug=
vmlinux_link vmlinux
# fill in BTF IDs # fill in BTF IDs
if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then
...@@ -293,7 +304,7 @@ fi ...@@ -293,7 +304,7 @@ fi
# step a (see comment above) # step a (see comment above)
if is_enabled CONFIG_KALLSYMS; then if is_enabled CONFIG_KALLSYMS; then
if ! cmp -s System.map ${kallsyms_vmlinux}.syms; then if ! cmp -s System.map "${kallsyms_sysmap}"; then
echo >&2 Inconsistent kallsyms data echo >&2 Inconsistent kallsyms data
echo >&2 'Try "make KALLSYMS_EXTRA_PASS=1" as a workaround' echo >&2 'Try "make KALLSYMS_EXTRA_PASS=1" as a workaround'
exit 1 exit 1
......
...@@ -22,6 +22,11 @@ the entire FIT. ...@@ -22,6 +22,11 @@ the entire FIT.
Use -c to compress the data, using bzip2, gzip, lz4, lzma, lzo and Use -c to compress the data, using bzip2, gzip, lz4, lzma, lzo and
zstd algorithms. zstd algorithms.
Use -D to decompose "composite" DTBs into their base components and
deduplicate the resulting base DTBs and DTB overlays. This requires the
DTBs to be sourced from the kernel build directory, as the implementation
looks at the .cmd files produced by the kernel build.
The resulting FIT can be booted by bootloaders which support FIT, such The resulting FIT can be booted by bootloaders which support FIT, such
as U-Boot, Linuxboot, Tianocore, etc. as U-Boot, Linuxboot, Tianocore, etc.
...@@ -64,6 +69,8 @@ def parse_args(): ...@@ -64,6 +69,8 @@ def parse_args():
help='Specifies the architecture') help='Specifies the architecture')
parser.add_argument('-c', '--compress', type=str, default='none', parser.add_argument('-c', '--compress', type=str, default='none',
help='Specifies the compression') help='Specifies the compression')
parser.add_argument('-D', '--decompose-dtbs', action='store_true',
help='Decompose composite DTBs into base DTB and overlays')
parser.add_argument('-E', '--external', action='store_true', parser.add_argument('-E', '--external', action='store_true',
help='Convert the FIT to use external data') help='Convert the FIT to use external data')
parser.add_argument('-n', '--name', type=str, required=True, parser.add_argument('-n', '--name', type=str, required=True,
...@@ -140,12 +147,12 @@ def finish_fit(fsw, entries): ...@@ -140,12 +147,12 @@ def finish_fit(fsw, entries):
fsw.end_node() fsw.end_node()
seq = 0 seq = 0
with fsw.add_node('configurations'): with fsw.add_node('configurations'):
for model, compat in entries: for model, compat, files in entries:
seq += 1 seq += 1
with fsw.add_node(f'conf-{seq}'): with fsw.add_node(f'conf-{seq}'):
fsw.property('compatible', bytes(compat)) fsw.property('compatible', bytes(compat))
fsw.property_string('description', model) fsw.property_string('description', model)
fsw.property_string('fdt', f'fdt-{seq}') fsw.property('fdt', bytes(''.join(f'fdt-{x}\x00' for x in files), "ascii"))
fsw.property_string('kernel', 'kernel') fsw.property_string('kernel', 'kernel')
fsw.end_node() fsw.end_node()
...@@ -193,21 +200,9 @@ def output_dtb(fsw, seq, fname, arch, compress): ...@@ -193,21 +200,9 @@ def output_dtb(fsw, seq, fname, arch, compress):
fname (str): Filename containing the DTB fname (str): Filename containing the DTB
arch: FIT architecture, e.g. 'arm64' arch: FIT architecture, e.g. 'arm64'
compress (str): Compressed algorithm, e.g. 'gzip' compress (str): Compressed algorithm, e.g. 'gzip'
Returns:
tuple:
str: Model name
bytes: Compatible stringlist
""" """
with fsw.add_node(f'fdt-{seq}'): with fsw.add_node(f'fdt-{seq}'):
# Get the compatible / model information fsw.property_string('description', os.path.basename(fname))
with open(fname, 'rb') as inf:
data = inf.read()
fdt = libfdt.FdtRo(data)
model = fdt.getprop(0, 'model').as_str()
compat = fdt.getprop(0, 'compatible')
fsw.property_string('description', model)
fsw.property_string('type', 'flat_dt') fsw.property_string('type', 'flat_dt')
fsw.property_string('arch', arch) fsw.property_string('arch', arch)
fsw.property_string('compression', compress) fsw.property_string('compression', compress)
...@@ -215,9 +210,45 @@ def output_dtb(fsw, seq, fname, arch, compress): ...@@ -215,9 +210,45 @@ def output_dtb(fsw, seq, fname, arch, compress):
with open(fname, 'rb') as inf: with open(fname, 'rb') as inf:
compressed = compress_data(inf, compress) compressed = compress_data(inf, compress)
fsw.property('data', compressed) fsw.property('data', compressed)
return model, compat
def process_dtb(fname, args):
"""Process an input DTB, decomposing it if requested and is possible
Args:
fname (str): Filename containing the DTB
args (Namespace): Program arguments
Returns:
tuple:
str: Model name string
str: Root compatible string
files: list of filenames corresponding to the DTB
"""
# Get the compatible / model information
with open(fname, 'rb') as inf:
data = inf.read()
fdt = libfdt.FdtRo(data)
model = fdt.getprop(0, 'model').as_str()
compat = fdt.getprop(0, 'compatible')
if args.decompose_dtbs:
# Check if the DTB needs to be decomposed
path, basename = os.path.split(fname)
cmd_fname = os.path.join(path, f'.{basename}.cmd')
with open(cmd_fname, 'r', encoding='ascii') as inf:
cmd = inf.read()
if 'scripts/dtc/fdtoverlay' in cmd:
# This depends on the structure of the composite DTB command
files = cmd.split()
files = files[files.index('-i') + 1:]
else:
files = [fname]
else:
files = [fname]
return (model, compat, files)
def build_fit(args): def build_fit(args):
"""Build the FIT from the provided files and arguments """Build the FIT from the provided files and arguments
...@@ -235,6 +266,7 @@ def build_fit(args): ...@@ -235,6 +266,7 @@ def build_fit(args):
fsw = libfdt.FdtSw() fsw = libfdt.FdtSw()
setup_fit(fsw, args.name) setup_fit(fsw, args.name)
entries = [] entries = []
fdts = {}
# Handle the kernel # Handle the kernel
with open(args.kernel, 'rb') as inf: with open(args.kernel, 'rb') as inf:
...@@ -243,12 +275,22 @@ def build_fit(args): ...@@ -243,12 +275,22 @@ def build_fit(args):
write_kernel(fsw, comp_data, args) write_kernel(fsw, comp_data, args)
for fname in args.dtbs: for fname in args.dtbs:
# Ignore overlay (.dtbo) files # Ignore non-DTB (*.dtb) files
if os.path.splitext(fname)[1] == '.dtb': if os.path.splitext(fname)[1] != '.dtb':
seq += 1 continue
size += os.path.getsize(fname)
model, compat = output_dtb(fsw, seq, fname, args.arch, args.compress) (model, compat, files) = process_dtb(fname, args)
entries.append([model, compat])
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)
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef LIST_H
#define LIST_H
#include <stdbool.h>
#include <stddef.h>
/* Are two types/vars the same type (ignoring qualifiers)? */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
_Static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
#define LIST_POISON1 ((void *) 0x100)
#define LIST_POISON2 ((void *) 0x122)
/*
* Circular doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
/**
* INIT_LIST_HEAD - Initialize a list_head structure
* @list: list_head structure to be initialized.
*
* Initializes the list_head to point to itself. If it is a list header,
* the result is an empty list.
*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del_entry(entry);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
/**
* list_is_head - tests whether @list is the list @head
* @list: the entry to test
* @head: the head of the list
*/
static inline int list_is_head(const struct list_head *list, const struct list_head *head)
{
return list == head;
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
/**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_head within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)
/**
* list_entry_is_head - test if the entry points to the head of the list
* @pos: the type * to cursor
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_entry_is_head(pos, head, member) \
(&pos->member == (head))
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
!list_entry_is_head(pos, head, member); \
pos = list_next_entry(pos, member))
/**
* list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member), \
n = list_next_entry(pos, member); \
!list_entry_is_head(pos, head, member); \
pos = n, n = list_next_entry(n, member))
#endif /* LIST_H */
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <errno.h> #include <errno.h>
#include <hashtable.h>
#include <list.h>
#include "modpost.h" #include "modpost.h"
#include "../../include/linux/license.h" #include "../../include/linux/license.h"
...@@ -199,13 +202,8 @@ static struct module *new_module(const char *name, size_t namelen) ...@@ -199,13 +202,8 @@ static struct module *new_module(const char *name, size_t namelen)
return mod; return mod;
} }
/* A hash of all exported symbols,
* struct symbol is also used for lists of unresolved symbols */
#define SYMBOL_HASH_SIZE 1024
struct symbol { struct symbol {
struct symbol *next; struct hlist_node hnode;/* link to hash table */
struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */ struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */
struct module *module; struct module *module;
char *namespace; char *namespace;
...@@ -218,7 +216,7 @@ struct symbol { ...@@ -218,7 +216,7 @@ struct symbol {
char name[]; char name[];
}; };
static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; static HASHTABLE_DEFINE(symbol_hashtable, 1U << 10);
/* This is based on the hash algorithm from gdbm, via tdb */ /* This is based on the hash algorithm from gdbm, via tdb */
static inline unsigned int tdb_hash(const char *name) static inline unsigned int tdb_hash(const char *name)
...@@ -250,11 +248,7 @@ static struct symbol *alloc_symbol(const char *name) ...@@ -250,11 +248,7 @@ static struct symbol *alloc_symbol(const char *name)
/* For the hash of exported symbols */ /* For the hash of exported symbols */
static void hash_add_symbol(struct symbol *sym) static void hash_add_symbol(struct symbol *sym)
{ {
unsigned int hash; hash_add(symbol_hashtable, &sym->hnode, tdb_hash(sym->name));
hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE;
sym->next = symbolhash[hash];
symbolhash[hash] = sym;
} }
static void sym_add_unresolved(const char *name, struct module *mod, bool weak) static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
...@@ -275,7 +269,7 @@ static struct symbol *sym_find_with_module(const char *name, struct module *mod) ...@@ -275,7 +269,7 @@ static struct symbol *sym_find_with_module(const char *name, struct module *mod)
if (name[0] == '.') if (name[0] == '.')
name++; name++;
for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) { hash_for_each_possible(symbol_hashtable, s, hnode, tdb_hash(name)) {
if (strcmp(s->name, name) == 0 && (!mod || s->module == mod)) if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
return s; return s;
} }
...@@ -954,17 +948,6 @@ static int secref_whitelist(const char *fromsec, const char *fromsym, ...@@ -954,17 +948,6 @@ static int secref_whitelist(const char *fromsec, const char *fromsym,
match(fromsym, PATTERNS("*_ops", "*_probe", "*_console"))) match(fromsym, PATTERNS("*_ops", "*_probe", "*_console")))
return 0; return 0;
/*
* symbols in data sections must not refer to .exit.*, but there are
* quite a few offenders, so hide these unless for W=1 builds until
* these are fixed.
*/
if (!extra_warn &&
match(fromsec, PATTERNS(DATA_SECTIONS)) &&
match(tosec, PATTERNS(ALL_EXIT_SECTIONS)) &&
match(fromsym, PATTERNS("*driver")))
return 0;
/* Check for pattern 3 */ /* Check for pattern 3 */
if (strstarts(fromsec, ".head.text") && if (strstarts(fromsec, ".head.text") &&
match(tosec, PATTERNS(ALL_INIT_SECTIONS))) match(tosec, PATTERNS(ALL_INIT_SECTIONS)))
...@@ -1168,40 +1151,6 @@ static Elf_Addr addend_386_rel(uint32_t *location, unsigned int r_type) ...@@ -1168,40 +1151,6 @@ static Elf_Addr addend_386_rel(uint32_t *location, unsigned int r_type)
return (Elf_Addr)(-1); return (Elf_Addr)(-1);
} }
#ifndef R_ARM_CALL
#define R_ARM_CALL 28
#endif
#ifndef R_ARM_JUMP24
#define R_ARM_JUMP24 29
#endif
#ifndef R_ARM_THM_CALL
#define R_ARM_THM_CALL 10
#endif
#ifndef R_ARM_THM_JUMP24
#define R_ARM_THM_JUMP24 30
#endif
#ifndef R_ARM_MOVW_ABS_NC
#define R_ARM_MOVW_ABS_NC 43
#endif
#ifndef R_ARM_MOVT_ABS
#define R_ARM_MOVT_ABS 44
#endif
#ifndef R_ARM_THM_MOVW_ABS_NC
#define R_ARM_THM_MOVW_ABS_NC 47
#endif
#ifndef R_ARM_THM_MOVT_ABS
#define R_ARM_THM_MOVT_ABS 48
#endif
#ifndef R_ARM_THM_JUMP19
#define R_ARM_THM_JUMP19 51
#endif
static int32_t sign_extend32(int32_t value, int index) static int32_t sign_extend32(int32_t value, int index)
{ {
uint8_t shift = 31 - index; uint8_t shift = 31 - index;
...@@ -1262,7 +1211,7 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type) ...@@ -1262,7 +1211,7 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
((lower & 0x07ff) << 1), ((lower & 0x07ff) << 1),
20); 20);
return offset + sym->st_value + 4; return offset + sym->st_value + 4;
case R_ARM_THM_CALL: case R_ARM_THM_PC22:
case R_ARM_THM_JUMP24: case R_ARM_THM_JUMP24:
/* /*
* Encoding T4: * Encoding T4:
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <elf.h> #include <elf.h>
#include "../../include/linux/module_symbol.h" #include "../../include/linux/module_symbol.h"
#include "list.h" #include <list_types.h>
#include "elfconfig.h" #include "elfconfig.h"
/* On BSD-alike OSes elf.h defines these according to host's word size */ /* On BSD-alike OSes elf.h defines these according to host's word size */
......
# SPDX-License-Identifier: GPL-2.0-only
# Maintainer: Thomas Weißschuh <linux@weissschuh.net>
# Contributor: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
pkgbase=${PACMAN_PKGBASE:-linux-upstream}
pkgname=("${pkgbase}" "${pkgbase}-api-headers")
if grep -q CONFIG_MODULES=y include/config/auto.conf; then
pkgname+=("${pkgbase}-headers")
fi
pkgver="${KERNELRELEASE//-/_}"
# The PKGBUILD is evaluated multiple times.
# Running scripts/build-version from here would introduce inconsistencies.
pkgrel="${KBUILD_REVISION}"
pkgdesc='Upstream Linux'
url='https://www.kernel.org/'
# Enable flexible cross-compilation
arch=(${CARCH})
license=(GPL-2.0-only)
makedepends=(
bc
bison
cpio
flex
gettext
kmod
libelf
openssl
pahole
perl
python
rsync
tar
)
options=(!debug !strip !buildflags !makeflags)
build() {
# MAKEFLAGS from makepkg.conf override the ones inherited from kbuild.
# Bypass this override with a custom variable.
export MAKEFLAGS="${KBUILD_MAKEFLAGS}"
cd "${objtree}"
${MAKE} KERNELRELEASE="${KERNELRELEASE}" KBUILD_BUILD_VERSION="${pkgrel}"
}
_package() {
pkgdesc="The ${pkgdesc} kernel and modules"
export MAKEFLAGS="${KBUILD_MAKEFLAGS}"
cd "${objtree}"
local modulesdir="${pkgdir}/usr/${MODLIB}"
echo "Installing boot image..."
# systemd expects to find the kernel here to allow hibernation
# https://github.com/systemd/systemd/commit/edda44605f06a41fb86b7ab8128dcf99161d2344
install -Dm644 "$(${MAKE} -s image_name)" "${modulesdir}/vmlinuz"
# Used by mkinitcpio to name the kernel
echo "${pkgbase}" > "${modulesdir}/pkgbase"
echo "Installing modules..."
${MAKE} INSTALL_MOD_PATH="${pkgdir}/usr" INSTALL_MOD_STRIP=1 \
DEPMOD=true modules_install
if [ -d "${srctree}/arch/${SRCARCH}/boot/dts" ]; then
echo "Installing dtbs..."
${MAKE} INSTALL_DTBS_PATH="${modulesdir}/dtb" dtbs_install
fi
# remove build link, will be part of -headers package
rm -f "${modulesdir}/build"
}
_package-headers() {
pkgdesc="Headers and scripts for building modules for the ${pkgdesc} kernel"
export MAKEFLAGS="${KBUILD_MAKEFLAGS}"
cd "${objtree}"
local builddir="${pkgdir}/usr/${MODLIB}/build"
echo "Installing build files..."
"${srctree}/scripts/package/install-extmod-build" "${builddir}"
echo "Installing System.map and config..."
cp System.map "${builddir}/System.map"
cp .config "${builddir}/.config"
echo "Adding symlink..."
mkdir -p "${pkgdir}/usr/src"
ln -sr "${builddir}" "${pkgdir}/usr/src/${pkgbase}"
}
_package-api-headers() {
pkgdesc="Kernel headers sanitized for use in userspace"
provides=(linux-api-headers)
conflicts=(linux-api-headers)
export MAKEFLAGS="${KBUILD_MAKEFLAGS}"
cd "${objtree}"
${MAKE} headers_install INSTALL_HDR_PATH="${pkgdir}/usr"
}
for _p in "${pkgname[@]}"; do
eval "package_$_p() {
$(declare -f "_package${_p#$pkgbase}")
_package${_p#$pkgbase}
}"
done
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# specified in KDEB_HOOKDIR) that will be called on package install and # specified in KDEB_HOOKDIR) that will be called on package install and
# removal. # removal.
set -e set -eu
is_enabled() { is_enabled() {
grep -q "^$1=y" include/config/auto.conf grep -q "^$1=y" include/config/auto.conf
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# Wichert Akkerman <wichert@wiggy.net>. # Wichert Akkerman <wichert@wiggy.net>.
# #
set -e set -eu
# #
# Some variables and settings used throughout the script # Some variables and settings used throughout the script
......
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
set -eu
diff_patch=$1 diff_patch=$1
mkdir -p "$(dirname "${diff_patch}")" mkdir -p "$(dirname "${diff_patch}")"
......
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
set -e set -eu
destdir=${1} destdir=${1}
test -n "${srctree}"
test -n "${SRCARCH}"
is_enabled() { is_enabled() {
grep -q "^$1=y" include/config/auto.conf grep -q "^$1=y" include/config/auto.conf
} }
......
...@@ -27,7 +27,7 @@ The Linux Kernel, the operating system core itself ...@@ -27,7 +27,7 @@ The Linux Kernel, the operating system core itself
%package headers %package headers
Summary: Header files for the Linux kernel for use by glibc Summary: Header files for the Linux kernel for use by glibc
Group: Development/System Group: Development/System
Obsoletes: kernel-headers Obsoletes: kernel-headers < %{version}
Provides: kernel-headers = %{version} Provides: kernel-headers = %{version}
%description headers %description headers
Kernel-headers includes the C header files that specify the interface Kernel-headers includes the C header files that specify the interface
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# #
# Simple script to generate a debian/ directory for a Linux kernel. # Simple script to generate a debian/ directory for a Linux kernel.
set -e set -eu
is_enabled() { is_enabled() {
grep -q "^$1=y" include/config/auto.conf grep -q "^$1=y" include/config/auto.conf
...@@ -19,7 +19,7 @@ if_enabled_echo() { ...@@ -19,7 +19,7 @@ if_enabled_echo() {
} }
set_debarch() { set_debarch() {
if [ -n "$KBUILD_DEBARCH" ] ; then if [ "${KBUILD_DEBARCH:+set}" ]; then
debarch="$KBUILD_DEBARCH" debarch="$KBUILD_DEBARCH"
return return
fi fi
...@@ -125,32 +125,34 @@ gen_source () ...@@ -125,32 +125,34 @@ gen_source ()
rm -rf debian rm -rf debian
mkdir debian mkdir debian
email=${DEBEMAIL-$EMAIL} user=${KBUILD_BUILD_USER:-$(id -nu)}
name=${DEBFULLNAME:-${user}}
# use email string directly if it contains <email> if [ "${DEBEMAIL:+set}" ]; then
if echo "${email}" | grep -q '<.*>'; then email=${DEBEMAIL}
maintainer=${email}
else else
# or construct the maintainer string buildhost=${KBUILD_BUILD_HOST:-$(hostname -f 2>/dev/null || hostname)}
user=${KBUILD_BUILD_USER-$(id -nu)} email="${user}@${buildhost}"
name=${DEBFULLNAME-${user}}
if [ -z "${email}" ]; then
buildhost=${KBUILD_BUILD_HOST-$(hostname -f 2>/dev/null || hostname)}
email="${user}@${buildhost}"
fi
maintainer="${name} <${email}>"
fi fi
maintainer="${name} <${email}>"
if [ "$1" = --need-source ]; then while [ $# -gt 0 ]; do
gen_source case "$1" in
fi --need-source)
gen_source
shift
;;
*)
break
;;
esac
done
# Some variables and settings used throughout the script # Some variables and settings used throughout the script
version=$KERNELRELEASE version=$KERNELRELEASE
if [ -n "$KDEB_PKGVERSION" ]; then if [ "${KDEB_PKGVERSION:+set}" ]; then
packageversion=$KDEB_PKGVERSION packageversion=$KDEB_PKGVERSION
else else
packageversion=$(${srctree}/scripts/setlocalversion --no-local ${srctree})-$($srctree/init/build-version) packageversion=$(${srctree}/scripts/setlocalversion --no-local ${srctree})-$($srctree/scripts/build-version)
fi fi
sourcename=${KDEB_SOURCENAME:-linux-upstream} sourcename=${KDEB_SOURCENAME:-linux-upstream}
...@@ -164,7 +166,7 @@ debarch= ...@@ -164,7 +166,7 @@ debarch=
set_debarch set_debarch
# Try to determine distribution # Try to determine distribution
if [ -n "$KDEB_CHANGELOG_DIST" ]; then if [ "${KDEB_CHANGELOG_DIST:+set}" ]; then
distribution=$KDEB_CHANGELOG_DIST distribution=$KDEB_CHANGELOG_DIST
# In some cases lsb_release returns the codename as n/a, which breaks dpkg-parsechangelog # In some cases lsb_release returns the codename as n/a, which breaks dpkg-parsechangelog
elif distribution=$(lsb_release -cs 2>/dev/null) && [ -n "$distribution" ] && [ "$distribution" != "n/a" ]; then elif distribution=$(lsb_release -cs 2>/dev/null) && [ -n "$distribution" ] && [ "$distribution" != "n/a" ]; then
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
# Patched for non-x86 by Opencon (L) 2002 <opencon@rio.skydome.net> # Patched for non-x86 by Opencon (L) 2002 <opencon@rio.skydome.net>
# #
set -eu
output=$1 output=$1
mkdir -p "$(dirname "${output}")" mkdir -p "$(dirname "${output}")"
...@@ -24,7 +26,30 @@ fi ...@@ -24,7 +26,30 @@ fi
cat<<EOF cat<<EOF
%define ARCH ${ARCH} %define ARCH ${ARCH}
%define KERNELRELEASE ${KERNELRELEASE} %define KERNELRELEASE ${KERNELRELEASE}
%define pkg_release $("${srctree}/init/build-version") %define pkg_release $("${srctree}/scripts/build-version")
EOF EOF
cat "${srctree}/scripts/package/kernel.spec" cat "${srctree}/scripts/package/kernel.spec"
# collect the user's name and email address for the changelog entry
if [ "$(command -v git)" ]; then
name=$(git config user.name) || true
email=$(git config user.email) || true
fi
if [ ! "${name:+set}" ]; then
name=${KBUILD_BUILD_USER:-$(id -nu)}
fi
if [ ! "${email:+set}" ]; then
buildhost=${KBUILD_BUILD_HOST:-$(hostname -f 2>/dev/null || hostname)}
builduser=${KBUILD_BUILD_USER:-$(id -nu)}
email="${builduser}@${buildhost}"
fi
cat << EOF
%changelog
* $(LC_ALL=C; date +'%a %b %d %Y') ${name} <${email}>
- Custom built Linux kernel.
EOF
...@@ -20,22 +20,4 @@ set -e ...@@ -20,22 +20,4 @@ set -e
# yard. Stale files stay in this file for a while (for some release cycles?), # yard. Stale files stay in this file for a while (for some release cycles?),
# then will be really dead and removed from the code base entirely. # then will be really dead and removed from the code base entirely.
rm -f arch/powerpc/purgatory/kexec-purgatory.c
rm -f arch/riscv/purgatory/kexec-purgatory.c
rm -f arch/x86/purgatory/kexec-purgatory.c
rm -f scripts/extract-cert
rm -f scripts/kconfig/[gmnq]conf-cfg
rm -f rust/target.json
rm -f scripts/bin2c
rm -f .scmversion
rm -rf include/ksym
find . -name '*.usyms' | xargs rm -f
rm -f *.spec rm -f *.spec
...@@ -26,7 +26,6 @@ static bool is_ignored_symbol(const char *name, char type) ...@@ -26,7 +26,6 @@ static bool is_ignored_symbol(const char *name, char type)
* when --all-symbols is specified so exclude them to get a * when --all-symbols is specified so exclude them to get a
* stable symbol list. * stable symbol list.
*/ */
"kallsyms_addresses",
"kallsyms_offsets", "kallsyms_offsets",
"kallsyms_relative_base", "kallsyms_relative_base",
"kallsyms_num_syms", "kallsyms_num_syms",
......
...@@ -62,8 +62,8 @@ $(deps_initramfs): ; ...@@ -62,8 +62,8 @@ $(deps_initramfs): ;
quiet_cmd_initfs = GEN $@ quiet_cmd_initfs = GEN $@
cmd_initfs = \ cmd_initfs = \
$(CONFIG_SHELL) $< -o $@ -l $(obj)/.initramfs_data.cpio.d \ $(CONFIG_SHELL) $< -o $@ -l $(obj)/.initramfs_data.cpio.d \
$(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \ $(addprefix -u , $(CONFIG_INITRAMFS_ROOT_UID)) \
$(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) \ $(addprefix -g , $(CONFIG_INITRAMFS_ROOT_GID)) \
$(if $(KBUILD_BUILD_TIMESTAMP), -d "$(KBUILD_BUILD_TIMESTAMP)") \ $(if $(KBUILD_BUILD_TIMESTAMP), -d "$(KBUILD_BUILD_TIMESTAMP)") \
$(ramfs-input) $(ramfs-input)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment