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
#
/tar-install/
#
# pacman files (make pacman-pkg)
#
/PKGBUILD
/pacman/
#
# We don't want to ignore the following even if they are dot-files
#
......
......@@ -409,16 +409,9 @@ choices::
"endchoice"
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
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
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.
options.
A choice only allows a single config entry to be selected.
comment::
......
......@@ -578,7 +578,7 @@ cc-option
Note: cc-option uses KBUILD_CFLAGS for $(CC) options
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".
Example::
......@@ -596,7 +596,7 @@ cc-option-yn
Note: cc-option-yn uses KBUILD_CFLAGS for $(CC) options
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,
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.
......@@ -606,7 +606,7 @@ cc-disable-warning
KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
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 tests if the value of $(CONFIG_GCC_VERSION) is greater than
......
......@@ -33,7 +33,7 @@ GNU C 5.1 gcc --version
Clang/LLVM (optional) 13.0.1 clang --version
Rust (optional) 1.78.0 rustc --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
binutils 2.25 ld -v
flex 2.5.35 flex --version
......@@ -112,7 +112,7 @@ It depends on ``libclang``.
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
----
......
......@@ -12117,6 +12117,7 @@ F: scripts/Makefile*
F: scripts/basic/
F: scripts/clang-tools/
F: scripts/dummy-tools/
F: scripts/include/
F: scripts/mk*
F: scripts/mod/
F: scripts/package/
......@@ -12172,6 +12173,13 @@ F: include/uapi/linux/nfsd/
F: include/uapi/linux/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
M: Thorsten Leemhuis <linux@leemhuis.info>
L: regressions@lists.linux.dev
......
......@@ -11,8 +11,8 @@ NAME = Baby Opossum Posse
# Comments in this file are targeted only to the developer, do not
# expect to learn how to build the kernel reading this file.
ifeq ($(filter undefine,$(.FEATURES)),)
$(error GNU Make >= 3.82 is required. Your Make version is $(MAKE_VERSION))
ifeq ($(filter output-sync,$(.FEATURES)),)
$(error GNU Make >= 4.0 is required. Your Make version is $(MAKE_VERSION))
endif
$(if $(filter __%, $(MAKECMDGOALS)), \
......@@ -93,15 +93,7 @@ endif
# If the user is running make -s (silent mode), suppress echoing of
# commands
# make-4.0 (and later) keep single letter options in the 1st word of MAKEFLAGS.
ifeq ($(filter 3.%,$(MAKE_VERSION)),)
short-opts := $(firstword -$(MAKEFLAGS))
else
short-opts := $(filter-out --%,$(MAKEFLAGS))
endif
ifneq ($(findstring s,$(short-opts)),)
ifneq ($(findstring s,$(firstword -$(MAKEFLAGS))),)
quiet=silent_
override KBUILD_VERBOSE :=
endif
......@@ -201,14 +193,6 @@ ifneq ($(words $(subst :, ,$(abs_srctree))), 1)
$(error source directory cannot contain spaces or colons)
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
endif # sub_make_done
......@@ -474,8 +458,10 @@ export rust_common_flags := --edition=2021 \
-Dclippy::no_mangle_with_rust_abi \
-Wclippy::dbg_macro
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS)
KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS)
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \
$(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 \
-Zallow-features= $(HOSTRUSTFLAGS)
KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
......@@ -1344,6 +1330,12 @@ prepare: tools/bpf/resolve_btfids
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
resolve_btfids_O = $(abspath $(objtree))/tools/bpf/resolve_btfids
......@@ -1497,7 +1489,7 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \
# Directories & files removed with 'make mrproper'
MRPROPER_FILES += include/config include/generated \
arch/$(SRCARCH)/include/generated .objdiff \
debian snap tar-install \
debian snap tar-install PKGBUILD pacman \
.config .config.old .version \
Module.symvers \
certs/signing_key.pem \
......
......@@ -1483,7 +1483,8 @@ config ARM_ATAG_DTB_COMPAT
from the ATAG list and store it at run time into the appended DTB.
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
config ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER
......@@ -1512,7 +1513,8 @@ config CMDLINE
memory size and the root device (e.g., mem=64M root=/dev/nfs).
choice
prompt "Kernel command line type" if CMDLINE != ""
prompt "Kernel command line type"
depends on CMDLINE != ""
default CMDLINE_FROM_BOOTLOADER
config CMDLINE_FROM_BOOTLOADER
......
......@@ -17,6 +17,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
if [ "$(basename $2)" = "zImage" ]; then
# Compressed install
echo "Installing compressed kernel"
......
......@@ -2290,7 +2290,8 @@ config CMDLINE
root device (e.g. root=/dev/nfs).
choice
prompt "Kernel command line type" if CMDLINE != ""
prompt "Kernel command line type"
depends on CMDLINE != ""
default CMDLINE_FROM_BOOTLOADER
help
Choose how the kernel will handle the provided default kernel
......
......@@ -17,6 +17,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
if [ "$(basename $2)" = "Image.gz" ] || [ "$(basename $2)" = "vmlinuz.efi" ]
then
# Compressed install
......
......@@ -16,6 +16,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old
fi
......
......@@ -2927,7 +2927,8 @@ config BUILTIN_DTB
bool
choice
prompt "Kernel appended dtb support" if USE_OF
prompt "Kernel appended dtb support"
depends on USE_OF
default MIPS_NO_APPENDED_DTB
config MIPS_NO_APPENDED_DTB
......@@ -2968,7 +2969,8 @@ choice
endchoice
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 && \
!MACH_LOONGSON64 && !MIPS_MALTA && \
!CAVIUM_OCTEON_SOC
......
......@@ -16,6 +16,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old
fi
......
......@@ -16,6 +16,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
if [ "$(basename $2)" = "vmlinuz" ]; then
# Compressed install
echo "Installing compressed kernel"
......
......@@ -964,7 +964,8 @@ config CMDLINE
most cases you will need to specify the root device here.
choice
prompt "Kernel command line type" if CMDLINE != ""
prompt "Kernel command line type"
depends on CMDLINE != ""
default CMDLINE_FROM_BOOTLOADER
config CMDLINE_FROM_BOOTLOADER
......
......@@ -960,7 +960,8 @@ config CMDLINE
line here and choose how the kernel should use it later on.
choice
prompt "Built-in command line usage" if CMDLINE != ""
prompt "Built-in command line usage"
depends on CMDLINE != ""
default CMDLINE_FALLBACK
help
Choose how the kernel will handle the provided built-in command
......
......@@ -17,6 +17,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
case "${2##*/}" in
# Compressed install
Image.*|vmlinuz.efi)
......
......@@ -15,6 +15,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
echo "Warning: '${INSTALLKERNEL}' command not available - additional " \
"bootloader config required" >&2
if [ -f "$4/vmlinuz-$1" ]; then mv -- "$4/vmlinuz-$1" "$4/vmlinuz-$1.old"; fi
......
......@@ -16,6 +16,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old
fi
......
......@@ -16,6 +16,8 @@
# $3 - kernel map file
# $4 - default install path (blank if root directory)
set -e
if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old
fi
......
......@@ -151,8 +151,9 @@ config JFFS2_RUBIN
RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
choice
prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
prompt "JFFS2 default compression mode"
default JFFS2_CMODE_PRIORITY
depends on JFFS2_COMPRESSION_OPTIONS
depends on JFFS2_FS
help
You can set here the default compression mode of JFFS2 from
......
......@@ -442,30 +442,11 @@
#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
*/
#define RO_DATA(align) \
. = ALIGN((align)); \
PRELIMINARY_SYMBOL_DEFINITIONS \
.rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \
__start_rodata = .; \
*(.rodata) *(.rodata.*) \
......
......@@ -1803,24 +1803,6 @@ config KALLSYMS_ABSOLUTE_PERCPU
depends on KALLSYMS
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
config ARCH_HAS_MEMBARRIER_CALLBACKS
......
......@@ -52,7 +52,7 @@ CFLAGS_version.o := -include $(obj)/utsversion-tmp.h
# 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: FORCE
$(call filechk,uts_version)
......
......@@ -148,9 +148,6 @@ static unsigned int get_symbol_offset(unsigned long pos)
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 */
if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
......@@ -325,7 +322,7 @@ static unsigned long get_symbol_pos(unsigned long addr,
unsigned long symbol_start = 0, symbol_end = 0;
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;
high = kallsyms_num_syms;
......
......@@ -4,12 +4,6 @@
#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 u8 kallsyms_names[];
......
......@@ -216,12 +216,8 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_SYMBOL(kallsyms_num_syms);
VMCOREINFO_SYMBOL(kallsyms_token_table);
VMCOREINFO_SYMBOL(kallsyms_token_index);
#ifdef CONFIG_KALLSYMS_BASE_RELATIVE
VMCOREINFO_SYMBOL(kallsyms_offsets);
VMCOREINFO_SYMBOL(kallsyms_relative_base);
#else
VMCOREINFO_SYMBOL(kallsyms_addresses);
#endif /* CONFIG_KALLSYMS_BASE_RELATIVE */
#endif /* CONFIG_KALLSYMS */
arch_crash_save_vmcoreinfo();
......
......@@ -68,7 +68,7 @@ kbuild-file = $(or $(wildcard $(src)/Kbuild),$(src)/Makefile)
# Read a file, replacing newlines with spaces
#
# 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))
else
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) $< ;
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),)
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
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
$(multi-dtb-y): FORCE
......@@ -529,6 +533,7 @@ quiet_cmd_fit = FIT $@
cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
--name '$(UIMAGE_NAME)' \
$(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
$(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
--compress $(FIT_COMPRESSION) -k $< @$(word 2,$^)
# XZ
......
......@@ -141,6 +141,19 @@ snap-pkg:
cd $(objtree)/snap && \
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
# ---------------------------------------------------------------------------
......@@ -221,6 +234,7 @@ help:
@echo ' bindeb-pkg - Build only the binary kernel deb package'
@echo ' snap-pkg - Build only the binary kernel snap package'
@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 ' tar-pkg - Build the kernel as an uncompressed 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)
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: the entry to test
......@@ -166,6 +189,17 @@ static inline int list_empty(const struct list_head *head)
#define list_first_entry(ptr, 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
* @pos: the type * to cursor
......@@ -174,6 +208,14 @@ static inline int list_empty(const struct list_head *head)
#define list_next_entry(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
* @pos: the type * to cursor
......@@ -194,6 +236,17 @@ static inline int list_empty(const struct list_head *head)
!list_entry_is_head(pos, head, 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
* @pos: the type * to use as a loop cursor.
......
......@@ -20,6 +20,10 @@ do
fi
done
if [ -n "${INSTALL_PATH}" ] && ! [ -e "${INSTALL_PATH}" ]; then
mkdir -p "${INSTALL_PATH}"
fi
# User/arch may have a custom install script
for file in "${HOME}/bin/${INSTALLKERNEL}" \
"/sbin/${INSTALLKERNEL}" \
......
......@@ -6,7 +6,7 @@
* of the GNU General Public License, incorporated herein by reference.
*
* 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
* maps these to the most used substrings (tokens). For instance, it might
......@@ -36,8 +36,7 @@ struct sym_entry {
unsigned long long addr;
unsigned int len;
unsigned int seq;
unsigned int start_pos;
unsigned int percpu_absolute;
bool percpu_absolute;
unsigned char sym[];
};
......@@ -63,7 +62,6 @@ static struct sym_entry **table;
static unsigned int table_size, table_cnt;
static int all_symbols;
static int absolute_percpu;
static int base_relative;
static int lto_clang;
static int token_profit[0x10000];
......@@ -76,7 +74,7 @@ static unsigned char best_table_len[256];
static void usage(void)
{
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);
}
......@@ -183,7 +181,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
sym->len = len;
sym->sym[0] = type;
strcpy(sym_name(sym), name);
sym->percpu_absolute = 0;
sym->percpu_absolute = false;
return sym;
}
......@@ -259,12 +257,6 @@ static void shrink_table(void)
}
}
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)
......@@ -285,7 +277,7 @@ static void read_map(const char *in)
if (!sym)
continue;
sym->start_pos = table_cnt;
sym->seq = table_cnt;
if (table_cnt >= table_size) {
table_size += 10000;
......@@ -347,7 +339,7 @@ static int expand_symbol(const unsigned char *data, int len, char *result)
return total;
}
static int symbol_absolute(const struct sym_entry *s)
static bool symbol_absolute(const struct sym_entry *s)
{
return s->percpu_absolute;
}
......@@ -400,7 +392,7 @@ static void write_src(void)
{
unsigned int i, k, off;
unsigned int best_idx[256];
unsigned int *markers;
unsigned int *markers, markers_cnt;
char buf[KSYM_NAME_LEN];
printf("#include <asm/bitsperlong.h>\n");
......@@ -420,7 +412,8 @@ static void write_src(void)
/* table of offset markers, that give the offset in the compressed stream
* 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) {
fprintf(stderr, "kallsyms failure: "
"unable to allocate required memory\n");
......@@ -462,21 +455,19 @@ static void write_src(void)
}
for (k = 0; k < table[i]->len; k++)
printf(", 0x%02x", table[i]->sym[k]);
printf("\n");
}
printf("\n");
/*
* Now that we wrote out the compressed symbol names, restore the
* original names, which are needed in some of the later steps.
*/
for (i = 0; i < table_cnt; i++) {
/*
* Now that we wrote out the compressed symbol name, restore the
* original name and print it in the comment.
*/
expand_symbol(table[i]->sym, table[i]->len, buf);
strcpy((char *)table[i]->sym, buf);
printf("\t/* %s */\n", table[i]->sym);
}
printf("\n");
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("\n");
......@@ -497,54 +488,43 @@ static void write_src(void)
printf("\t.short\t%d\n", best_idx[i]);
printf("\n");
if (!base_relative)
output_label("kallsyms_addresses");
else
output_label("kallsyms_offsets");
output_label("kallsyms_offsets");
for (i = 0; i < table_cnt; i++) {
if (base_relative) {
/*
* Use the offset relative to the lowest value
* encountered of all relative symbols, and emit
* non-relocatable fixed offsets that will be fixed
* up at runtime.
*/
/*
* Use the offset relative to the lowest value
* encountered of all relative symbols, and emit
* non-relocatable fixed offsets that will be fixed
* up at runtime.
*/
long long offset;
int overflow;
if (!absolute_percpu) {
offset = table[i]->addr - relative_base;
overflow = (offset < 0 || offset > UINT_MAX);
} else if (symbol_absolute(table[i])) {
offset = table[i]->addr;
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);
long long offset;
int overflow;
if (!absolute_percpu) {
offset = table[i]->addr - relative_base;
overflow = (offset < 0 || offset > UINT_MAX);
} else if (symbol_absolute(table[i])) {
offset = table[i]->addr;
overflow = (offset < 0 || offset > INT_MAX);
} 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");
if (base_relative) {
output_label("kallsyms_relative_base");
output_address(relative_base);
printf("\n");
}
output_label("kallsyms_relative_base");
output_address(relative_base);
printf("\n");
if (lto_clang)
for (i = 0; i < table_cnt; i++)
......@@ -553,10 +533,11 @@ static void write_src(void)
sort_symbols_by_name();
output_label("kallsyms_seqs_of_names");
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 >> 8),
(unsigned char)(table[i]->seq >> 0));
(unsigned char)(table[i]->seq >> 0),
table[i]->sym);
printf("\n");
}
......@@ -780,7 +761,7 @@ static int compare_symbols(const void *a, const void *b)
return wa - wb;
/* 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)
......@@ -800,7 +781,7 @@ static void make_percpus_absolute(void)
* versions of this tool.
*/
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)
static const struct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1},
{"absolute-percpu", no_argument, &absolute_percpu, 1},
{"base-relative", no_argument, &base_relative, 1},
{"lto-clang", no_argument, &lto_clang, 1},
{},
};
......@@ -847,8 +827,7 @@ int main(int argc, char **argv)
if (absolute_percpu)
make_percpus_absolute();
sort_symbols();
if (base_relative)
record_relative_base();
record_relative_base();
optimize_token_table();
write_src();
......
......@@ -114,51 +114,54 @@ static void set_randconfig_seed(void)
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 symbol *sym;
struct expr *e;
int cnt, def;
struct menu *menu;
int x;
int cnt = 0;
/*
* If choice is mod then we may have more items selected
* and if no then no-one.
* In both cases stop.
* First, count the number of symbols to randomize. If sym_has_value()
* is true, it was specified by KCONFIG_ALLCONFIG. It needs to be
* respected.
*/
if (csym->curr.tri != yes)
return false;
menu_for_each_sub_entry(menu, choice) {
struct symbol *sym = menu->sym;
prop = sym_get_choice_prop(csym);
if (sym && !sym_has_value(sym))
cnt++;
}
/* count entries in choice block */
cnt = 0;
expr_list_for_each_sym(prop->expr, e, sym)
cnt++;
while (cnt > 0) {
x = rand() % cnt;
/*
* find a random value and set it to yes,
* set the rest to no so we have only one set
*/
def = rand() % cnt;
cnt = 0;
expr_list_for_each_sym(prop->expr, e, sym) {
if (def == cnt++) {
sym->def[S_DEF_USER].tri = yes;
csym->def[S_DEF_USER].val = sym;
} else {
sym->def[S_DEF_USER].tri = no;
menu_for_each_sub_entry(menu, choice) {
struct symbol *sym = menu->sym;
if (sym && !sym_has_value(sym))
x--;
if (x < 0) {
sym->def[S_DEF_USER].tri = yes;
sym->flags |= SYMBOL_DEF_USER;
/*
* Move the selected item to the _tail_ because
* this needs to have a lower priority than the
* user input from KCONFIG_ALLCONFIG.
*/
list_move_tail(&sym->choice_link,
&choice->choice_members);
break;
}
}
sym->flags |= SYMBOL_DEF_USER;
/* clear VALID to get value calculated */
sym->flags &= ~SYMBOL_VALID;
cnt--;
}
csym->flags |= SYMBOL_DEF_USER;
/* clear VALID to get value calculated */
csym->flags &= ~SYMBOL_VALID;
return true;
}
enum conf_def_mode {
......@@ -169,9 +172,9 @@ enum conf_def_mode {
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;
/*
* 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)
int pby = 50; /* probability of bool = y */
int pty = 33; /* probability of tristate = y */
int ptm = 33; /* probability of tristate = m */
bool has_changed = false;
if (mode == def_random) {
int n, p[3];
......@@ -227,79 +229,51 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
}
}
for_all_symbols(sym) {
if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
continue;
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;
}
}
menu_for_each_entry(menu) {
struct symbol *sym = menu->sym;
tristate val;
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;
/*
* We have different type of choice blocks.
* If curr.tri equals to mod then we can select several
* choice symbols in one block.
* 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;
if (sym_is_choice(sym)) {
if (mode == def_random)
randomize_choice_values(menu);
continue;
}
}
for_all_symbols(csym) {
if (sym_has_value(csym) || !sym_is_choice(csym))
switch (mode) {
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;
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)
......@@ -448,39 +422,15 @@ static int conf_sym(struct menu *menu)
static void conf_choice(struct menu *menu)
{
struct symbol *sym, *def_sym;
struct symbol *def_sym;
struct menu *child;
bool is_new;
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;
}
}
bool is_new = false;
while (1) {
int cnt, def;
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;
line[0] = 0;
for (child = menu->list; child; child = child->next) {
......@@ -498,8 +448,10 @@ static void conf_choice(struct menu *menu)
printf("%*c", indent, ' ');
printf(" %d. %s (%s)", cnt, menu_get_prompt(child),
child->sym->name);
if (!sym_has_value(child->sym))
if (!sym_has_value(child->sym)) {
is_new = true;
printf(" (NEW)");
}
printf("\n");
}
printf("%*schoice", indent - 1, "");
......@@ -549,7 +501,7 @@ static void conf_choice(struct menu *menu)
print_help(child);
continue;
}
sym_set_tristate_value(child->sym, yes);
choice_set_value(menu, child->sym);
return;
}
}
......@@ -596,9 +548,7 @@ static void conf(struct menu *menu)
if (sym_is_choice(sym)) {
conf_choice(menu);
if (sym->curr.tri != mod)
return;
goto conf_childs;
return;
}
switch (sym->type) {
......@@ -630,10 +580,7 @@ static void check_conf(struct menu *menu)
return;
sym = menu->sym;
if (sym && !sym_has_value(sym) &&
(sym_is_changeable(sym) ||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) {
if (sym && !sym_has_value(sym) && sym_is_changeable(sym)) {
switch (input_mode) {
case listnewconfig:
if (sym->name)
......@@ -849,8 +796,7 @@ int main(int ac, char **av)
conf_set_all_new_symbols(def_default);
break;
case randconfig:
/* Really nothing to do in this loop */
while (conf_set_all_new_symbols(def_random)) ;
conf_set_all_new_symbols(def_random);
break;
case defconfig:
conf_set_all_new_symbols(def_default);
......
......@@ -382,10 +382,7 @@ int conf_read_simple(const char *name, int def)
def_flags = SYMBOL_DEF << def;
for_all_symbols(sym) {
sym->flags |= SYMBOL_CHANGED;
sym->flags &= ~(def_flags|SYMBOL_VALID);
if (sym_is_choice(sym))
sym->flags |= def_flags;
switch (sym->type) {
case S_INT:
case S_HEX:
......@@ -399,6 +396,8 @@ int conf_read_simple(const char *name, int def)
}
while (getline_stripped(&line, &line_asize, in) != -1) {
struct menu *choice;
conf_lineno++;
if (!line[0]) /* blank line */
......@@ -460,25 +459,14 @@ int conf_read_simple(const char *name, int def)
if (conf_set_sym_val(sym, def, def_flags, val))
continue;
if (sym && sym_is_choice_value(sym)) {
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
switch (sym->def[def].tri) {
case no:
break;
case mod:
if (cs->def[def].tri == yes) {
conf_warning("%s creates inconsistent choice state", sym->name);
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);
}
/*
* If this is a choice member, give it the highest priority.
* If conflicting CONFIG options are given from an input file,
* the last one wins.
*/
choice = sym_get_choice_menu(sym);
if (choice)
list_move(&sym->choice_link, &choice->choice_members);
}
free(line);
fclose(in);
......@@ -489,7 +477,6 @@ int conf_read_simple(const char *name, int def)
int conf_read(const char *name)
{
struct symbol *sym;
int conf_unsaved = 0;
conf_set_changed(false);
......@@ -520,23 +507,11 @@ int conf_read(const char *name)
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
/* no previous value and not saved */
continue;
conf_unsaved++;
conf_set_changed(true);
/* maybe print value in verbose mode... */
}
for_all_symbols(sym) {
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)
if (conf_warnings)
conf_set_changed(true);
return 0;
......@@ -784,35 +759,31 @@ int conf_write_defconfig(const char *filename)
struct menu *choice;
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 symbol is a choice value and equals to the
* default for a choice - skip.
*/
choice = sym_get_choice_menu(sym);
if (choice) {
struct symbol *ds;
ds = sym_choice_default(choice->sym);
if (sym == ds) {
if ((sym->type == S_BOOLEAN) &&
sym_get_tristate_value(sym) == yes)
continue;
}
}
print_symbol_for_dotconfig(out, sym);
if (!sym || sym_is_choice(sym))
continue;
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE))
continue;
sym->flags &= ~SYMBOL_WRITE;
/* Skip unchangeable symbols */
if (!sym_is_changeable(sym))
continue;
/* Skip symbols that are equal to the default */
if (!strcmp(sym_get_string_value(sym), sym_get_string_default(sym)))
continue;
/* Skip choice values that are equal to the default */
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);
return 0;
......@@ -1141,16 +1112,14 @@ int conf_write_autoconf(int overwrite)
}
static bool conf_changed;
static void (*conf_changed_callback)(void);
static void (*conf_changed_callback)(bool);
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;
if (conf_changed_callback && changed)
conf_changed_callback();
}
bool conf_get_changed(void)
......@@ -1158,27 +1127,7 @@ bool conf_get_changed(void)
return conf_changed;
}
void conf_set_changed_callback(void (*fn)(void))
void conf_set_changed_callback(void (*fn)(bool))
{
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)
break;
case E_AND:
case E_OR:
case E_LIST:
e->left.expr = expr_copy(org->left.expr);
e->right.expr = expr_copy(org->right.expr);
break;
......@@ -136,9 +135,6 @@ void expr_free(struct expr *e)
static int trans_count;
#define e1 (*ep1)
#define e2 (*ep2)
/*
* expr_eliminate_eq() helper.
*
......@@ -151,38 +147,38 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
{
/* Recurse down to leaves */
if (e1->type == type) {
__expr_eliminate_eq(type, &e1->left.expr, &e2);
__expr_eliminate_eq(type, &e1->right.expr, &e2);
if ((*ep1)->type == type) {
__expr_eliminate_eq(type, &(*ep1)->left.expr, ep2);
__expr_eliminate_eq(type, &(*ep1)->right.expr, ep2);
return;
}
if (e2->type == type) {
__expr_eliminate_eq(type, &e1, &e2->left.expr);
__expr_eliminate_eq(type, &e1, &e2->right.expr);
if ((*ep2)->type == type) {
__expr_eliminate_eq(type, ep1, &(*ep2)->left.expr);
__expr_eliminate_eq(type, ep1, &(*ep2)->right.expr);
return;
}
/* e1 and e2 are leaves. Compare them. */
/* *ep1 and *ep2 are leaves. Compare them. */
if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
e1->left.sym == e2->left.sym &&
(e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
if ((*ep1)->type == E_SYMBOL && (*ep2)->type == E_SYMBOL &&
(*ep1)->left.sym == (*ep2)->left.sym &&
((*ep1)->left.sym == &symbol_yes || (*ep1)->left.sym == &symbol_no))
return;
if (!expr_eq(e1, e2))
if (!expr_eq(*ep1, *ep2))
return;
/* e1 and e2 are equal leaves. Prepare them for elimination. */
/* *ep1 and *ep2 are equal leaves. Prepare them for elimination. */
trans_count++;
expr_free(e1); expr_free(e2);
expr_free(*ep1); expr_free(*ep2);
switch (type) {
case E_OR:
e1 = expr_alloc_symbol(&symbol_no);
e2 = expr_alloc_symbol(&symbol_no);
*ep1 = expr_alloc_symbol(&symbol_no);
*ep2 = expr_alloc_symbol(&symbol_no);
break;
case E_AND:
e1 = expr_alloc_symbol(&symbol_yes);
e2 = expr_alloc_symbol(&symbol_yes);
*ep1 = expr_alloc_symbol(&symbol_yes);
*ep2 = expr_alloc_symbol(&symbol_yes);
break;
default:
;
......@@ -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)
{
if (!e1 || !e2)
if (!*ep1 || !*ep2)
return;
switch (e1->type) {
switch ((*ep1)->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e1->type, ep1, ep2);
__expr_eliminate_eq((*ep1)->type, ep1, ep2);
default:
;
}
if (e1->type != e2->type) switch (e2->type) {
if ((*ep1)->type != (*ep2)->type) switch ((*ep2)->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e2->type, ep1, ep2);
__expr_eliminate_eq((*ep2)->type, ep1, ep2);
default:
;
}
e1 = expr_eliminate_yn(e1);
e2 = expr_eliminate_yn(e2);
*ep1 = expr_eliminate_yn(*ep1);
*ep2 = expr_eliminate_yn(*ep2);
}
#undef e1
#undef e2
/*
* Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
* &&/|| expressions are considered equal if every operand in one expression
......@@ -286,7 +279,6 @@ int expr_eq(struct expr *e1, struct expr *e2)
expr_free(e2);
trans_count = old_count;
return res;
case E_LIST:
case E_RANGE:
case E_NONE:
/* panic */;
......@@ -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)
{
#define e1 (*ep1)
#define e2 (*ep2)
struct expr *tmp;
/* Recurse down to leaves */
if (e1->type == type) {
expr_eliminate_dups1(type, &e1->left.expr, &e2);
expr_eliminate_dups1(type, &e1->right.expr, &e2);
if ((*ep1)->type == type) {
expr_eliminate_dups1(type, &(*ep1)->left.expr, ep2);
expr_eliminate_dups1(type, &(*ep1)->right.expr, ep2);
return;
}
if (e2->type == type) {
expr_eliminate_dups1(type, &e1, &e2->left.expr);
expr_eliminate_dups1(type, &e1, &e2->right.expr);
if ((*ep2)->type == type) {
expr_eliminate_dups1(type, ep1, &(*ep2)->left.expr);
expr_eliminate_dups1(type, ep1, &(*ep2)->right.expr);
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;
switch (e1->type) {
switch ((*ep1)->type) {
case E_OR: case E_AND:
expr_eliminate_dups1(e1->type, &e1, &e1);
expr_eliminate_dups1((*ep1)->type, ep1, ep1);
default:
;
}
switch (type) {
case E_OR:
tmp = expr_join_or(e1, e2);
tmp = expr_join_or(*ep1, *ep2);
if (tmp) {
expr_free(e1); expr_free(e2);
e1 = expr_alloc_symbol(&symbol_no);
e2 = tmp;
expr_free(*ep1); expr_free(*ep2);
*ep1 = expr_alloc_symbol(&symbol_no);
*ep2 = tmp;
trans_count++;
}
break;
case E_AND:
tmp = expr_join_and(e1, e2);
tmp = expr_join_and(*ep1, *ep2);
if (tmp) {
expr_free(e1); expr_free(e2);
e1 = expr_alloc_symbol(&symbol_yes);
e2 = tmp;
expr_free(*ep1); expr_free(*ep2);
*ep1 = expr_alloc_symbol(&symbol_yes);
*ep2 = tmp;
trans_count++;
}
break;
default:
;
}
#undef e1
#undef e2
}
/*
......@@ -639,7 +627,7 @@ struct expr *expr_eliminate_dups(struct expr *e)
return e;
oldcount = trans_count;
while (1) {
do {
trans_count = 0;
switch (e->type) {
case E_OR: case E_AND:
......@@ -647,11 +635,8 @@ struct expr *expr_eliminate_dups(struct expr *e)
default:
;
}
if (!trans_count)
/* No simplifications done in this pass. We're done */
break;
e = expr_eliminate_yn(e);
}
} while (trans_count); /* repeat until we get no more simplifications */
trans_count = oldcount;
return e;
}
......@@ -676,7 +661,6 @@ struct expr *expr_transform(struct expr *e)
case E_LTH:
case E_UNEQUAL:
case E_SYMBOL:
case E_LIST:
break;
default:
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
break;
case E_SYMBOL:
return expr_alloc_comp(type, e->left.sym, sym);
case E_LIST:
case E_RANGE:
case E_NONE:
/* panic */;
......@@ -1083,29 +1066,27 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
case E_GTH:
if (t2 == E_EQUAL || t2 == E_UNEQUAL)
return 1;
/* fallthrough */
case E_EQUAL:
case E_UNEQUAL:
if (t2 == E_NOT)
return 1;
/* fallthrough */
case E_NOT:
if (t2 == E_AND)
return 1;
/* fallthrough */
case E_AND:
if (t2 == E_OR)
return 1;
case E_OR:
if (t2 == E_LIST)
return 1;
case E_LIST:
if (t2 == 0)
return 1;
/* fallthrough */
default:
return -1;
break;
}
return 0;
}
void expr_print(struct expr *e,
void expr_print(const struct expr *e,
void (*fn)(void *, struct symbol *, const char *),
void *data, int prevtoken)
{
......@@ -1171,13 +1152,6 @@ void expr_print(struct expr *e,
fn(data, NULL, " && ");
expr_print(e->right.expr, fn, data, E_AND);
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:
fn(data, NULL, "[");
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
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);
}
......
......@@ -12,12 +12,11 @@ extern "C" {
#include <assert.h>
#include <stdio.h>
#include "list_types.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include "list_types.h"
#include <list_types.h>
typedef enum tristate {
no, mod, yes
......@@ -26,7 +25,7 @@ typedef enum tristate {
enum expr_type {
E_NONE, E_OR, E_AND, E_NOT,
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 {
......@@ -43,9 +42,6 @@ struct expr {
#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
#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 *expr;
tristate tri;
......@@ -73,6 +69,8 @@ enum {
* Represents a configuration symbol.
*
* Choices are represented as a special kind of symbol with null name.
*
* @choice_link: linked to menu::choice_members
*/
struct symbol {
/* link node for the hash table */
......@@ -110,6 +108,8 @@ struct symbol {
/* config entries associated with this symbol */
struct list_head menus;
struct list_head choice_link;
/* SYMBOL_* flags */
int flags;
......@@ -130,10 +130,8 @@ struct symbol {
#define SYMBOL_CONST 0x0001 /* symbol is const */
#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_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_CHECKED 0x2000 /* used during dependency checking */
#define SYMBOL_WARNED 0x8000 /* warning has been issued */
......@@ -145,9 +143,6 @@ struct symbol {
#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] 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
/* A property represent the config options that can be associated
......@@ -170,7 +165,6 @@ enum prop_type {
P_COMMENT, /* text associated with a comment */
P_MENU, /* prompt associated with a menu or menuconfig symbol */
P_DEFAULT, /* default y */
P_CHOICE, /* choice value */
P_SELECT, /* select BAR */
P_IMPLY, /* imply BAR */
P_RANGE, /* range 7..100 (for a symbol) */
......@@ -184,7 +178,7 @@ struct property {
struct expr_value visible;
struct expr *expr; /* the optional conditional part of the property */
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 */
const char *filename; /* what file was this property defined */
int lineno; /* what lineno was this property defined */
......@@ -194,7 +188,6 @@ struct property {
for (st = sym->prop; st; st = st->next) \
if (st->type == (tok))
#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) \
for (st = sym->prop; st; st = st->next) \
if (st->text)
......@@ -204,6 +197,8 @@ struct property {
* 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
* location.
*
* @choice_members: list of choice members with priority.
*/
struct menu {
/* The next menu node at the same level */
......@@ -223,6 +218,8 @@ struct menu {
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
* 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
void expr_fprint(struct expr *e, FILE *out);
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,
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);
}
......
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1
libs=$2
......
......@@ -65,9 +65,6 @@ static void display_list(void);
static void display_tree(struct menu *menu);
static void display_tree_part(void);
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,
GtkStyle *style, gchar *btn_name, gchar **xpm)
......@@ -87,6 +84,12 @@ static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
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 */
static void init_main_window(const gchar *glade_file)
{
......@@ -1051,7 +1054,7 @@ static gchar **fill_row(struct menu *menu)
if (sym_is_choice(sym)) { // parse childs for getting final value
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;
for (child = menu->list; child; child = child->next) {
......@@ -1064,12 +1067,10 @@ static gchar **fill_row(struct menu *menu)
row[COL_VALUE] =
g_strdup(menu_get_prompt(def_menu));
if (sym_get_type(sym) == S_BOOLEAN) {
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
return row;
}
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
return row;
}
if (sym->flags & SYMBOL_CHOICEVAL)
if (sym_is_choice_value(sym))
row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
stype = sym_get_type(sym);
......@@ -1447,10 +1448,3 @@ int main(int ac, char *av[])
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 @@
#ifndef INTERNAL_H
#define INTERNAL_H
#include "hashtable.h"
#include <hashtable.h>
#define SYMBOL_HASHSIZE (1U << 14)
......
......@@ -40,7 +40,6 @@ void zconf_nextfile(const char *name);
/* confdata.c */
extern struct gstr autoconf_cmd;
const char *conf_get_configname(void);
void set_all_choice_values(struct symbol *csym);
/* confdata.c and expr.c */
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
......@@ -76,7 +75,7 @@ struct gstr str_new(void);
void str_free(struct gstr *gs);
void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...);
char *str_get(struct gstr *gs);
char *str_get(const struct gstr *gs);
/* menu.c */
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) \
menu_for_each_sub_entry(menu, &rootmenu)
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);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym);
void menu_add_dep(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_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
void menu_finalize(void);
......@@ -101,8 +101,8 @@ extern struct menu rootmenu;
bool menu_is_empty(struct menu *menu);
bool menu_is_visible(struct menu *menu);
bool menu_has_prompt(struct menu *menu);
const char *menu_get_prompt(struct menu *menu);
bool menu_has_prompt(const struct menu *menu);
const char *menu_get_prompt(const struct menu *menu);
struct menu *menu_get_parent_menu(struct menu *menu);
int get_jump_key_char(void);
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);
/* symbol.c */
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);
const char *sym_get_string_default(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;
}
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)
static inline bool sym_is_choice(const struct symbol *sym)
{
/* A choice is a symbol with no name */
return sym->name == NULL;
}
static inline bool sym_is_choice_value(struct symbol *sym)
{
return sym->flags & SYMBOL_CHOICEVAL ? true : false;
}
bool sym_is_choice_value(const struct symbol *sym);
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;
}
......
......@@ -13,7 +13,7 @@ int conf_write(const char *name);
int conf_write_autoconf(int overwrite);
void conf_set_changed(bool val);
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));
bool conf_errors(void);
......@@ -25,21 +25,23 @@ struct symbol ** sym_re_search(const char *pattern);
const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym);
bool sym_dep_errors(void);
enum symbol_type sym_get_type(struct symbol *sym);
bool sym_tristate_within_range(struct symbol *sym,tristate tri);
enum symbol_type sym_get_type(const struct symbol *sym);
bool sym_tristate_within_range(const 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);
bool sym_string_valid(struct symbol *sym, const char *newval);
bool sym_string_within_range(struct symbol *sym, const char *str);
bool sym_set_string_value(struct symbol *sym, const char *newval);
bool sym_is_changeable(struct symbol *sym);
struct property * sym_get_choice_prop(struct symbol *sym);
struct menu *sym_get_choice_menu(struct symbol *sym);
bool sym_is_changeable(const struct symbol *sym);
struct menu *sym_get_choice_menu(const struct symbol *sym);
const char * sym_get_string_value(struct symbol *sym);
const char * prop_get_type_name(enum prop_type type);
/* 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 */
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1
libs=$2
......
......@@ -19,7 +19,7 @@
#include <signal.h>
#include <unistd.h>
#include "list.h"
#include <list.h>
#include "lkc.h"
#include "lxdialog/dialog.h"
#include "mnconf-common.h"
......@@ -514,7 +514,7 @@ static void build_conf(struct menu *menu)
type = sym_get_type(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;
child_count++;
......@@ -523,28 +523,14 @@ static void build_conf(struct menu *menu)
def_menu = child;
}
val = sym_get_tristate_value(sym);
if (sym_is_changeable(sym)) {
switch (val) {
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_make(" ");
item_set_tag(def_menu ? 't' : ':');
item_set_data(menu);
item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
if (val == yes) {
if (def_menu)
item_add_str(" (%s) --->", menu_get_prompt(def_menu));
return;
}
if (def_menu)
item_add_str(" (%s) --->", menu_get_prompt(def_menu));
return;
} else {
if (menu == current_menu) {
item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
......@@ -614,7 +600,7 @@ static void conf_choice(struct menu *menu)
struct menu *child;
struct symbol *active;
active = sym_get_choice_value(menu->sym);
active = sym_calc_choice(menu);
while (1) {
int res;
int selected;
......@@ -633,7 +619,7 @@ static void conf_choice(struct menu *menu)
item_set_data(child);
if (child->sym == active)
item_set_selected(1);
if (child->sym == sym_get_choice_value(menu->sym))
if (child->sym == sym_calc_choice(menu))
item_set_tag('X');
}
dialog_clear();
......@@ -650,7 +636,7 @@ static void conf_choice(struct menu *menu)
if (!child->sym)
break;
sym_set_tristate_value(child->sym, yes);
choice_set_value(menu, child->sym);
}
return;
case 1:
......@@ -814,7 +800,7 @@ static void conf(struct menu *menu, struct menu *active_menu)
conf(submenu, NULL);
break;
case 't':
if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
if (sym_is_choice(sym))
conf_choice(submenu);
else if (submenu->prompt->type == P_MENU)
conf(submenu, NULL);
......
......@@ -8,9 +8,9 @@
#include <stdlib.h>
#include <string.h>
#include <list.h>
#include "lkc.h"
#include "internal.h"
#include "list.h"
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)
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_start(ap, fmt);
......@@ -48,7 +48,7 @@ void menu_warn(struct menu *menu, const char *fmt, ...)
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_start(ap, fmt);
......@@ -175,7 +175,7 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
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 property *prop = menu_add_prop(type, NULL, dep);
......@@ -306,7 +306,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
struct menu *menu, *last_menu;
struct symbol *sym;
struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2, **ep;
struct expr *basedep, *dep, *dep2;
sym = parent->sym;
if (parent->list) {
......@@ -315,35 +315,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
* 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 (menu = parent->list; menu; menu = menu->next) {
/*
......@@ -352,7 +323,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
*/
basedep = rewrite_m(menu->dep);
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);
menu->dep = basedep;
......@@ -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
* moving on
*/
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) {
/*
* 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)
sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
}
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:
*
......@@ -575,17 +515,6 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
sym_check_prop(sym);
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)
......@@ -593,7 +522,7 @@ void menu_finalize(void)
_menu_finalize(&rootmenu, false);
}
bool menu_has_prompt(struct menu *menu)
bool menu_has_prompt(const struct menu *menu)
{
if (!menu->prompt)
return false;
......@@ -618,7 +547,6 @@ bool menu_is_empty(struct menu *menu)
bool menu_is_visible(struct menu *menu)
{
struct menu *child;
struct symbol *sym;
tristate visible;
......@@ -637,24 +565,10 @@ bool menu_is_visible(struct menu *menu)
} else
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
if (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;
return visible != no;
}
const char *menu_get_prompt(struct menu *menu)
const char *menu_get_prompt(const struct menu *menu)
{
if (menu->prompt)
return menu->prompt->text;
......@@ -675,13 +589,14 @@ struct menu *menu_get_parent_menu(struct menu *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",
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)) {
str_append(r, prefix);
......
// SPDX-License-Identifier: GPL-2.0-only
#include <list.h>
#include "expr.h"
#include "list.h"
#include "mnconf-common.h"
int jump_key_char;
......
......@@ -4,6 +4,8 @@
#include <stddef.h>
#include <list_types.h>
struct search_data {
struct list_head *head;
struct menu *target;
......
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1
libs=$2
......
......@@ -11,7 +11,7 @@
#include <strings.h>
#include <stdlib.h>
#include "list.h"
#include <list.h>
#include "lkc.h"
#include "mnconf-common.h"
#include "nconf.h"
......@@ -815,7 +815,7 @@ static void build_conf(struct menu *menu)
type = sym_get_type(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;
child_count++;
......@@ -825,30 +825,13 @@ static void build_conf(struct menu *menu)
}
val = sym_get_tristate_value(sym);
if (sym_is_changeable(sym)) {
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_make(menu, def_menu ? 't' : ':', " ");
item_add_str("%*c%s", indent + 1,
' ', menu_get_prompt(menu));
if (val == yes) {
if (def_menu)
item_add_str(" (%s) --->", menu_get_prompt(def_menu));
return;
}
if (def_menu)
item_add_str(" (%s) --->", menu_get_prompt(def_menu));
return;
} else {
if (menu == current_menu) {
item_make(menu, ':',
......@@ -1191,8 +1174,7 @@ static void selected_conf(struct menu *menu, struct menu *active_menu)
conf(submenu);
break;
case 't':
if (sym_is_choice(sym) &&
sym_get_tristate_value(sym) == yes)
if (sym_is_choice(sym))
conf_choice(submenu);
else if (submenu->prompt &&
submenu->prompt->type == P_MENU)
......@@ -1257,7 +1239,7 @@ static void conf_choice(struct menu *menu)
.pattern = "",
};
active = sym_get_choice_value(menu->sym);
active = sym_calc_choice(menu);
/* this is mostly duplicated from the conf() function. */
while (!global_exit) {
reset_menu();
......@@ -1266,7 +1248,7 @@ static void conf_choice(struct menu *menu)
if (!show_all_items && !menu_is_visible(child))
continue;
if (child->sym == sym_get_choice_value(menu->sym))
if (child->sym == sym_calc_choice(menu))
item_make(child, ':', "<X> %s",
menu_get_prompt(child));
else if (child->sym)
......@@ -1349,7 +1331,7 @@ static void conf_choice(struct menu *menu)
case ' ':
case 10:
case KEY_RIGHT:
sym_set_tristate_value(child->sym, yes);
choice_set_value(menu, child->sym);
return;
case 'h':
case '?':
......
......@@ -28,9 +28,7 @@ static void zconf_error(const char *err, ...);
static bool zconf_endtoken(const char *tokenname,
const char *expected_tokenname);
struct menu *current_menu, *current_entry;
static bool inside_choice = false;
struct menu *current_menu, *current_entry, *current_choice;
%}
......@@ -90,7 +88,7 @@ static bool inside_choice = false;
%type <symbol> nonconst_symbol
%type <symbol> symbol
%type <type> type logic_type default
%type <type> type default
%type <expr> expr
%type <expr> if_expr
%type <string> end
......@@ -147,12 +145,21 @@ config_entry_start: T_CONFIG nonconst_symbol T_EOL
config_stmt: config_entry_start config_option_list
{
if (inside_choice) {
if (current_choice) {
if (!current_entry->prompt) {
fprintf(stderr, "%s:%d: error: choice member must have a prompt\n",
current_entry->filename, current_entry->lineno);
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);
......@@ -234,7 +241,9 @@ choice: T_CHOICE T_EOL
struct symbol *sym = sym_lookup(NULL, 0);
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);
};
......@@ -248,12 +257,12 @@ choice_entry: choice choice_option_list
$$ = menu_add_menu();
inside_choice = true;
current_choice = current_entry;
};
choice_end: end
{
inside_choice = false;
current_choice = NULL;
if (zconf_endtoken($1, "choice")) {
menu_end_menu();
......@@ -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);
};
choice_option: logic_type prompt_stmt_opt T_EOL
choice_option: T_BOOL T_WORD_QUOTE if_expr T_EOL
{
menu_set_type($1);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
menu_add_prompt(P_PROMPT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:bool\n", cur_filename, cur_lineno);
};
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:
logic_type
T_BOOL { $$ = S_BOOLEAN; }
| T_TRISTATE { $$ = S_TRISTATE; }
| T_INT { $$ = S_INT; }
| T_HEX { $$ = S_HEX; }
| T_STRING { $$ = S_STRING; }
logic_type:
T_BOOL { $$ = S_BOOLEAN; }
| T_TRISTATE { $$ = S_TRISTATE; }
default:
T_DEFAULT { $$ = S_UNKNOWN; }
| T_DEF_BOOL { $$ = S_BOOLEAN; }
......@@ -483,7 +489,7 @@ assign_val:
*
* 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;
int ret = 0;
......@@ -638,7 +644,7 @@ static void print_quoted_string(FILE *out, const char *str)
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 property *prop;
......@@ -689,9 +695,6 @@ static void print_symbol(FILE *out, struct menu *menu)
}
fputc('\n', out);
break;
case P_CHOICE:
fputs(" #choice value\n", out);
break;
case P_SELECT:
fputs( " select ", out);
expr_fprint(prop->expr, out);
......
......@@ -9,9 +9,9 @@
#include <stdlib.h>
#include <string.h>
#include "array_size.h"
#include <array_size.h>
#include <list.h>
#include "internal.h"
#include "list.h"
#include "lkc.h"
#include "preprocess.h"
......
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
set -eu
cflags=$1
libs=$2
bin=$3
......
......@@ -147,7 +147,7 @@ void ConfigItem::updateMenu(void)
expr = sym_get_tristate_value(sym);
switch (expr) {
case yes:
if (sym_is_choice_value(sym) && type == S_BOOLEAN)
if (sym_is_choice_value(sym))
setIcon(promptColIdx, choiceYesIcon);
else
setIcon(promptColIdx, symbolYesIcon);
......@@ -1101,14 +1101,6 @@ QString ConfigInfoView::debug_info(struct symbol *sym)
&stream, E_NONE);
stream << "<br>";
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:
stream << "unknown property: ";
stream << prop_get_type_name(prop->type);
......@@ -1397,8 +1389,6 @@ ConfigMainWindow::ConfigMainWindow(void)
conf_set_changed_callback(conf_changed);
// Set saveAction's initial state
conf_changed();
configname = xstrdup(conf_get_configname());
QAction *saveAsAction = new QAction("Save &As...", this);
......@@ -1851,10 +1841,10 @@ void ConfigMainWindow::saveSettings(void)
configSettings->writeSizes("/split2", split2->sizes());
}
void ConfigMainWindow::conf_changed(void)
void ConfigMainWindow::conf_changed(bool dirty)
{
if (saveAction)
saveAction->setEnabled(conf_get_changed());
saveAction->setEnabled(dirty);
}
void fixup_rootmenu(struct menu *menu)
......@@ -1904,7 +1894,6 @@ int main(int ac, char** av)
conf_parse(name);
fixup_rootmenu(&rootmenu);
conf_read(NULL);
//zconfdump(stdout);
configApp = new QApplication(ac, av);
......@@ -1916,6 +1905,9 @@ int main(int ac, char** av)
//zconfdump(stdout);
configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
conf_read(NULL);
v->show();
configApp->exec();
......
......@@ -239,7 +239,7 @@ class ConfigMainWindow : public QMainWindow {
char *configname;
static QAction *saveAction;
static void conf_changed(void);
static void conf_changed(bool);
public:
ConfigMainWindow(void);
public slots:
......
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0
config MODULES
bool "Enable loadable module support"
modules
default y
choice
prompt "boolean choice"
default BOOL_CHOICE1
......@@ -16,15 +11,3 @@ config BOOL_CHOICE1
bool "choice 1"
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
"""
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):
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):
assert conf.allyesconfig() == 0
assert conf.config_contains('allyes_expected_config')
......
CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set
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_CHOICE1=y
CONFIG_TRI_CHOICE0=m
CONFIG_TRI_CHOICE1=m
# CONFIG_MODULES is not set
# CONFIG_BOOL_CHOICE0 is not set
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_CHOICE1=y
# CONFIG_TRI_CHOICE0 is not set
CONFIG_TRI_CHOICE1=y
Enable loadable module support (MODULES) [Y/n/?] (NEW)
boolean choice
1. choice 0 (BOOL_CHOICE0) (NEW)
> 2. choice 1 (BOOL_CHOICE1) (NEW)
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!
Kconfig:5: symbol A depends on A
error: recursive dependency detected!
symbol A depends on A
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:11:error: recursive dependency detected!
Kconfig:11: symbol B is selected by B
error: recursive dependency detected!
symbol B is selected by B
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:17:error: recursive dependency detected!
Kconfig:17: symbol C1 depends on C2
Kconfig:21: symbol C2 depends on C1
error: recursive dependency detected!
symbol C1 depends on C2
symbol C2 depends on C1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:27:error: recursive dependency detected!
Kconfig:27: symbol D1 depends on D2
Kconfig:32: symbol D2 is selected by D1
error: recursive dependency detected!
symbol D1 depends on D2
symbol D2 is selected by D1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:37:error: recursive dependency detected!
Kconfig:37: symbol E1 depends on E2
Kconfig:42: symbol E2 is implied by E1
error: recursive dependency detected!
symbol E1 depends on E2
symbol E2 is implied by E1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:49:error: recursive dependency detected!
Kconfig:49: symbol F1 default value contains F2
Kconfig:51: symbol F2 depends on F1
error: recursive dependency detected!
symbol F1 default value contains F2
symbol F2 depends on F1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:60:error: recursive dependency detected!
Kconfig:60: symbol G depends on G
error: recursive dependency detected!
symbol G depends on G
For a resolution refer to Documentation/kbuild/kconfig-language.rst
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 @@
#include <stdlib.h>
#include <string.h>
#include "hashtable.h"
#include <hashtable.h>
#include "lkc.h"
unsigned int strhash(const char *s)
......@@ -98,7 +98,7 @@ void str_printf(struct gstr *gs, const char *fmt, ...)
}
/* Retrieve value of growable string */
char *str_get(struct gstr *gs)
char *str_get(const struct gstr *gs)
{
return gs->s;
}
......
......@@ -45,7 +45,6 @@ info()
# Link of vmlinux
# ${1} - output file
# ${2}, ${3}, ... - optional extra .o files
vmlinux_link()
{
local output=${1}
......@@ -90,7 +89,7 @@ vmlinux_link()
ldflags="${ldflags} ${wl}--script=${objtree}/${KBUILD_LDS}"
# 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"
fi
......@@ -101,15 +100,15 @@ vmlinux_link()
${ld} ${ldflags} -o ${output} \
${wl}--whole-archive ${objs} ${wl}--no-whole-archive \
${wl}--start-group ${libs} ${wl}--end-group \
$@ ${ldlibs}
${kallsymso} ${btf_vmlinux_bin_o} ${ldlibs}
}
# generate .BTF typeinfo from DWARF debuginfo
# ${1} - vmlinux image
# ${2} - file to dump raw BTF data into
gen_btf()
{
local pahole_ver
local btf_data=${1}.btf.o
if ! [ -x "$(command -v ${PAHOLE})" ]; then
echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available"
......@@ -122,18 +121,16 @@ gen_btf()
return 1
fi
vmlinux_link ${1}
info "BTF" ${2}
info BTF "${btf_data}"
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
# deletes all symbols including __start_BTF and __stop_BTF, which will
# be redefined in the linker script. Add 2>/dev/null to suppress GNU
# objcopy warnings: "empty loadable segment detected at ..."
${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.
# GNU ld 2.35+ and lld do not allow an ET_EXEC input.
if is_enabled CONFIG_CPU_BIG_ENDIAN; then
......@@ -141,10 +138,12 @@ gen_btf()
else
et_rel='\1\0'
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()
{
local kallsymopt;
......@@ -157,35 +156,27 @@ kallsyms()
kallsymopt="${kallsymopt} --absolute-percpu"
fi
if is_enabled CONFIG_KALLSYMS_BASE_RELATIVE; then
kallsymopt="${kallsymopt} --base-relative"
fi
if is_enabled CONFIG_LTO_CLANG; then
kallsymopt="${kallsymopt} --lto-clang"
fi
info KSYMS ${2}
scripts/kallsyms ${kallsymopt} ${1} > ${2}
info KSYMS "${2}.S"
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
# vmlinux.
kallsyms_step()
# Perform kallsyms for the given temporary vmlinux.
sysmap_and_kallsyms()
{
kallsymso_prev=${kallsymso}
kallsyms_vmlinux=.tmp_vmlinux.kallsyms${1}
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}
mksysmap "${1}" "${1}.syms"
kallsyms "${1}.syms" "${1}.kallsyms"
info AS ${kallsymso}
${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
-c -o ${kallsymso} ${kallsyms_S}
kallsyms_sysmap=${1}.syms
}
# Create map file with all symbols from ${1}
......@@ -223,26 +214,40 @@ fi
${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
btf_vmlinux_bin_o=.btf.vmlinux.bin.o
if ! gen_btf .tmp_vmlinux.btf $btf_vmlinux_bin_o ; then
if ! gen_btf .tmp_vmlinux1; then
echo >&2 "Failed to generate BTF for vmlinux"
echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
exit 1
fi
fi
kallsymso=""
kallsymso_prev=""
kallsyms_vmlinux=""
if is_enabled CONFIG_KALLSYMS; then
# kallsyms support
# 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,
# but __kallsyms is empty.
# with a dummy __kallsyms.
# Running kallsyms on that gives us .tmp_kallsyms1.o with
# the right size
# 2) Link .tmp_vmlinux.kallsyms2 so it now has a __kallsyms section of
......@@ -261,19 +266,25 @@ if is_enabled CONFIG_KALLSYMS; then
# a) Verify that the System.map from vmlinux matches the map from
# ${kallsymso}.
kallsyms_step 1
kallsyms_step 2
# The kallsyms linking does not need debug symbols included.
strip_debug=1
# step 3
size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso_prev})
sysmap_and_kallsyms .tmp_vmlinux1
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})
if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
kallsyms_step 3
vmlinux_link .tmp_vmlinux3
sysmap_and_kallsyms .tmp_vmlinux3
fi
fi
vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o}
strip_debug=
vmlinux_link vmlinux
# fill in BTF IDs
if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then
......@@ -293,7 +304,7 @@ fi
# step a (see comment above)
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 'Try "make KALLSYMS_EXTRA_PASS=1" as a workaround'
exit 1
......
......@@ -22,6 +22,11 @@ the entire FIT.
Use -c to compress the data, using bzip2, gzip, lz4, lzma, lzo and
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
as U-Boot, Linuxboot, Tianocore, etc.
......@@ -64,6 +69,8 @@ def parse_args():
help='Specifies the architecture')
parser.add_argument('-c', '--compress', type=str, default='none',
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',
help='Convert the FIT to use external data')
parser.add_argument('-n', '--name', type=str, required=True,
......@@ -140,12 +147,12 @@ def finish_fit(fsw, entries):
fsw.end_node()
seq = 0
with fsw.add_node('configurations'):
for model, compat in entries:
for model, compat, files in entries:
seq += 1
with fsw.add_node(f'conf-{seq}'):
fsw.property('compatible', bytes(compat))
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.end_node()
......@@ -193,21 +200,9 @@ def output_dtb(fsw, seq, fname, arch, compress):
fname (str): Filename containing the DTB
arch: FIT architecture, e.g. 'arm64'
compress (str): Compressed algorithm, e.g. 'gzip'
Returns:
tuple:
str: Model name
bytes: Compatible stringlist
"""
with fsw.add_node(f'fdt-{seq}'):
# 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')
fsw.property_string('description', model)
fsw.property_string('description', os.path.basename(fname))
fsw.property_string('type', 'flat_dt')
fsw.property_string('arch', arch)
fsw.property_string('compression', compress)
......@@ -215,9 +210,45 @@ def output_dtb(fsw, seq, fname, arch, compress):
with open(fname, 'rb') as inf:
compressed = compress_data(inf, compress)
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):
"""Build the FIT from the provided files and arguments
......@@ -235,6 +266,7 @@ def build_fit(args):
fsw = libfdt.FdtSw()
setup_fit(fsw, args.name)
entries = []
fdts = {}
# Handle the kernel
with open(args.kernel, 'rb') as inf:
......@@ -243,12 +275,22 @@ def build_fit(args):
write_kernel(fsw, comp_data, args)
for fname in args.dtbs:
# Ignore overlay (.dtbo) files
if os.path.splitext(fname)[1] == '.dtb':
seq += 1
size += os.path.getsize(fname)
model, compat = output_dtb(fsw, seq, fname, args.arch, args.compress)
entries.append([model, compat])
# Ignore non-DTB (*.dtb) files
if os.path.splitext(fname)[1] != '.dtb':
continue
(model, compat, files) = process_dtb(fname, args)
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)
......
/* 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 @@
#include <limits.h>
#include <stdbool.h>
#include <errno.h>
#include <hashtable.h>
#include <list.h>
#include "modpost.h"
#include "../../include/linux/license.h"
......@@ -199,13 +202,8 @@ static struct module *new_module(const char *name, size_t namelen)
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 *next;
struct hlist_node hnode;/* link to hash table */
struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */
struct module *module;
char *namespace;
......@@ -218,7 +216,7 @@ struct symbol {
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 */
static inline unsigned int tdb_hash(const char *name)
......@@ -250,11 +248,7 @@ static struct symbol *alloc_symbol(const char *name)
/* For the hash of exported symbols */
static void hash_add_symbol(struct symbol *sym)
{
unsigned int hash;
hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE;
sym->next = symbolhash[hash];
symbolhash[hash] = sym;
hash_add(symbol_hashtable, &sym->hnode, tdb_hash(sym->name));
}
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)
if (name[0] == '.')
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))
return s;
}
......@@ -954,17 +948,6 @@ static int secref_whitelist(const char *fromsec, const char *fromsym,
match(fromsym, PATTERNS("*_ops", "*_probe", "*_console")))
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 */
if (strstarts(fromsec, ".head.text") &&
match(tosec, PATTERNS(ALL_INIT_SECTIONS)))
......@@ -1168,40 +1151,6 @@ static Elf_Addr addend_386_rel(uint32_t *location, unsigned int r_type)
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)
{
uint8_t shift = 31 - index;
......@@ -1262,7 +1211,7 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
((lower & 0x07ff) << 1),
20);
return offset + sym->st_value + 4;
case R_ARM_THM_CALL:
case R_ARM_THM_PC22:
case R_ARM_THM_JUMP24:
/*
* Encoding T4:
......
......@@ -13,7 +13,7 @@
#include <elf.h>
#include "../../include/linux/module_symbol.h"
#include "list.h"
#include <list_types.h>
#include "elfconfig.h"
/* 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 @@
# specified in KDEB_HOOKDIR) that will be called on package install and
# removal.
set -e
set -eu
is_enabled() {
grep -q "^$1=y" include/config/auto.conf
......
......@@ -11,7 +11,7 @@
# Wichert Akkerman <wichert@wiggy.net>.
#
set -e
set -eu
#
# Some variables and settings used throughout the script
......
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
set -eu
diff_patch=$1
mkdir -p "$(dirname "${diff_patch}")"
......
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
set -e
set -eu
destdir=${1}
test -n "${srctree}"
test -n "${SRCARCH}"
is_enabled() {
grep -q "^$1=y" include/config/auto.conf
}
......
......@@ -27,7 +27,7 @@ The Linux Kernel, the operating system core itself
%package headers
Summary: Header files for the Linux kernel for use by glibc
Group: Development/System
Obsoletes: kernel-headers
Obsoletes: kernel-headers < %{version}
Provides: kernel-headers = %{version}
%description headers
Kernel-headers includes the C header files that specify the interface
......
......@@ -4,7 +4,7 @@
#
# Simple script to generate a debian/ directory for a Linux kernel.
set -e
set -eu
is_enabled() {
grep -q "^$1=y" include/config/auto.conf
......@@ -19,7 +19,7 @@ if_enabled_echo() {
}
set_debarch() {
if [ -n "$KBUILD_DEBARCH" ] ; then
if [ "${KBUILD_DEBARCH:+set}" ]; then
debarch="$KBUILD_DEBARCH"
return
fi
......@@ -125,32 +125,34 @@ gen_source ()
rm -rf debian
mkdir debian
email=${DEBEMAIL-$EMAIL}
# use email string directly if it contains <email>
if echo "${email}" | grep -q '<.*>'; then
maintainer=${email}
user=${KBUILD_BUILD_USER:-$(id -nu)}
name=${DEBFULLNAME:-${user}}
if [ "${DEBEMAIL:+set}" ]; then
email=${DEBEMAIL}
else
# or construct the maintainer string
user=${KBUILD_BUILD_USER-$(id -nu)}
name=${DEBFULLNAME-${user}}
if [ -z "${email}" ]; then
buildhost=${KBUILD_BUILD_HOST-$(hostname -f 2>/dev/null || hostname)}
email="${user}@${buildhost}"
fi
maintainer="${name} <${email}>"
buildhost=${KBUILD_BUILD_HOST:-$(hostname -f 2>/dev/null || hostname)}
email="${user}@${buildhost}"
fi
maintainer="${name} <${email}>"
if [ "$1" = --need-source ]; then
gen_source
fi
while [ $# -gt 0 ]; do
case "$1" in
--need-source)
gen_source
shift
;;
*)
break
;;
esac
done
# Some variables and settings used throughout the script
version=$KERNELRELEASE
if [ -n "$KDEB_PKGVERSION" ]; then
if [ "${KDEB_PKGVERSION:+set}" ]; then
packageversion=$KDEB_PKGVERSION
else
packageversion=$(${srctree}/scripts/setlocalversion --no-local ${srctree})-$($srctree/init/build-version)
packageversion=$(${srctree}/scripts/setlocalversion --no-local ${srctree})-$($srctree/scripts/build-version)
fi
sourcename=${KDEB_SOURCENAME:-linux-upstream}
......@@ -164,7 +166,7 @@ debarch=
set_debarch
# Try to determine distribution
if [ -n "$KDEB_CHANGELOG_DIST" ]; then
if [ "${KDEB_CHANGELOG_DIST:+set}" ]; then
distribution=$KDEB_CHANGELOG_DIST
# 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
......
......@@ -9,6 +9,8 @@
# Patched for non-x86 by Opencon (L) 2002 <opencon@rio.skydome.net>
#
set -eu
output=$1
mkdir -p "$(dirname "${output}")"
......@@ -24,7 +26,30 @@ fi
cat<<EOF
%define ARCH ${ARCH}
%define KERNELRELEASE ${KERNELRELEASE}
%define pkg_release $("${srctree}/init/build-version")
%define pkg_release $("${srctree}/scripts/build-version")
EOF
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
# 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.
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
......@@ -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
* stable symbol list.
*/
"kallsyms_addresses",
"kallsyms_offsets",
"kallsyms_relative_base",
"kallsyms_num_syms",
......
......@@ -62,8 +62,8 @@ $(deps_initramfs): ;
quiet_cmd_initfs = GEN $@
cmd_initfs = \
$(CONFIG_SHELL) $< -o $@ -l $(obj)/.initramfs_data.cpio.d \
$(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
$(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) \
$(addprefix -u , $(CONFIG_INITRAMFS_ROOT_UID)) \
$(addprefix -g , $(CONFIG_INITRAMFS_ROOT_GID)) \
$(if $(KBUILD_BUILD_TIMESTAMP), -d "$(KBUILD_BUILD_TIMESTAMP)") \
$(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