Commit 1d35aae7 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull Kbuild updates from Masahiro Yamada:

 - Generate a list of built DTB files (arch/*/boot/dts/dtbs-list)

 - Use more threads when building Debian packages in parallel

 - Fix warnings shown during the RPM kernel package uninstallation

 - Change OBJECT_FILES_NON_STANDARD_*.o etc. to take a relative path to
   Makefile

 - Support GCC's -fmin-function-alignment flag

 - Fix a null pointer dereference bug in modpost

 - Add the DTB support to the RPM package

 - Various fixes and cleanups in Kconfig

* tag 'kbuild-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild: (67 commits)
  kconfig: tests: test dependency after shuffling choices
  kconfig: tests: add a test for randconfig with dependent choices
  kconfig: tests: support KCONFIG_SEED for the randconfig runner
  kbuild: rpm-pkg: add dtb files in kernel rpm
  kconfig: remove unneeded menu_is_visible() call in conf_write_defconfig()
  kconfig: check prompt for choice while parsing
  kconfig: lxdialog: remove unused dialog colors
  kconfig: lxdialog: fix button color for blackbg theme
  modpost: fix null pointer dereference
  kbuild: remove GCC's default -Wpacked-bitfield-compat flag
  kbuild: unexport abs_srctree and abs_objtree
  kbuild: Move -Wenum-{compare-conditional,enum-conversion} into W=1
  kconfig: remove named choice support
  kconfig: use linked list in get_symbol_str() to iterate over menus
  kconfig: link menus to a symbol
  kbuild: fix inconsistent indentation in top Makefile
  kbuild: Use -fmin-function-alignment when available
  alpha: merge two entries for CONFIG_ALPHA_GAMMA
  alpha: merge two entries for CONFIG_ALPHA_EV4
  kbuild: change DTC_FLAGS_<basetarget>.o to take the path relative to $(obj)
  ...
parents 88d92fb1 f2fd2aad
......@@ -52,6 +52,7 @@
*.xz
*.zst
Module.symvers
dtbs-list
modules.order
#
......
......@@ -393,7 +393,7 @@ of C0, which doesn't depend on M::
choices::
"choice" [symbol]
"choice"
<choice options>
<choice block>
"endchoice"
......@@ -412,10 +412,6 @@ the kernel, but all drivers can be compiled as modules.
A choice accepts another option "optional", which allows to set the
choice to 'n' and no entry needs to be selected.
If no [symbol] is associated with a choice, then you can not have multiple
definitions of that choice. If a [symbol] is associated to the choice,
then you may define the same choice (i.e. with the same entries) in another
place.
comment::
......
===================
Kconfig make config
===================
=================================
Configuration targets and editors
=================================
This file contains some assistance for using `make *config`.
This file contains some assistance for using ``make *config``.
Use "make help" to list all of the possible configuration targets.
Use ``make help`` to list all of the possible configuration targets.
The xconfig ('qconf'), menuconfig ('mconf'), and nconfig ('nconf')
programs also have embedded help text. Be sure to check that for
......@@ -12,8 +12,9 @@ navigation, search, and other general help text.
The gconfig ('gconf') program has limited help text.
General
-------
=======
New kernel releases often introduce new config symbols. Often more
important, new kernel releases may rename config symbols. When
......@@ -34,102 +35,86 @@ Alternatively, you can use the brute force method::
make oldconfig
scripts/diffconfig .config.old .config | less
----------------------------------------------------------------------
Environment variables for `*config`
KCONFIG_CONFIG
--------------
This environment variable can be used to specify a default kernel config
file name to override the default name of ".config".
KCONFIG_DEFCONFIG_LIST
----------------------
This environment variable specifies a list of config files which can be used
as a base configuration in case the .config does not exist yet. Entries in
the list are separated with whitespaces to each other, and the first one
that exists is used.
Environment variables
=====================
KCONFIG_OVERWRITECONFIG
-----------------------
If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
break symlinks when .config is a symlink to somewhere else.
Environment variables for ``*config``:
KCONFIG_WARN_UNKNOWN_SYMBOLS
----------------------------
This environment variable makes Kconfig warn about all unrecognized
symbols in the config input.
``KCONFIG_CONFIG``
This environment variable can be used to specify a default kernel config
file name to override the default name of ".config".
KCONFIG_WERROR
--------------
If set, Kconfig treats warnings as errors.
``KCONFIG_DEFCONFIG_LIST``
This environment variable specifies a list of config files which can be
used as a base configuration in case the .config does not exist yet.
Entries in the list are separated with whitespaces to each other, and
the first one that exists is used.
`CONFIG_`
---------
If you set `CONFIG_` in the environment, Kconfig will prefix all symbols
with its value when saving the configuration, instead of using the default,
`CONFIG_`.
``KCONFIG_OVERWRITECONFIG``
If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
break symlinks when .config is a symlink to somewhere else.
----------------------------------------------------------------------
``KCONFIG_WARN_UNKNOWN_SYMBOLS``
This environment variable makes Kconfig warn about all unrecognized
symbols in the config input.
Environment variables for '{allyes/allmod/allno/rand}config'
``KCONFIG_WERROR``
If set, Kconfig treats warnings as errors.
KCONFIG_ALLCONFIG
-----------------
(partially based on lkml email from/by Rob Landley, re: miniconfig)
``CONFIG_``
If you set ``CONFIG_`` in the environment, Kconfig will prefix all symbols
with its value when saving the configuration, instead of using the
default, ``CONFIG_``.
--------------------------------------------------
Environment variables for ``{allyes/allmod/allno/rand}config``:
The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also
use the environment variable KCONFIG_ALLCONFIG as a flag or a filename
that contains config symbols that the user requires to be set to a
specific value. If KCONFIG_ALLCONFIG is used without a filename where
KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", `make *config`
checks for a file named "all{yes/mod/no/def/random}.config"
(corresponding to the `*config` command that was used) for symbol values
that are to be forced. If this file is not found, it checks for a
file named "all.config" to contain forced values.
``KCONFIG_ALLCONFIG``
The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also
use the environment variable KCONFIG_ALLCONFIG as a flag or a filename
that contains config symbols that the user requires to be set to a
specific value. If KCONFIG_ALLCONFIG is used without a filename where
KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", ``make *config``
checks for a file named "all{yes/mod/no/def/random}.config"
(corresponding to the ``*config`` command that was used) for symbol values
that are to be forced. If this file is not found, it checks for a
file named "all.config" to contain forced values.
This enables you to create "miniature" config (miniconfig) or custom
config files containing just the config symbols that you are interested
in. Then the kernel config system generates the full .config file,
including symbols of your miniconfig file.
This enables you to create "miniature" config (miniconfig) or custom
config files containing just the config symbols that you are interested
in. Then the kernel config system generates the full .config file,
including symbols of your miniconfig file.
This 'KCONFIG_ALLCONFIG' file is a config file which contains
(usually a subset of all) preset config symbols. These variable
settings are still subject to normal dependency checks.
This ``KCONFIG_ALLCONFIG`` file is a config file which contains
(usually a subset of all) preset config symbols. These variable
settings are still subject to normal dependency checks.
Examples::
Examples::
KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig
or::
or::
KCONFIG_ALLCONFIG=mini.config make allnoconfig
or::
or::
make KCONFIG_ALLCONFIG=mini.config allnoconfig
These examples will disable most options (allnoconfig) but enable or
disable the options that are explicitly listed in the specified
mini-config files.
----------------------------------------------------------------------
These examples will disable most options (allnoconfig) but enable or
disable the options that are explicitly listed in the specified
mini-config files.
Environment variables for 'randconfig'
Environment variables for ``randconfig``:
KCONFIG_SEED
------------
You can set this to the integer value used to seed the RNG, if you want
to somehow debug the behaviour of the kconfig parser/frontends.
If not set, the current time will be used.
``KCONFIG_SEED``
You can set this to the integer value used to seed the RNG, if you want
to somehow debug the behaviour of the kconfig parser/frontends.
If not set, the current time will be used.
KCONFIG_PROBABILITY
-------------------
This variable can be used to skew the probabilities. This variable can
be unset or empty, or set to three different formats:
``KCONFIG_PROBABILITY``
This variable can be used to skew the probabilities. This variable can
be unset or empty, or set to three different formats:
======================= ================== =====================
KCONFIG_PROBABILITY y:n split y:m:n split
......@@ -159,33 +144,24 @@ Examples::
10% of booleans will be set to 'y', 90% to 'n'
15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
----------------------------------------------------------------------
Environment variables for ``syncconfig``:
Environment variables for 'syncconfig'
``KCONFIG_NOSILENTUPDATE``
If this variable has a non-blank value, it prevents silent kernel
config updates (requires explicit updates).
KCONFIG_NOSILENTUPDATE
----------------------
If this variable has a non-blank value, it prevents silent kernel
config updates (requires explicit updates).
``KCONFIG_AUTOCONFIG``
This environment variable can be set to specify the path & name of the
"auto.conf" file. Its default value is "include/config/auto.conf".
KCONFIG_AUTOCONFIG
------------------
This environment variable can be set to specify the path & name of the
"auto.conf" file. Its default value is "include/config/auto.conf".
``KCONFIG_AUTOHEADER``
This environment variable can be set to specify the path & name of the
"autoconf.h" (header) file.
Its default value is "include/generated/autoconf.h".
KCONFIG_AUTOHEADER
------------------
This environment variable can be set to specify the path & name of the
"autoconf.h" (header) file.
Its default value is "include/generated/autoconf.h".
----------------------------------------------------------------------
menuconfig
----------
SEARCHING for CONFIG symbols
==========
Searching in menuconfig:
......@@ -212,7 +188,7 @@ Searching in menuconfig:
is when the search matches the complete symbol name);
- then, other matches, sorted alphabetically.
For example: ^ATH.K matches:
For example, ^ATH.K matches:
ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
[...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
......@@ -225,36 +201,31 @@ Searching in menuconfig:
directly to that location. You will be returned to the current
search results after exiting this new menu.
----------------------------------------------------------------------
User interface options for 'menuconfig'
User interface options for 'menuconfig':
MENUCONFIG_COLOR
----------------
It is possible to select different color themes using the variable
MENUCONFIG_COLOR. To select a theme use::
``MENUCONFIG_COLOR``
It is possible to select different color themes using the variable
MENUCONFIG_COLOR. To select a theme use::
make MENUCONFIG_COLOR=<theme> menuconfig
Available themes are::
Available themes are::
- mono => selects colors suitable for monochrome displays
- blackbg => selects a color scheme with black background
- classic => theme with blue background. The classic look
- bluetitle => a LCD friendly version of classic. (default)
MENUCONFIG_MODE
---------------
This mode shows all sub-menus in one large tree.
``MENUCONFIG_MODE``
This mode shows all sub-menus in one large tree.
Example::
Example::
make MENUCONFIG_MODE=single_menu menuconfig
----------------------------------------------------------------------
nconfig
-------
=======
nconfig is an alternate text-based configurator. It lists function
keys across the bottom of the terminal (window) that execute commands.
......@@ -281,18 +252,18 @@ Searching in nconfig:
jump directly to that location. You will be returned to the
current search results after exiting this new menu.
NCONFIG_MODE
------------
This mode shows all sub-menus in one large tree.
Environment variables:
``NCONFIG_MODE``
This mode shows all sub-menus in one large tree.
Example::
Example::
make NCONFIG_MODE=single_menu nconfig
----------------------------------------------------------------------
xconfig
-------
=======
Searching in xconfig:
......@@ -315,10 +286,8 @@ Searching in xconfig:
to return to the main menu.
----------------------------------------------------------------------
gconfig
-------
=======
Searching in gconfig:
......
......@@ -39,8 +39,8 @@ __all:
# prepare rule.
this-makefile := $(lastword $(MAKEFILE_LIST))
export abs_srctree := $(realpath $(dir $(this-makefile)))
export abs_objtree := $(CURDIR)
abs_srctree := $(realpath $(dir $(this-makefile)))
abs_objtree := $(CURDIR)
ifneq ($(sub_make_done),1)
......@@ -965,8 +965,15 @@ export CC_FLAGS_CFI
endif
ifneq ($(CONFIG_FUNCTION_ALIGNMENT),0)
# Set the minimal function alignment. Use the newer GCC option
# -fmin-function-alignment if it is available, or fall back to -falign-funtions.
# See also CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT.
ifdef CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT
KBUILD_CFLAGS += -fmin-function-alignment=$(CONFIG_FUNCTION_ALIGNMENT)
else
KBUILD_CFLAGS += -falign-functions=$(CONFIG_FUNCTION_ALIGNMENT)
endif
endif
# arch Makefile may override CC so keep this after arch Makefile is included
NOSTDINC_FLAGS += -nostdinc
......@@ -1384,7 +1391,7 @@ ifneq ($(dtstree),)
PHONY += dtbs dtbs_prepare dtbs_install dtbs_check
dtbs: dtbs_prepare
$(Q)$(MAKE) $(build)=$(dtstree)
$(Q)$(MAKE) $(build)=$(dtstree) need-dtbslist=1
# include/config/kernel.release is actually needed when installing DTBs because
# INSTALL_DTBS_PATH contains $(KERNELRELEASE). However, we do not want to make
......@@ -1402,7 +1409,7 @@ endif
dtbs_check: dtbs
dtbs_install:
$(Q)$(MAKE) $(dtbinst)=$(dtstree) dst=$(INSTALL_DTBS_PATH)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.dtbinst obj=$(dtstree)
ifdef CONFIG_OF_EARLY_FLATTREE
all: dtbs
......@@ -1923,7 +1930,7 @@ clean: $(clean-dirs)
-o -name '*.ko.*' \
-o -name '*.dtb' -o -name '*.dtbo' \
-o -name '*.dtb.S' -o -name '*.dtbo.S' \
-o -name '*.dt.yaml' \
-o -name '*.dt.yaml' -o -name 'dtbs-list' \
-o -name '*.dwo' -o -name '*.lst' \
-o -name '*.su' -o -name '*.mod' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
......
......@@ -1597,4 +1597,16 @@ config FUNCTION_ALIGNMENT
default 4 if FUNCTION_ALIGNMENT_4B
default 0
config CC_HAS_MIN_FUNCTION_ALIGNMENT
# Detect availability of the GCC option -fmin-function-alignment which
# guarantees minimal alignment for all functions, unlike
# -falign-functions which the compiler ignores for cold functions.
def_bool $(cc-option, -fmin-function-alignment=8)
config CC_HAS_SANE_FUNCTION_ALIGNMENT
# Set if the guaranteed alignment with -fmin-function-alignment is
# available or extra care is required in the kernel. Clang provides
# strict alignment always, even with -falign-functions.
def_bool CC_HAS_MIN_FUNCTION_ALIGNMENT || CC_IS_CLANG
endmenu
......@@ -339,6 +339,7 @@ config ALPHA_EV4
bool
depends on ALPHA_JENSEN || (ALPHA_SABLE && !ALPHA_GAMMA) || ALPHA_LYNX || ALPHA_NORITAKE && !ALPHA_PRIMO || ALPHA_MIKASA && !ALPHA_PRIMO || ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P_CH || ALPHA_XL || ALPHA_NONAME || ALPHA_EB66 || ALPHA_EB66P || ALPHA_P2K
default y if !ALPHA_LYNX
default y if !ALPHA_EV5
config ALPHA_LCA
bool
......@@ -366,10 +367,6 @@ config ALPHA_EV5
bool "EV5 CPU(s) (model 5/xxx)?" if ALPHA_LYNX
default y if ALPHA_RX164 || ALPHA_RAWHIDE || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_SABLE && ALPHA_GAMMA || ALPHA_NORITAKE && ALPHA_PRIMO || ALPHA_MIKASA && ALPHA_PRIMO || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR
config ALPHA_EV4
bool
default y if ALPHA_LYNX && !ALPHA_EV5
config ALPHA_CIA
bool
depends on ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_NORITAKE && ALPHA_PRIMO || ALPHA_MIKASA && ALPHA_PRIMO || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR
......@@ -394,16 +391,12 @@ config ALPHA_PRIMO
Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx.
config ALPHA_GAMMA
bool "EV5 CPU(s) (model 5/xxx)?"
depends on ALPHA_SABLE
bool "EV5 CPU(s) (model 5/xxx)?" if ALPHA_SABLE
depends on ALPHA_SABLE || ALPHA_LYNX
default ALPHA_LYNX
help
Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
config ALPHA_GAMMA
bool
depends on ALPHA_LYNX
default y
config ALPHA_T2
bool
depends on ALPHA_SABLE || ALPHA_LYNX
......
......@@ -7,11 +7,13 @@ config HEXAGON
select ARCH_32BIT_OFF_T
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_NO_PREEMPT
select ARCH_WANT_FRAME_POINTERS
select DMA_GLOBAL_POOL
select HAVE_PAGE_SIZE_4KB
select HAVE_PAGE_SIZE_16KB
select HAVE_PAGE_SIZE_64KB
select HAVE_PAGE_SIZE_256KB
select FRAME_POINTER
# Other pending projects/to-do items.
# select HAVE_REGS_AND_STACK_ACCESS_API
# select HAVE_HW_BREAKPOINT if PERF_EVENTS
......@@ -23,6 +25,7 @@ config HEXAGON
select HAVE_PERF_EVENTS
# GENERIC_ALLOCATOR is used by dma_alloc_coherent()
select GENERIC_ALLOCATOR
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK
......@@ -47,9 +50,6 @@ config HEXAGON_PHYS_OFFSET
help
Platforms that don't load the kernel at zero set this.
config FRAME_POINTER
def_bool y
config LOCKDEP_SUPPORT
def_bool y
......@@ -62,12 +62,6 @@ config MMU
config GENERIC_CSUM
def_bool y
#
# Use the generic interrupt handling code in kernel/irq/:
#
config GENERIC_IRQ_PROBE
def_bool y
config GENERIC_HWEIGHT
def_bool y
......
......@@ -238,9 +238,9 @@ config PARISC_HUGE_KERNEL
def_bool y if !MODULES || UBSAN || FTRACE || COMPILE_TEST
config MLONGCALLS
def_bool y if PARISC_HUGE_KERNEL
bool "Enable the -mlong-calls compiler option for big kernels" if !PARISC_HUGE_KERNEL
depends on PA8X00
default PARISC_HUGE_KERNEL
help
If you configure the kernel to include many drivers built-in instead
as modules, the kernel executable may become too big, so that the
......@@ -255,9 +255,9 @@ config MLONGCALLS
Enabling this option will probably slow down your kernel.
config 64BIT
def_bool y if "$(ARCH)" = "parisc64"
bool "64-bit kernel" if "$(ARCH)" = "parisc"
depends on PA8X00
default "$(ARCH)" = "parisc64"
help
Enable this if you want to support 64bit kernel on PA-RISC platform.
......
......@@ -6,7 +6,7 @@ config AS_HAS_ULEB128
menuconfig RUNTIME_KERNEL_TESTING_MENU
bool "arch/riscv/kernel runtime Testing"
def_bool y
default y
help
Enable riscv kernel runtime testing.
......
......@@ -9,7 +9,9 @@ include $(srctree)/lib/vdso/Makefile
# Sanitizer runtimes are unavailable and cannot be linked here.
KASAN_SANITIZE := n
KMSAN_SANITIZE_vclock_gettime.o := n
KMSAN_SANITIZE_vdso32/vclock_gettime.o := n
KMSAN_SANITIZE_vgetcpu.o := n
KMSAN_SANITIZE_vdso32/vgetcpu.o := n
UBSAN_SANITIZE := n
KCSAN_SANITIZE := n
......
......@@ -118,8 +118,8 @@ config KVM_AMD
will be called kvm-amd.
config KVM_AMD_SEV
def_bool y
bool "AMD Secure Encrypted Virtualization (SEV) support"
default y
depends on KVM_AMD && X86_64
depends on CRYPTO_DEV_SP_PSP && !(KVM_AMD=y && CRYPTO_DEV_CCP_DD=m)
help
......
......@@ -4,7 +4,8 @@ ccflags-y += -I $(srctree)/arch/x86/kvm
ccflags-$(CONFIG_KVM_WERROR) += -Werror
ifeq ($(CONFIG_FRAME_POINTER),y)
OBJECT_FILES_NON_STANDARD_vmenter.o := y
OBJECT_FILES_NON_STANDARD_vmx/vmenter.o := y
OBJECT_FILES_NON_STANDARD_svm/vmenter.o := y
endif
include $(srctree)/virt/kvm/Makefile.kvm
......
......@@ -81,7 +81,6 @@ config XEN_PVH
bool "Xen PVH guest support"
depends on XEN && XEN_PVHVM && ACPI
select PVH
def_bool n
help
Support for running as a Xen PVH guest.
......
......@@ -460,7 +460,6 @@ config ACPI_BGRT
config ACPI_REDUCED_HARDWARE_ONLY
bool "Hardware-reduced ACPI support only" if EXPERT
def_bool n
help
This config item changes the way the ACPI code is built. When this
option is selected, the kernel will use a specialized version of
......
......@@ -87,8 +87,8 @@ config INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON
the default value.
config INTEL_IOMMU_PERF_EVENTS
def_bool y
bool "Intel IOMMU performance events"
default y
depends on INTEL_IOMMU && PERF_EVENTS
help
Selecting this option will enable the performance monitoring
......
......@@ -519,7 +519,6 @@ config DM_VERITY
If unsure, say N.
config DM_VERITY_VERIFY_ROOTHASH_SIG
def_bool n
bool "Verity data device root hash signature verification support"
depends on DM_VERITY
select SYSTEM_DATA_VERIFICATION
......
......@@ -99,17 +99,17 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html#index-cold-label-attribute
*
* When -falign-functions=N is in use, we must avoid the cold attribute as
* contemporary versions of GCC drop the alignment for cold functions. Worse,
* GCC can implicitly mark callees of cold functions as cold themselves, so
* it's not sufficient to add __function_aligned here as that will not ensure
* that callees are correctly aligned.
* GCC drops the alignment for cold functions. Worse, GCC can implicitly mark
* callees of cold functions as cold themselves, so it's not sufficient to add
* __function_aligned here as that will not ensure that callees are correctly
* aligned.
*
* See:
*
* https://lore.kernel.org/lkml/Y77%2FqVgvaJidFpYt@FVFF77S0Q05N
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88345#c9
*/
#if !defined(CONFIG_CC_IS_GCC) || (CONFIG_FUNCTION_ALIGNMENT == 0)
#if defined(CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT) || (CONFIG_FUNCTION_ALIGNMENT == 0)
#define __cold __attribute__((__cold__))
#else
#define __cold
......
......@@ -1499,7 +1499,7 @@ config MULTIUSER
config SGETMASK_SYSCALL
bool "sgetmask/ssetmask syscalls support" if EXPERT
def_bool PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH
default PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH
help
sys_sgetmask and sys_ssetmask are obsolete system calls
no longer supported in libc but still enabled by default in some
......
......@@ -362,8 +362,7 @@ config MODPROBE_PATH
userspace can still load modules explicitly).
config TRIM_UNUSED_KSYMS
bool "Trim unused exported kernel symbols" if EXPERT
depends on !COMPILE_TEST
bool "Trim unused exported kernel symbols"
help
The kernel and some modules make many symbols available for
other modules to use via EXPORT_SYMBOL() and variants. Depending
......
......@@ -2127,7 +2127,7 @@ config KCOV_IRQ_AREA_SIZE
menuconfig RUNTIME_TESTING_MENU
bool "Runtime Testing"
def_bool y
default y
if RUNTIME_TESTING_MENU
......
......@@ -583,7 +583,7 @@ config MEMORY_BALLOON
# support for memory balloon compaction
config BALLOON_COMPACTION
bool "Allow for balloon memory compaction/migration"
def_bool y
default y
depends on COMPACTION && MEMORY_BALLOON
help
Memory fragmentation introduced by ballooning might reduce
......@@ -598,7 +598,7 @@ config BALLOON_COMPACTION
# support for memory compaction
config COMPACTION
bool "Allow for memory compaction"
def_bool y
default y
select MIGRATION
depends on MMU
help
......@@ -621,7 +621,6 @@ config COMPACT_UNEVICTABLE_DEFAULT
# support for free page reporting
config PAGE_REPORTING
bool "Free page reporting"
def_bool n
help
Free page reporting allows for the incremental acquisition of
free pages from the buddy allocator for the purpose of reporting
......@@ -633,7 +632,7 @@ config PAGE_REPORTING
#
config MIGRATION
bool "Page migration"
def_bool y
default y
depends on (NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION || CMA) && MMU
help
Allows the migration of the physical location of pages of processes
......
......@@ -13,7 +13,7 @@ config IP_DCCP_CCID2_DEBUG
config IP_DCCP_CCID3
bool "CCID-3 (TCP-Friendly)"
def_bool y if (IP_DCCP = y || IP_DCCP = m)
default IP_DCCP = y || IP_DCCP = m
help
CCID-3 denotes TCP-Friendly Rate Control (TFRC), an equation-based
rate-controlled congestion control mechanism. TFRC is designed to
......
......@@ -100,7 +100,7 @@ rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
-e 's:rust-logo-[0-9a-f]+\.svg:logo.svg:g' \
-e 's:favicon-[0-9a-f]+\.svg:logo.svg:g' \
-e 's:<link rel="alternate icon" type="image/png" href="[/.]+/static\.files/favicon-(16x16|32x32)-[0-9a-f]+\.png">::g' \
-e 's:<a href="srctree/([^"]+)">:<a href="$(abs_srctree)/\1">:g'
-e 's:<a href="srctree/([^"]+)">:<a href="$(realpath $(srctree))/\1">:g'
$(Q)for f in $(rustdoc_output)/static.files/rustdoc-*.css; do \
echo ".logo-container > img { object-fit: contain; }" >> $$f; done
......@@ -414,7 +414,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
rust-analyzer:
$(Q)$(srctree)/scripts/generate_rust_analyzer.py \
--cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-cfgs)' \
$(abs_srctree) $(abs_objtree) \
$(realpath $(srctree)) $(realpath $(objtree)) \
$(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \
$(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json
......
......@@ -113,12 +113,6 @@ endef
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj=
# Usage:
# $(Q)$(MAKE) $(dtbinst)=dir
dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=
# Usage:
......
......@@ -71,6 +71,7 @@ endif
# subdir-builtin and subdir-modorder may contain duplications. Use $(sort ...)
subdir-builtin := $(sort $(filter %/built-in.a, $(real-obj-y)))
subdir-modorder := $(sort $(filter %/modules.order, $(obj-m)))
subdir-dtbslist := $(sort $(filter %/dtbs-list, $(dtb-y)))
targets-for-builtin := $(extra-y)
......@@ -213,7 +214,7 @@ endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file
is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y)
is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(target-stem).o)$(OBJECT_FILES_NON_STANDARD)n),y)
$(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y))
......@@ -388,6 +389,7 @@ $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
# To build objects in subdirs, we need to descend into the directories
$(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ;
$(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;
$(subdir-dtbslist): $(obj)/%/dtbs-list: $(obj)/% ;
#
# Rule to compile a set of .o files into one .a file (without symbol table)
......@@ -404,19 +406,21 @@ $(obj)/built-in.a: $(real-obj-y) FORCE
$(call if_changed,ar_builtin)
#
# Rule to create modules.order file
# Rule to create modules.order and dtbs-list
#
# Create commands to either record .ko file or cat modules.order from
# a subdirectory
# Add $(obj-m) as the prerequisite to avoid updating the timestamp of
# modules.order unless contained modules are updated.
# This is a list of build artifacts (module or dtb) from the current Makefile
# and its sub-directories. The timestamp should be updated when any of the
# member files.
cmd_modules_order = { $(foreach m, $(real-prereqs), \
$(if $(filter %/modules.order, $m), cat $m, echo $m);) :; } \
cmd_gen_order = { $(foreach m, $(real-prereqs), \
$(if $(filter %/$(notdir $@), $m), cat $m, echo $m);) :; } \
> $@
$(obj)/modules.order: $(obj-m) FORCE
$(call if_changed,modules_order)
$(call if_changed,gen_order)
$(obj)/dtbs-list: $(dtb-y) FORCE
$(call if_changed,gen_order)
#
# Rule to compile a set of .o files into one .a file (with symbol table)
......
......@@ -8,32 +8,36 @@
# $INSTALL_PATH/dtbs/$KERNELRELEASE
# ==========================================================================
src := $(obj)
PHONY := __dtbs_install
__dtbs_install:
include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
include $(kbuild-file)
dtbs := $(addprefix $(dst)/, $(dtb-y) $(if $(CONFIG_OF_ALL_DTBS),$(dtb-)))
subdirs := $(addprefix $(obj)/, $(subdir-y) $(subdir-m))
__dtbs_install: $(dtbs) $(subdirs)
@:
dst := $(INSTALL_DTBS_PATH)
quiet_cmd_dtb_install = INSTALL $@
cmd_dtb_install = install -D $< $@
$(dst)/%.dtb: $(obj)/%.dtb
$(dst)/%: $(obj)/%
$(call cmd,dtb_install)
$(dst)/%.dtbo: $(obj)/%.dtbo
$(call cmd,dtb_install)
dtbs := $(patsubst $(obj)/%,%,$(call read-file, $(obj)/dtbs-list))
ifdef CONFIG_ARCH_WANT_FLAT_DTB_INSTALL
PHONY += $(subdirs)
$(subdirs):
$(Q)$(MAKE) $(dtbinst)=$@ dst=$(if $(CONFIG_ARCH_WANT_FLAT_DTB_INSTALL),$(dst),$(patsubst $(obj)/%,$(dst)/%,$@))
define gen_install_rules
$(dst)/%: $(obj)/$(1)%
$$(call cmd,dtb_install)
endef
$(foreach d, $(sort $(dir $(dtbs))), $(eval $(call gen_install_rules,$(d))))
dtbs := $(notdir $(dtbs))
endif # CONFIG_ARCH_WANT_FLAT_DTB_INSTALL
__dtbs_install: $(addprefix $(dst)/, $(dtbs))
@:
.PHONY: $(PHONY)
......@@ -132,6 +132,8 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access)
KBUILD_CFLAGS += $(call cc-disable-warning, cast-function-type-strict)
KBUILD_CFLAGS += -Wno-enum-compare-conditional
KBUILD_CFLAGS += -Wno-enum-enum-conversion
endif
endif
......@@ -185,7 +187,6 @@ KBUILD_CFLAGS += -Wpointer-arith
KBUILD_CFLAGS += -Wredundant-decls
KBUILD_CFLAGS += -Wsign-compare
KBUILD_CFLAGS += -Wswitch-default
KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat)
KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3
......
......@@ -45,6 +45,11 @@ else
obj-y := $(filter-out %/, $(obj-y))
endif
ifdef need-dtbslist
dtb-y += $(addsuffix /dtbs-list, $(subdir-ym))
always-y += dtbs-list
endif
# Expand $(foo-objs) $(foo-y) etc. by replacing their individuals
suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s))))
# List composite targets that are constructed by combining other targets
......@@ -99,6 +104,7 @@ lib-y := $(addprefix $(obj)/,$(lib-y))
real-obj-y := $(addprefix $(obj)/,$(real-obj-y))
real-obj-m := $(addprefix $(obj)/,$(real-obj-m))
multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m))
dtb-y := $(addprefix $(obj)/, $(dtb-y))
multi-dtb-y := $(addprefix $(obj)/, $(multi-dtb-y))
real-dtb-y := $(addprefix $(obj)/, $(real-dtb-y))
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
......@@ -148,7 +154,7 @@ _cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(target-stem).lds)
#
ifeq ($(CONFIG_GCOV_KERNEL),y)
_c_flags += $(if $(patsubst n%,, \
$(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \
$(GCOV_PROFILE_$(target-stem).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \
$(CFLAGS_GCOV))
endif
......@@ -159,32 +165,32 @@ endif
ifeq ($(CONFIG_KASAN),y)
ifneq ($(CONFIG_KASAN_HW_TAGS),y)
_c_flags += $(if $(patsubst n%,, \
$(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \
$(KASAN_SANITIZE_$(target-stem).o)$(KASAN_SANITIZE)y), \
$(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE))
endif
endif
ifeq ($(CONFIG_KMSAN),y)
_c_flags += $(if $(patsubst n%,, \
$(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \
$(KMSAN_SANITIZE_$(target-stem).o)$(KMSAN_SANITIZE)y), \
$(CFLAGS_KMSAN))
_c_flags += $(if $(patsubst n%,, \
$(KMSAN_ENABLE_CHECKS_$(basetarget).o)$(KMSAN_ENABLE_CHECKS)y), \
$(KMSAN_ENABLE_CHECKS_$(target-stem).o)$(KMSAN_ENABLE_CHECKS)y), \
, -mllvm -msan-disable-checks=1)
endif
ifeq ($(CONFIG_UBSAN),y)
_c_flags += $(if $(patsubst n%,, \
$(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)y), \
$(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SANITIZE)y), \
$(CFLAGS_UBSAN))
_c_flags += $(if $(patsubst n%,, \
$(UBSAN_SIGNED_WRAP_$(basetarget).o)$(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SIGNED_WRAP)$(UBSAN_SANITIZE)y), \
$(UBSAN_SIGNED_WRAP_$(target-stem).o)$(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SIGNED_WRAP)$(UBSAN_SANITIZE)y), \
$(CFLAGS_UBSAN_SIGNED_WRAP))
endif
ifeq ($(CONFIG_KCOV),y)
_c_flags += $(if $(patsubst n%,, \
$(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \
$(KCOV_INSTRUMENT_$(target-stem).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \
$(CFLAGS_KCOV))
endif
......@@ -194,12 +200,12 @@ endif
#
ifeq ($(CONFIG_KCSAN),y)
_c_flags += $(if $(patsubst n%,, \
$(KCSAN_SANITIZE_$(basetarget).o)$(KCSAN_SANITIZE)y), \
$(KCSAN_SANITIZE_$(target-stem).o)$(KCSAN_SANITIZE)y), \
$(CFLAGS_KCSAN))
# Some uninstrumented files provide implied barriers required to avoid false
# positives: set KCSAN_INSTRUMENT_BARRIERS for barrier instrumentation only.
_c_flags += $(if $(patsubst n%,, \
$(KCSAN_INSTRUMENT_BARRIERS_$(basetarget).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \
$(KCSAN_INSTRUMENT_BARRIERS_$(target-stem).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \
-D__KCSAN_INSTRUMENT_BARRIERS__)
endif
......@@ -364,7 +370,7 @@ DTC_FLAGS += -Wnode_name_chars_strict \
-Wunique_unit_address
endif
DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
DTC_FLAGS += $(DTC_FLAGS_$(target-stem))
# Set -@ if the target is a base DTB that overlay is applied onto
DTC_FLAGS += $(if $(filter $(patsubst $(obj)/%,%,$@), $(base-dtb-y)), -@)
......
......@@ -135,7 +135,7 @@ snap-pkg:
mkdir $(objtree)/snap
$(MAKE) clean
sed "s@KERNELRELEASE@$(KERNELRELEASE)@; \
s@SRCTREE@$(abs_srctree)@" \
s@SRCTREE@$(realpath $(srctree))@" \
$(srctree)/scripts/package/snapcraft.template > \
$(objtree)/snap/snapcraft.yaml
cd $(objtree)/snap && \
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ARRAY_SIZE_H
#define ARRAY_SIZE_H
/**
* ARRAY_SIZE - get the number of elements in array @arr
* @arr: array to be sized
*/
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif /* ARRAY_SIZE_H */
......@@ -14,6 +14,7 @@
#include <sys/time.h>
#include <errno.h>
#include "internal.h"
#include "lkc.h"
static void conf(struct menu *menu);
......@@ -171,7 +172,7 @@ enum conf_def_mode {
static bool conf_set_all_new_symbols(enum conf_def_mode mode)
{
struct symbol *sym, *csym;
int i, cnt;
int cnt;
/*
* can't go as the default in switch-case below, otherwise gcc whines
* about -Wmaybe-uninitialized
......@@ -226,7 +227,7 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
}
}
for_all_symbols(i, sym) {
for_all_symbols(sym) {
if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
continue;
switch (sym_get_type(sym)) {
......@@ -278,14 +279,14 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
* and the rest to no.
*/
if (mode != def_random) {
for_all_symbols(i, csym) {
for_all_symbols(csym) {
if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
sym_is_choice_value(csym))
csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
}
}
for_all_symbols(i, csym) {
for_all_symbols(csym) {
if (sym_has_value(csym) || !sym_is_choice(csym))
continue;
......@@ -304,9 +305,8 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
static void conf_rewrite_tristates(tristate old_val, tristate new_val)
{
struct symbol *sym;
int i;
for_all_symbols(i, sym) {
for_all_symbols(sym) {
if (sym_get_type(sym) == S_TRISTATE &&
sym->def[S_DEF_USER].tri == old_val)
sym->def[S_DEF_USER].tri = new_val;
......
......@@ -18,8 +18,11 @@
#include <time.h>
#include <unistd.h>
#include "internal.h"
#include "lkc.h"
struct gstr autoconf_cmd;
/* return true if 'path' exists, false otherwise */
static bool is_present(const char *path)
{
......@@ -293,63 +296,12 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
return 0;
}
#define LINE_GROWTH 16
static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
{
size_t new_size = slen + 1;
if (new_size > *n) {
new_size += LINE_GROWTH - 1;
new_size *= 2;
*lineptr = xrealloc(*lineptr, new_size);
*n = new_size;
}
(*lineptr)[slen] = c;
return 0;
}
static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
{
char *line = *lineptr;
size_t slen = 0;
for (;;) {
int c = getc(stream);
switch (c) {
case '\n':
if (add_byte(c, &line, slen, n) < 0)
goto e_out;
slen++;
/* fall through */
case EOF:
if (add_byte('\0', &line, slen, n) < 0)
goto e_out;
*lineptr = line;
if (slen == 0)
return -1;
return slen;
default:
if (add_byte(c, &line, slen, n) < 0)
goto e_out;
slen++;
}
}
e_out:
line[slen-1] = '\0';
*lineptr = line;
return -1;
}
/* like getline(), but the newline character is stripped away */
static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream)
{
ssize_t len;
len = compat_getline(lineptr, n, stream);
len = getline(lineptr, n, stream);
if (len > 0 && (*lineptr)[len - 1] == '\n') {
len--;
......@@ -371,7 +323,7 @@ int conf_read_simple(const char *name, int def)
size_t line_asize = 0;
char *p, *val;
struct symbol *sym;
int i, def_flags;
int def_flags;
const char *warn_unknown, *sym_name;
warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS");
......@@ -429,7 +381,7 @@ int conf_read_simple(const char *name, int def)
conf_warnings = 0;
def_flags = SYMBOL_DEF << def;
for_all_symbols(i, sym) {
for_all_symbols(sym) {
sym->flags |= SYMBOL_CHANGED;
sym->flags &= ~(def_flags|SYMBOL_VALID);
if (sym_is_choice(sym))
......@@ -538,7 +490,6 @@ int conf_read(const char *name)
{
struct symbol *sym;
int conf_unsaved = 0;
int i;
conf_set_changed(false);
......@@ -549,7 +500,7 @@ int conf_read(const char *name)
sym_calc_value(modules_sym);
for_all_symbols(i, sym) {
for_all_symbols(sym) {
sym_calc_value(sym);
if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
continue;
......@@ -573,7 +524,7 @@ int conf_read(const char *name)
/* maybe print value in verbose mode... */
}
for_all_symbols(i, sym) {
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
......@@ -848,10 +799,7 @@ int conf_write_defconfig(const char *filename)
while (menu != NULL)
{
sym = menu->sym;
if (sym == NULL) {
if (!menu_is_visible(menu))
goto next_menu;
} else if (!sym_is_choice(sym)) {
if (sym && !sym_is_choice(sym)) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE))
goto next_menu;
......@@ -911,7 +859,6 @@ int conf_write(const char *name)
const char *str;
char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
char *env;
int i;
bool need_newline = false;
if (!name)
......@@ -995,7 +942,7 @@ int conf_write(const char *name)
}
fclose(out);
for_all_symbols(i, sym)
for_all_symbols(sym)
sym->flags &= ~SYMBOL_WRITTEN;
if (*tmpname) {
......@@ -1023,7 +970,6 @@ int conf_write(const char *name)
static int conf_write_autoconf_cmd(const char *autoconf_name)
{
char name[PATH_MAX], tmp[PATH_MAX];
struct file *file;
FILE *out;
int ret;
......@@ -1044,15 +990,9 @@ static int conf_write_autoconf_cmd(const char *autoconf_name)
return -1;
}
fprintf(out, "deps_config := \\\n");
for (file = file_list; file; file = file->next)
fprintf(out, "\t%s \\\n", file->name);
fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
fprintf(out, "autoconfig := %s\n", autoconf_name);
env_write_dep(out, autoconf_name);
fprintf(out, "\n$(deps_config): ;\n");
fputs(str_get(&autoconf_cmd), out);
fflush(out);
ret = ferror(out); /* error check for all fprintf() calls */
......@@ -1072,7 +1012,7 @@ static int conf_touch_deps(void)
{
const char *name, *tmp;
struct symbol *sym;
int res, i;
int res;
name = conf_get_autoconfig_name();
tmp = strrchr(name, '/');
......@@ -1086,7 +1026,7 @@ static int conf_touch_deps(void)
conf_read_simple(name, S_DEF_AUTO);
sym_calc_value(modules_sym);
for_all_symbols(i, sym) {
for_all_symbols(sym) {
sym_calc_value(sym);
if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
continue;
......@@ -1152,7 +1092,7 @@ static int __conf_write_autoconf(const char *filename,
char tmp[PATH_MAX];
FILE *file;
struct symbol *sym;
int ret, i;
int ret;
if (make_parent_dir(filename))
return -1;
......@@ -1169,7 +1109,7 @@ static int __conf_write_autoconf(const char *filename,
conf_write_heading(file, comment_style);
for_all_symbols(i, sym)
for_all_symbols(sym)
if ((sym->flags & SYMBOL_WRITE) && sym->name)
print_symbol(file, sym);
......@@ -1192,7 +1132,7 @@ int conf_write_autoconf(int overwrite)
{
struct symbol *sym;
const char *autoconf_name = conf_get_autoconfig_name();
int ret, i;
int ret;
if (!overwrite && is_present(autoconf_name))
return 0;
......@@ -1204,7 +1144,7 @@ int conf_write_autoconf(int overwrite)
if (conf_touch_deps())
return 1;
for_all_symbols(i, sym)
for_all_symbols(sym)
sym_calc_value(sym);
ret = __conf_write_autoconf(conf_get_autoheader_name(),
......
......@@ -12,17 +12,12 @@ extern "C" {
#include <assert.h>
#include <stdio.h>
#include "list.h"
#include "list_types.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
struct file {
struct file *next;
struct file *parent;
const char *name;
int lineno;
};
#include "list_types.h"
typedef enum tristate {
no, mod, yes
......@@ -81,8 +76,8 @@ enum {
* SYMBOL_CHOICE bit set in 'flags'.
*/
struct symbol {
/* The next symbol in the same bucket in the symbol hash table */
struct symbol *next;
/* link node for the hash table */
struct hlist_node node;
/* The name of the symbol, e.g. "FOO" for 'config FOO' */
char *name;
......@@ -113,6 +108,9 @@ struct symbol {
*/
tristate visible;
/* config entries associated with this symbol */
struct list_head menus;
/* SYMBOL_* flags */
int flags;
......@@ -131,8 +129,6 @@ struct symbol {
struct expr_value implied;
};
#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next)
#define SYMBOL_CONST 0x0001 /* symbol is const */
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
......@@ -157,7 +153,6 @@ struct symbol {
#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
#define SYMBOL_MAXLENGTH 256
#define SYMBOL_HASHSIZE 9973
/* A property represent the config options that can be associated
* with a config "symbol".
......@@ -195,7 +190,7 @@ struct property {
struct menu *menu; /* the menu the property are associated with
* valid for: P_SELECT, P_RANGE, P_CHOICE,
* P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
struct file *file; /* what file was this property defined */
const char *filename; /* what file was this property defined */
int lineno; /* what lineno was this property defined */
};
......@@ -230,6 +225,8 @@ struct menu {
*/
struct symbol *sym;
struct list_head link; /* link to symbol::menus */
/*
* 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
......@@ -256,7 +253,7 @@ struct menu {
char *help;
/* The location where the menu node appears in the Kconfig files */
struct file *file;
const char *filename;
int lineno;
/* For use by front ends that need to store auxiliary data */
......@@ -277,10 +274,6 @@ struct jump_key {
struct menu *target;
};
extern struct file *file_list;
extern struct file *current_file;
struct file *lookup_file(const char *name);
extern struct symbol symbol_yes, symbol_no, symbol_mod;
extern struct symbol *modules_sym;
extern int cdebug;
......
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include "array_size.h"
#include "list.h"
#define HASH_SIZE(name) (ARRAY_SIZE(name))
#define HASHTABLE_DECLARE(name, size) struct hlist_head name[size]
#define HASHTABLE_DEFINE(name, size) \
HASHTABLE_DECLARE(name, size) = \
{ [0 ... ((size) - 1)] = HLIST_HEAD_INIT }
#define hash_head(table, key) (&(table)[(key) % HASH_SIZE(table)])
/**
* hash_add - add an object to a hashtable
* @table: hashtable to add to
* @node: the &struct hlist_node of the object to be added
* @key: the key of the object to be added
*/
#define hash_add(table, node, key) \
hlist_add_head(node, hash_head(table, key))
/**
* hash_for_each - iterate over a hashtable
* @table: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
*/
#define hash_for_each(table, obj, member) \
for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \
hlist_for_each_entry(obj, &table[_bkt], member)
/**
* hash_for_each_possible - iterate over all possible objects hashing to the
* same bucket
* @table: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
* @key: the key of the objects to iterate over
*/
#define hash_for_each_possible(table, obj, member, key) \
hlist_for_each_entry(obj, hash_head(table, key), member)
#endif /* HASHTABLE_H */
......@@ -2,8 +2,20 @@
#ifndef INTERNAL_H
#define INTERNAL_H
#include "hashtable.h"
#define SYMBOL_HASHSIZE (1U << 14)
extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE);
#define for_all_symbols(sym) \
hash_for_each(sym_hashtable, sym, node)
struct menu;
extern struct menu *current_menu, *current_entry;
extern const char *cur_filename;
extern int cur_lineno;
#endif /* INTERNAL_H */
......@@ -14,16 +14,22 @@
#include <string.h>
#include "lkc.h"
#include "preprocess.h"
#include "parser.tab.h"
#define YY_DECL static int yylex1(void)
#define START_STRSIZE 16
static struct {
struct file *file;
int lineno;
} current_pos;
/* The Kconfig file currently being parsed. */
const char *cur_filename;
/*
* The line number of the current statement. This does not match yylineno.
* yylineno is used by the lexer, while cur_lineno is used by the parser.
*/
int cur_lineno;
static int prev_prev_token = T_EOL;
static int prev_token = T_EOL;
......@@ -33,6 +39,9 @@ static int text_size, text_asize;
struct buffer {
struct buffer *parent;
YY_BUFFER_STATE state;
int yylineno;
const char *filename;
int source_lineno;
};
static struct buffer *current_buf;
......@@ -77,7 +86,7 @@ static void warn_ignored_character(char chr)
{
fprintf(stderr,
"%s:%d:warning: ignoring unsupported character '%c'\n",
current_file->name, yylineno, chr);
cur_filename, yylineno, chr);
}
%}
......@@ -180,7 +189,7 @@ n [A-Za-z0-9_-]
\n {
fprintf(stderr,
"%s:%d:warning: multi-line strings not supported\n",
zconf_curname(), zconf_lineno());
cur_filename, cur_lineno);
unput('\n');
BEGIN(INITIAL);
yylval.string = text;
......@@ -246,9 +255,9 @@ n [A-Za-z0-9_-]
if (prev_token != T_EOL && prev_token != T_HELPTEXT)
fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
current_file->name, yylineno);
cur_filename, yylineno);
if (current_file) {
if (current_buf) {
zconf_endfile();
return T_EOL;
}
......@@ -267,19 +276,17 @@ repeat:
token = yylex1();
if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
if (token == T_EOL) {
if (token == T_EOL)
/* Do not pass unneeded T_EOL to the parser. */
goto repeat;
} else {
else
/*
* For the parser, update file/lineno at the first token
* For the parser, update lineno at the first token
* of each statement. Generally, \n is a statement
* terminator in Kconfig, but it is not always true
* because \n could be escaped by a backslash.
*/
current_pos.file = current_file;
current_pos.lineno = yylineno;
}
cur_lineno = yylineno;
}
if (prev_prev_token == T_EOL && prev_token == T_WORD &&
......@@ -302,8 +309,11 @@ static char *expand_token(const char *in, size_t n)
new_string();
append_string(in, n);
/* get the whole line because we do not know the end of token. */
while ((c = input()) != EOF) {
/*
* get the whole line because we do not know the end of token.
* input() returns 0 (not EOF!) when it reachs the end of file.
*/
while ((c = input()) != 0) {
if (c == '\n') {
unput(c);
break;
......@@ -391,78 +401,60 @@ void zconf_initscan(const char *name)
exit(1);
}
current_buf = xmalloc(sizeof(*current_buf));
memset(current_buf, 0, sizeof(*current_buf));
current_file = file_lookup(name);
cur_filename = file_lookup(name);
yylineno = 1;
}
void zconf_nextfile(const char *name)
{
struct file *iter;
struct file *file = file_lookup(name);
struct buffer *buf = xmalloc(sizeof(*buf));
memset(buf, 0, sizeof(*buf));
bool recur_include = false;
current_buf->state = YY_CURRENT_BUFFER;
yyin = zconf_fopen(file->name);
buf->state = YY_CURRENT_BUFFER;
buf->yylineno = yylineno;
buf->filename = cur_filename;
buf->source_lineno = cur_lineno;
buf->parent = current_buf;
current_buf = buf;
yyin = zconf_fopen(name);
if (!yyin) {
fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
zconf_curname(), zconf_lineno(), file->name);
cur_filename, cur_lineno, name);
exit(1);
}
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
buf->parent = current_buf;
current_buf = buf;
current_file->lineno = yylineno;
file->parent = current_file;
for (buf = current_buf; buf; buf = buf->parent) {
if (!strcmp(buf->filename, name))
recur_include = true;
}
for (iter = current_file; iter; iter = iter->parent) {
if (!strcmp(iter->name, file->name)) {
if (recur_include) {
fprintf(stderr,
"Recursive inclusion detected.\n"
"Inclusion path:\n"
" current file : %s\n", file->name);
iter = file;
do {
iter = iter->parent;
" current file : %s\n", name);
for (buf = current_buf; buf; buf = buf->parent)
fprintf(stderr, " included from: %s:%d\n",
iter->name, iter->lineno - 1);
} while (strcmp(iter->name, file->name));
buf->filename, buf->source_lineno);
exit(1);
}
}
yylineno = 1;
current_file = file;
cur_filename = file_lookup(name);
}
static void zconf_endfile(void)
{
struct buffer *parent;
current_file = current_file->parent;
if (current_file)
yylineno = current_file->lineno;
struct buffer *tmp;
parent = current_buf->parent;
if (parent) {
fclose(yyin);
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(parent->state);
}
free(current_buf);
current_buf = parent;
}
int zconf_lineno(void)
{
return current_pos.lineno;
}
const char *zconf_curname(void)
{
return current_pos.file ? current_pos.file->name : "<none>";
yy_switch_to_buffer(current_buf->state);
yylineno = current_buf->yylineno;
cur_filename = current_buf->filename;
tmp = current_buf;
current_buf = current_buf->parent;
free(tmp);
}
......@@ -2,12 +2,12 @@
#ifndef LIST_H
#define LIST_H
/*
* Copied from include/linux/...
*/
#include <stddef.h>
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#include "list_types.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
......@@ -17,14 +17,24 @@
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(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))); })
struct list_head {
struct list_head *next, *prev;
};
#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.
*/
#define LIST_HEAD_INIT(name) { &(name), &(name) }
......@@ -32,45 +42,16 @@ struct list_head {
struct list_head name = LIST_HEAD_INIT(name)
/**
* 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_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_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*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_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
* 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 int list_empty(const struct list_head *head)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
return head->next == head;
list->next = list;
list->prev = list;
}
/*
......@@ -79,14 +60,27 @@ static inline int list_empty(const struct list_head *head)
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *_new,
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;
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);
}
/**
......@@ -97,9 +91,9 @@ static inline void __list_add(struct list_head *_new,
* 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)
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(_new, head->prev, head);
__list_add(new, head->prev, head);
}
/*
......@@ -115,8 +109,11 @@ static inline void __list_del(struct list_head *prev, struct list_head *next)
prev->next = next;
}
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
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.
......@@ -125,8 +122,135 @@ static inline void __list_del(struct list_head *prev, struct list_head *next)
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (struct list_head*)LIST_POISON1;
entry->prev = (struct list_head*)LIST_POISON2;
__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;
}
#endif
/**
* 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))
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/
#define HLIST_HEAD_INIT { .first = NULL }
/**
* hlist_add_head - add a new entry at the beginning of the hlist
* @n: new entry to be added
* @h: hlist head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
#define hlist_entry_safe(ptr, type, member) \
({ typeof(ptr) ____ptr = (ptr); \
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
})
/**
* hlist_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 hlist_node within the struct.
*/
#define hlist_for_each_entry(pos, head, member) \
for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
pos; \
pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
#endif /* LIST_H */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef LIST_TYPES_H
#define LIST_TYPES_H
struct list_head {
struct list_head *next, *prev;
};
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#endif /* LIST_TYPES_H */
......@@ -36,10 +36,9 @@ void zconf_starthelp(void);
FILE *zconf_fopen(const char *name);
void zconf_initscan(const char *name);
void zconf_nextfile(const char *name);
int zconf_lineno(void);
const char *zconf_curname(void);
/* confdata.c */
extern struct gstr autoconf_cmd;
const char *conf_get_configname(void);
void set_all_choice_values(struct symbol *csym);
......@@ -53,7 +52,8 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
}
/* util.c */
struct file *file_lookup(const char *name);
unsigned int strhash(const char *s);
const char *file_lookup(const char *name);
void *xmalloc(size_t size);
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *p, size_t size);
......
......@@ -18,8 +18,6 @@ void conf_set_message_callback(void (*fn)(const char *s));
bool conf_errors(void);
/* symbol.c */
extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
struct symbol * sym_lookup(const char *name, int flags);
struct symbol * sym_find(const char *name);
void print_symbol_for_listconfig(struct symbol *sym);
......@@ -40,19 +38,6 @@ const char * sym_get_string_value(struct symbol *sym);
const char * prop_get_type_name(enum prop_type type);
/* preprocess.c */
enum variable_flavor {
VAR_SIMPLE,
VAR_RECURSIVE,
VAR_APPEND,
};
void env_write_dep(FILE *f, const char *auto_conf_name);
void variable_add(const char *name, const char *value,
enum variable_flavor flavor);
void variable_all_del(void);
char *expand_dollar(const char **str);
char *expand_one_token(const char **str);
/* expr.c */
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);
......
......@@ -188,9 +188,8 @@ int dialog_checklist(const char *title, const char *prompt, int height,
print_buttons(dialog, height, width, 0);
wnoutrefresh(dialog);
wnoutrefresh(list);
doupdate();
wmove(list, choice, check_x + 1);
wrefresh(list);
while (key != KEY_ESC) {
key = wgetch(dialog);
......
......@@ -91,10 +91,6 @@ struct dialog_info {
struct dialog_color button_label_active;
struct dialog_color button_label_inactive;
struct dialog_color inputbox;
struct dialog_color inputbox_border;
struct dialog_color searchbox;
struct dialog_color searchbox_title;
struct dialog_color searchbox_border;
struct dialog_color position_indicator;
struct dialog_color menubox;
struct dialog_color menubox_border;
......
......@@ -29,10 +29,6 @@ static void set_mono_theme(void)
dlg.button_label_active.atr = A_REVERSE;
dlg.button_label_inactive.atr = A_NORMAL;
dlg.inputbox.atr = A_NORMAL;
dlg.inputbox_border.atr = A_NORMAL;
dlg.searchbox.atr = A_NORMAL;
dlg.searchbox_title.atr = A_BOLD;
dlg.searchbox_border.atr = A_NORMAL;
dlg.position_indicator.atr = A_BOLD;
dlg.menubox.atr = A_NORMAL;
dlg.menubox_border.atr = A_NORMAL;
......@@ -69,10 +65,6 @@ static void set_classic_theme(void)
DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
......@@ -101,14 +93,9 @@ static void set_blackbg_theme(void)
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(button_label_inactive, COLOR_WHITE, COLOR_BLACK, false);
DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
......@@ -136,7 +123,6 @@ static void set_bluetitle_theme(void)
DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
......@@ -189,10 +175,6 @@ static void init_dialog_colors(void)
init_one_color(&dlg.button_label_active);
init_one_color(&dlg.button_label_inactive);
init_one_color(&dlg.inputbox);
init_one_color(&dlg.inputbox_border);
init_one_color(&dlg.searchbox);
init_one_color(&dlg.searchbox_title);
init_one_color(&dlg.searchbox_border);
init_one_color(&dlg.position_indicator);
init_one_color(&dlg.menubox);
init_one_color(&dlg.menubox_border);
......
......@@ -19,6 +19,7 @@
#include <signal.h>
#include <unistd.h>
#include "list.h"
#include "lkc.h"
#include "lxdialog/dialog.h"
#include "mnconf-common.h"
......
......@@ -10,20 +10,18 @@
#include "lkc.h"
#include "internal.h"
#include "list.h"
static const char nohelp_text[] = "There is no help available for this option.";
struct menu rootmenu;
static struct menu **last_entry_ptr;
struct file *file_list;
struct file *current_file;
void menu_warn(struct menu *menu, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
......@@ -33,7 +31,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
......@@ -53,14 +51,16 @@ void menu_add_entry(struct symbol *sym)
memset(menu, 0, sizeof(*menu));
menu->sym = sym;
menu->parent = current_menu;
menu->file = current_file;
menu->lineno = zconf_lineno();
menu->filename = cur_filename;
menu->lineno = cur_lineno;
*last_entry_ptr = menu;
last_entry_ptr = &menu->next;
current_entry = menu;
if (sym)
if (sym) {
menu_add_symbol(P_SYMBOL, sym, NULL);
list_add_tail(&menu->link, &sym->menus);
}
}
struct menu *menu_add_menu(void)
......@@ -134,8 +134,8 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
prop = xmalloc(sizeof(*prop));
memset(prop, 0, sizeof(*prop));
prop->type = type;
prop->file = current_file;
prop->lineno = zconf_lineno();
prop->filename = cur_filename;
prop->lineno = cur_lineno;
prop->menu = current_entry;
prop->expr = expr;
prop->visible.expr = dep;
......@@ -307,12 +307,6 @@ void menu_finalize(struct menu *parent)
}
}
}
/* set the type of the remaining choice values */
for (menu = parent->list; menu; menu = menu->next) {
current_entry = menu;
if (menu->sym && menu->sym->type == S_UNKNOWN)
menu_set_type(sym->type);
}
/*
* Use the choice itself as the parent dependency of
......@@ -567,9 +561,6 @@ void menu_finalize(struct menu *parent)
if (sym->type == S_UNKNOWN)
menu_warn(parent, "config symbol defined without type");
if (sym_is_choice(sym) && !parent->prompt)
menu_warn(parent, "choice must have a prompt");
/* Check properties connected to this symbol */
sym_check_prop(sym);
sym->flags |= SYMBOL_WARNED;
......@@ -676,7 +667,7 @@ struct menu *menu_get_parent_menu(struct menu *menu)
static void get_def_str(struct gstr *r, struct menu *menu)
{
str_printf(r, "Defined at %s:%d\n",
menu->file->name, menu->lineno);
menu->filename, menu->lineno);
}
static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
......@@ -777,6 +768,7 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
struct list_head *head)
{
struct property *prop;
struct menu *menu;
if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
......@@ -793,17 +785,17 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
}
/* Print the definitions with prompts before the ones without */
for_all_properties(sym, prop, P_SYMBOL) {
if (prop->menu->prompt) {
get_def_str(r, prop->menu);
get_prompt_str(r, prop->menu->prompt, head);
list_for_each_entry(menu, &sym->menus, link) {
if (menu->prompt) {
get_def_str(r, menu);
get_prompt_str(r, menu->prompt, head);
}
}
for_all_properties(sym, prop, P_SYMBOL) {
if (!prop->menu->prompt) {
get_def_str(r, prop->menu);
get_dep_str(r, prop->menu->dep, " Depends on: ");
list_for_each_entry(menu, &sym->menus, link) {
if (!menu->prompt) {
get_def_str(r, menu);
get_dep_str(r, menu->dep, " Depends on: ");
}
}
......
......@@ -11,6 +11,7 @@
#include <strings.h>
#include <stdlib.h>
#include "list.h"
#include "lkc.h"
#include "mnconf-common.h"
#include "nconf.h"
......
......@@ -13,6 +13,7 @@
#include "lkc.h"
#include "internal.h"
#include "preprocess.h"
#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
......@@ -27,8 +28,6 @@ static void zconf_error(const char *err, ...);
static bool zconf_endtoken(const char *tokenname,
const char *expected_tokenname);
struct symbol *symbol_hash[SYMBOL_HASHSIZE];
struct menu *current_menu, *current_entry;
%}
......@@ -95,12 +94,12 @@ struct menu *current_menu, *current_entry;
%type <expr> if_expr
%type <string> end
%type <menu> if_entry menu_entry choice_entry
%type <string> word_opt assign_val
%type <string> assign_val
%type <flavor> assign_op
%destructor {
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
$$->file->name, $$->lineno);
$$->filename, $$->lineno);
if (current_menu == $$)
menu_end_menu();
} if_entry menu_entry choice_entry
......@@ -143,19 +142,19 @@ config_entry_start: T_CONFIG nonconst_symbol T_EOL
{
$2->flags |= SYMBOL_OPTIONAL;
menu_add_entry($2);
printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name);
printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);
};
config_stmt: config_entry_start config_option_list
{
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
};
menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
{
$2->flags |= SYMBOL_OPTIONAL;
menu_add_entry($2);
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name);
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);
};
menuconfig_stmt: menuconfig_entry_start config_option_list
......@@ -164,7 +163,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list
current_entry->prompt->type = P_MENU;
else
zconfprint("warning: menuconfig statement without prompt");
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
};
config_option_list:
......@@ -177,15 +176,13 @@ config_option_list:
config_option: type prompt_stmt_opt T_EOL
{
menu_set_type($1);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
zconf_curname(), zconf_lineno(),
$1);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
};
config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
{
menu_add_prompt(P_PROMPT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
};
config_option: default expr if_expr T_EOL
......@@ -193,27 +190,26 @@ config_option: default expr if_expr T_EOL
menu_add_expr(P_DEFAULT, $2, $3);
if ($1 != S_UNKNOWN)
menu_set_type($1);
printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
zconf_curname(), zconf_lineno(),
printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno,
$1);
};
config_option: T_SELECT nonconst_symbol if_expr T_EOL
{
menu_add_symbol(P_SELECT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno);
};
config_option: T_IMPLY nonconst_symbol if_expr T_EOL
{
menu_add_symbol(P_IMPLY, $2, $3);
printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno);
};
config_option: T_RANGE symbol symbol if_expr T_EOL
{
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno);
};
config_option: T_MODULES T_EOL
......@@ -226,18 +222,23 @@ config_option: T_MODULES T_EOL
/* choice entry */
choice: T_CHOICE word_opt T_EOL
choice: T_CHOICE T_EOL
{
struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
struct symbol *sym = sym_lookup(NULL, SYMBOL_CHOICE);
sym->flags |= SYMBOL_NO_WRITE;
menu_add_entry(sym);
menu_add_expr(P_CHOICE, NULL, NULL);
free($2);
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
};
choice_entry: choice choice_option_list
{
if (!current_entry->prompt) {
fprintf(stderr, "%s:%d: error: choice must have a prompt\n",
current_entry->filename, current_entry->lineno);
yynerrs++;
}
$$ = menu_add_menu();
};
......@@ -245,7 +246,7 @@ choice_end: end
{
if (zconf_endtoken($1, "choice")) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno);
}
};
......@@ -262,27 +263,25 @@ choice_option_list:
choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
{
menu_add_prompt(P_PROMPT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
};
choice_option: logic_type prompt_stmt_opt T_EOL
{
menu_set_type($1);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
zconf_curname(), zconf_lineno(), $1);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
};
choice_option: T_OPTIONAL T_EOL
{
current_entry->sym->flags |= SYMBOL_OPTIONAL;
printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:optional\n", cur_filename, cur_lineno);
};
choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
{
menu_add_symbol(P_DEFAULT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:default\n",
zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno);
};
type:
......@@ -304,7 +303,7 @@ default:
if_entry: T_IF expr T_EOL
{
printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
menu_add_entry(NULL);
menu_add_dep($2);
$$ = menu_add_menu();
......@@ -314,7 +313,7 @@ if_end: end
{
if (zconf_endtoken($1, "if")) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno);
}
};
......@@ -330,7 +329,7 @@ menu: T_MENU T_WORD_QUOTE T_EOL
{
menu_add_entry(NULL);
menu_add_prompt(P_MENU, $2, NULL);
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);
};
menu_entry: menu menu_option_list
......@@ -342,7 +341,7 @@ menu_end: end
{
if (zconf_endtoken($1, "menu")) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno);
}
};
......@@ -357,7 +356,7 @@ menu_option_list:
source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
{
printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2);
zconf_nextfile($2);
free($2);
};
......@@ -368,7 +367,7 @@ comment: T_COMMENT T_WORD_QUOTE T_EOL
{
menu_add_entry(NULL);
menu_add_prompt(P_COMMENT, $2, NULL);
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);
};
comment_stmt: comment comment_option_list
......@@ -383,7 +382,7 @@ comment_option_list:
help_start: T_HELP T_EOL
{
printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno);
zconf_starthelp();
};
......@@ -408,7 +407,7 @@ help: help_start T_HELPTEXT
depends: T_DEPENDS T_ON expr T_EOL
{
menu_add_dep($3);
printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
};
/* visibility option */
......@@ -455,9 +454,6 @@ symbol: nonconst_symbol
| T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
;
word_opt: /* empty */ { $$ = NULL; }
| T_WORD
/* assignment statement */
assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); }
......@@ -477,8 +473,11 @@ assign_val:
void conf_parse(const char *name)
{
struct symbol *sym;
int i;
struct menu *menu;
autoconf_cmd = str_new();
str_printf(&autoconf_cmd, "\ndeps_config := \\\n");
zconf_initscan(name);
......@@ -488,13 +487,28 @@ void conf_parse(const char *name)
yydebug = 1;
yyparse();
/*
* FIXME:
* cur_filename and cur_lineno are used even after yyparse();
* menu_finalize() calls menu_add_symbol(). This should be fixed.
*/
cur_filename = "<none>";
cur_lineno = 0;
str_printf(&autoconf_cmd,
"\n"
"$(autoconfig): $(deps_config)\n"
"$(deps_config): ;\n");
env_write_dep(&autoconf_cmd);
/* Variables are expanded in the parse phase. We can free them here. */
variable_all_del();
if (yynerrs)
exit(1);
if (!modules_sym)
modules_sym = sym_find( "n" );
modules_sym = &symbol_no;
if (!menu_has_prompt(&rootmenu)) {
current_entry = &rootmenu;
......@@ -502,10 +516,23 @@ void conf_parse(const char *name)
}
menu_finalize(&rootmenu);
for_all_symbols(i, sym) {
if (sym_check_deps(sym))
menu = &rootmenu;
while (menu) {
if (menu->sym && sym_check_deps(menu->sym))
yynerrs++;
if (menu->list) {
menu = menu->list;
continue;
}
while (!menu->next && menu->parent)
menu = menu->parent;
menu = menu->next;
}
if (yynerrs)
exit(1);
conf_set_changed(true);
......@@ -520,11 +547,11 @@ static bool zconf_endtoken(const char *tokenname,
yynerrs++;
return false;
}
if (current_menu->file != current_file) {
if (strcmp(current_menu->filename, cur_filename)) {
zconf_error("'%s' in different file than '%s'",
tokenname, expected_tokenname);
fprintf(stderr, "%s:%d: location of the '%s'\n",
current_menu->file->name, current_menu->lineno,
current_menu->filename, current_menu->lineno,
expected_tokenname);
yynerrs++;
return false;
......@@ -536,7 +563,7 @@ static void zconfprint(const char *err, ...)
{
va_list ap;
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
va_start(ap, err);
vfprintf(stderr, err, ap);
va_end(ap);
......@@ -548,7 +575,7 @@ static void zconf_error(const char *err, ...)
va_list ap;
yynerrs++;
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
va_start(ap, err);
vfprintf(stderr, err, ap);
va_end(ap);
......@@ -557,7 +584,7 @@ static void zconf_error(const char *err, ...)
static void yyerror(const char *err)
{
fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err);
}
static void print_quoted_string(FILE *out, const char *str)
......
......@@ -9,10 +9,11 @@
#include <stdlib.h>
#include <string.h>
#include "array_size.h"
#include "internal.h"
#include "list.h"
#include "lkc.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#include "preprocess.h"
static char *expand_string_with_args(const char *in, int argc, char *argv[]);
static char *expand_string(const char *in);
......@@ -21,7 +22,7 @@ static void __attribute__((noreturn)) pperror(const char *format, ...)
{
va_list ap;
fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
fprintf(stderr, "%s:%d: ", cur_filename, yylineno);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
......@@ -87,14 +88,17 @@ static char *env_expand(const char *name)
return xstrdup(value);
}
void env_write_dep(FILE *f, const char *autoconfig_name)
void env_write_dep(struct gstr *s)
{
struct env *e, *tmp;
list_for_each_entry_safe(e, tmp, &env_list, node) {
fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
fprintf(f, "%s: FORCE\n", autoconfig_name);
fprintf(f, "endif\n");
str_printf(s,
"\n"
"ifneq \"$(%s)\" \"%s\"\n"
"$(autoconfig): FORCE\n"
"endif\n",
e->name, e->value);
env_del(e);
}
}
......@@ -119,7 +123,7 @@ static char *do_error_if(int argc, char *argv[])
static char *do_filename(int argc, char *argv[])
{
return xstrdup(current_file->name);
return xstrdup(cur_filename);
}
static char *do_info(int argc, char *argv[])
......@@ -181,8 +185,7 @@ static char *do_shell(int argc, char *argv[])
static char *do_warning_if(int argc, char *argv[])
{
if (!strcmp(argv[0], "y"))
fprintf(stderr, "%s:%d: %s\n",
current_file->name, yylineno, argv[1]);
fprintf(stderr, "%s:%d: %s\n", cur_filename, yylineno, argv[1]);
return xstrdup("");
}
......
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef PREPROCESS_H
#define PREPROCESS_H
enum variable_flavor {
VAR_SIMPLE,
VAR_RECURSIVE,
VAR_APPEND,
};
struct gstr;
void env_write_dep(struct gstr *gs);
void variable_add(const char *name, const char *value,
enum variable_flavor flavor);
void variable_all_del(void);
char *expand_dollar(const char **str);
char *expand_one_token(const char **str);
#endif /* PREPROCESS_H */
......@@ -1058,7 +1058,7 @@ void ConfigInfoView::menuInfo(void)
stream << "<br><br>";
}
stream << "defined at " << _menu->file->name << ":"
stream << "defined at " << _menu->filename << ":"
<< _menu->lineno << "<br><br>";
}
}
......
......@@ -9,23 +9,27 @@
#include <string.h>
#include <regex.h>
#include "internal.h"
#include "lkc.h"
struct symbol symbol_yes = {
.name = "y",
.curr = { "y", yes },
.menus = LIST_HEAD_INIT(symbol_yes.menus),
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
struct symbol symbol_mod = {
.name = "m",
.curr = { "m", mod },
.menus = LIST_HEAD_INIT(symbol_mod.menus),
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
struct symbol symbol_no = {
.name = "n",
.curr = { "n", no },
.menus = LIST_HEAD_INIT(symbol_no.menus),
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
......@@ -160,9 +164,8 @@ static void sym_set_changed(struct symbol *sym)
static void sym_set_all_changed(void)
{
struct symbol *sym;
int i;
for_all_symbols(i, sym)
for_all_symbols(sym)
sym_set_changed(sym);
}
......@@ -475,9 +478,8 @@ void sym_calc_value(struct symbol *sym)
void sym_clear_all_valid(void)
{
struct symbol *sym;
int i;
for_all_symbols(i, sym)
for_all_symbols(sym)
sym->flags &= ~SYMBOL_VALID;
conf_set_changed(true);
sym_calc_value(modules_sym);
......@@ -803,14 +805,7 @@ bool sym_is_changeable(struct symbol *sym)
return sym->visible > sym->rev_dep.tri;
}
static unsigned strhash(const char *s)
{
/* fnv32 hash */
unsigned hash = 2166136261U;
for (; *s; s++)
hash = (hash ^ *s) * 0x01000193;
return hash;
}
HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE);
struct symbol *sym_lookup(const char *name, int flags)
{
......@@ -826,9 +821,9 @@ struct symbol *sym_lookup(const char *name, int flags)
case 'n': return &symbol_no;
}
}
hash = strhash(name) % SYMBOL_HASHSIZE;
hash = strhash(name);
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
hash_for_each_possible(sym_hashtable, symbol, node, hash) {
if (symbol->name &&
!strcmp(symbol->name, name) &&
(flags ? symbol->flags & flags
......@@ -846,9 +841,9 @@ struct symbol *sym_lookup(const char *name, int flags)
symbol->name = new_name;
symbol->type = S_UNKNOWN;
symbol->flags = flags;
INIT_LIST_HEAD(&symbol->menus);
symbol->next = symbol_hash[hash];
symbol_hash[hash] = symbol;
hash_add(sym_hashtable, &symbol->node, hash);
return symbol;
}
......@@ -868,9 +863,9 @@ struct symbol *sym_find(const char *name)
case 'n': return &symbol_no;
}
}
hash = strhash(name) % SYMBOL_HASHSIZE;
hash = strhash(name);
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
hash_for_each_possible(sym_hashtable, symbol, node, hash) {
if (symbol->name &&
!strcmp(symbol->name, name) &&
!(symbol->flags & SYMBOL_CONST))
......@@ -930,7 +925,7 @@ struct symbol **sym_re_search(const char *pattern)
if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
return NULL;
for_all_symbols(i, sym) {
for_all_symbols(sym) {
if (sym->flags & SYMBOL_CONST || !sym->name)
continue;
if (regexec(&re, sym->name, 1, match, 0))
......@@ -1041,42 +1036,42 @@ static void sym_check_print_recursive(struct symbol *last_sym)
}
if (stack->sym == last_sym)
fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
prop->file->name, prop->lineno);
prop->filename, prop->lineno);
if (sym_is_choice(sym)) {
fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
menu->file->name, menu->lineno,
menu->filename, menu->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (sym_is_choice_value(sym)) {
fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
menu->file->name, menu->lineno,
menu->filename, menu->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr == &sym->dir_dep.expr) {
fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
prop->file->name, prop->lineno,
prop->filename, prop->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr == &sym->rev_dep.expr) {
fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
prop->file->name, prop->lineno,
prop->filename, prop->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr == &sym->implied.expr) {
fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n",
prop->file->name, prop->lineno,
prop->filename, prop->lineno,
sym->name ? sym->name : "<choice>",
next_sym->name ? next_sym->name : "<choice>");
} else if (stack->expr) {
fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
prop->file->name, prop->lineno,
prop->filename, prop->lineno,
sym->name ? sym->name : "<choice>",
prop_get_type_name(prop->type),
next_sym->name ? next_sym->name : "<choice>");
} else {
fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n",
prop->file->name, prop->lineno,
prop->filename, prop->lineno,
sym->name ? sym->name : "<choice>",
prop_get_type_name(prop->type),
next_sym->name ? next_sym->name : "<choice>");
......
choice
prompt "choose A or B"
config A
bool "A"
config B
bool "B"
endchoice
choice
prompt "choose X or Y"
depends on B
config X
bool "X"
config Y
bool "Y"
endchoice
# SPDX-License-Identifier: GPL-2.0-only
"""
Randomize all dependent choices
This is a somewhat tricky case for randconfig; the visibility of one choice is
determined by a member of another choice. Randconfig should be able to generate
all possible patterns.
"""
def test(conf):
expected0 = False
expected1 = False
expected2 = False
for i in range(100):
assert conf.randconfig(seed=i) == 0
if conf.config_matches('expected_config0'):
expected0 = True
elif conf.config_matches('expected_config1'):
expected1 = True
elif conf.config_matches('expected_config2'):
expected2 = True
else:
assert False
if expected0 and expected1 and expected2:
break
assert expected0
assert expected1
assert expected2
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
CONFIG_A=y
# CONFIG_B is not set
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
# CONFIG_A is not set
CONFIG_B=y
CONFIG_X=y
# CONFIG_Y is not set
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
# CONFIG_A is not set
CONFIG_B=y
# CONFIG_X is not set
CONFIG_Y=y
choice
prompt "This is always invisible"
depends on n
config DUMMY
bool "DUMMY"
endchoice
choice
prompt "Choose A or B"
config A
bool "A"
config B
bool "B"
endchoice
config FOO
bool "FOO"
depends on A
choice
prompt "Choose X"
depends on FOO
config X
bool "X"
endchoice
# SPDX-License-Identifier: GPL-2.0-only
"""
Randomize choices with correct dependencies
When shuffling a choice may potentially disrupt certain dependencies, symbol
values must be recalculated.
Related Linux commits:
- c8fb7d7e48d11520ad24808cfce7afb7b9c9f798
"""
def test(conf):
for i in range(20):
assert conf.randconfig(seed=i) == 0
assert (conf.config_matches('expected_config0') or
conf.config_matches('expected_config1') or
conf.config_matches('expected_config2'))
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
CONFIG_A=y
# CONFIG_B is not set
CONFIG_FOO=y
CONFIG_X=y
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
CONFIG_A=y
# CONFIG_B is not set
# CONFIG_FOO is not set
#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
# CONFIG_A is not set
CONFIG_B=y
......@@ -154,12 +154,10 @@ class Conf:
defconfig_path = os.path.join(self._test_dir, defconfig)
return self._run_conf('--defconfig={}'.format(defconfig_path))
def _allconfig(self, mode, all_config):
def _allconfig(self, mode, all_config, extra_env={}):
if all_config:
all_config_path = os.path.join(self._test_dir, all_config)
extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
else:
extra_env = {}
extra_env['KCONFIG_ALLCONFIG'] = all_config_path
return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
......@@ -195,13 +193,19 @@ class Conf:
"""
return self._allconfig('alldef', all_config)
def randconfig(self, all_config=None):
def randconfig(self, all_config=None, seed=None):
"""Run randconfig.
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
seed: the seed for randconfig (optional)
returncode: exit status of the Kconfig executable
"""
return self._allconfig('rand', all_config)
if seed is not None:
extra_env = {'KCONFIG_SEED': hex(seed)}
else:
extra_env = {}
return self._allconfig('rand', all_config, extra_env=extra_env)
def savedefconfig(self, dot_config):
"""Run savedefconfig.
......
Kconfig:11:error: recursive dependency detected!
Kconfig:11: symbol B is selected by B
Kconfig:5:error: recursive dependency detected!
Kconfig:5: symbol A depends on A
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:5:error: recursive dependency detected!
Kconfig:5: symbol A depends on A
Kconfig:11:error: recursive dependency detected!
Kconfig:11: symbol B is selected by B
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
......@@ -14,9 +14,9 @@ Kconfig:21: symbol C2 depends on C1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:32:error: recursive dependency detected!
Kconfig:32: symbol D2 is selected by D1
Kconfig:27:error: recursive dependency detected!
Kconfig:27: symbol D1 depends on D2
Kconfig:32: symbol D2 is selected by D1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
......@@ -26,13 +26,13 @@ Kconfig:42: symbol E2 is implied by E1
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
Kconfig:49:error: recursive dependency detected!
Kconfig:49: symbol F1 default value contains F2
Kconfig:51: symbol F2 depends on F1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
Kconfig:51:error: recursive dependency detected!
Kconfig:51: symbol F2 depends on F1
Kconfig:49: symbol F1 default value contains F2
Kconfig:60:error: recursive dependency detected!
Kconfig:60: symbol G depends on G
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
......@@ -7,25 +7,50 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "hashtable.h"
#include "lkc.h"
unsigned int strhash(const char *s)
{
/* fnv32 hash */
unsigned int hash = 2166136261U;
for (; *s; s++)
hash = (hash ^ *s) * 0x01000193;
return hash;
}
/* hash table of all parsed Kconfig files */
static HASHTABLE_DEFINE(file_hashtable, 1U << 11);
struct file {
struct hlist_node node;
char name[];
};
/* file already present in list? If not add it */
struct file *file_lookup(const char *name)
const char *file_lookup(const char *name)
{
struct file *file;
size_t len;
int hash = strhash(name);
for (file = file_list; file; file = file->next) {
if (!strcmp(name, file->name)) {
return file;
}
}
hash_for_each_possible(file_hashtable, file, node, hash)
if (!strcmp(name, file->name))
return file->name;
file = xmalloc(sizeof(*file));
len = strlen(name);
file = xmalloc(sizeof(*file) + len + 1);
memset(file, 0, sizeof(*file));
file->name = xstrdup(name);
file->next = file_list;
file_list = file;
return file;
memcpy(file->name, name, len);
file->name[len] = '\0';
hash_add(file_hashtable, &file->node, hash);
str_printf(&autoconf_cmd, "\t%s \\\n", name);
return file->name;
}
/* Allocate initial growable string */
......
......@@ -1050,7 +1050,9 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
sec_mismatch_count++;
warn("%s: section mismatch in reference: %s+0x%x (section: %s) -> %s (section: %s)\n",
modname, fromsym, (unsigned int)(faddr - from->st_value), fromsec, tosym, tosec);
modname, fromsym,
(unsigned int)(faddr - (from ? from->st_value : 0)),
fromsec, tosym, tosec);
if (mismatch->mismatch == EXTABLE_TO_NON_TEXT) {
if (match(tosec, mismatch->bad_tosec))
......
......@@ -24,24 +24,10 @@ if_enabled_echo() {
fi
}
create_package() {
export DH_OPTIONS="-p${1}"
dh_installdocs
dh_installchangelogs
dh_compress
dh_fixperms
dh_gencontrol
dh_md5sums
dh_builddeb -- ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS}
}
install_linux_image () {
pname=$1
pdir=debian/$1
rm -rf ${pdir}
# Only some architectures with OF support have this target
if is_enabled CONFIG_OF_EARLY_FLATTREE && [ -d "${srctree}/arch/${SRCARCH}/boot/dts" ]; then
${MAKE} -f ${srctree}/Makefile INSTALL_DTBS_PATH="${pdir}/usr/lib/linux-image-${KERNELRELEASE}" dtbs_install
......@@ -109,8 +95,6 @@ install_linux_image () {
install_linux_image_dbg () {
pdir=debian/$1
rm -rf ${pdir}
# Parse modules.order directly because 'make modules_install' may sign,
# compress modules, and then run unneeded depmod.
while read -r mod; do
......@@ -140,8 +124,6 @@ install_kernel_headers () {
pdir=debian/$1
version=${1#linux-headers-}
rm -rf $pdir
"${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
mkdir -p $pdir/lib/modules/$version/
......@@ -151,8 +133,6 @@ install_kernel_headers () {
install_libc_headers () {
pdir=debian/$1
rm -rf $pdir
$MAKE -f $srctree/Makefile headers_install INSTALL_HDR_PATH=$pdir/usr
# move asm headers to /usr/include/<libc-machine>/asm to match the structure
......@@ -161,21 +141,15 @@ install_libc_headers () {
mv "$pdir/usr/include/asm" "$pdir/usr/include/${DEB_HOST_MULTIARCH}"
}
rm -f debian/files
package=$1
packages_enabled=$(dh_listpackages)
for package in ${packages_enabled}
do
case ${package} in
*-dbg)
case "${package}" in
*-dbg)
install_linux_image_dbg "${package}";;
linux-image-*|user-mode-linux-*)
linux-image-*|user-mode-linux-*)
install_linux_image "${package}";;
linux-libc-dev)
linux-libc-dev)
install_libc_headers "${package}";;
linux-headers-*)
linux-headers-*)
install_kernel_headers "${package}";;
esac
create_package "${package}"
done
esac
......@@ -11,28 +11,73 @@ ifneq (,$(filter-out parallel=1,$(filter parallel=%,$(DEB_BUILD_OPTIONS))))
MAKEFLAGS += -j$(NUMJOBS)
endif
# When KBUILD_VERBOSE is undefined (presumably you are directly working with
# the debianized tree), show verbose logs unless DEB_BUILD_OPTION=terse is set.
ifeq ($(origin KBUILD_VERBOSE),undefined)
ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS)))
export KBUILD_VERBOSE := 1
else
Q := @
endif
endif
revision = $(lastword $(subst -, ,$(shell dpkg-parsechangelog -S Version)))
CROSS_COMPILE ?= $(filter-out $(DEB_BUILD_GNU_TYPE)-, $(DEB_HOST_GNU_TYPE)-)
make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) KBUILD_BUILD_VERSION=$(revision) $(addprefix CROSS_COMPILE=,$(CROSS_COMPILE))
binary-targets := $(addprefix binary-, image image-dbg headers libc-dev)
all-packages = $(shell dh_listpackages)
image-package = $(filter linux-image-% user-%, $(filter-out %-dbg, $(all-packages)))
image-dbg-package = $(filter %-dbg, $(all-packages))
libc-dev-package = $(filter linux-libc-dev, $(all-packages))
headers-package = $(filter linux-headers-%, $(all-packages))
mk-files = $(patsubst binary-%,debian/%.files,$1)
package = $($(@:binary-%=%-package))
# DH_OPTION is an environment variable common for all debhelper commands.
# We could 'export' it, but here it is passed from the command line to clarify
# which package is being processed in the build log.
DH_OPTIONS = -p$(package)
define binary
$(Q)dh_testdir $(DH_OPTIONS)
$(Q)dh_testroot $(DH_OPTIONS)
$(Q)dh_prep $(DH_OPTIONS)
$(Q)+$(MAKE) $(make-opts) run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb $(package)'
$(Q)dh_installdocs $(DH_OPTIONS)
$(Q)dh_installchangelogs $(DH_OPTIONS)
$(Q)dh_compress $(DH_OPTIONS)
$(Q)dh_fixperms $(DH_OPTIONS)
$(Q)dh_gencontrol $(DH_OPTIONS) -- -f$(call mk-files,$@)
$(Q)dh_md5sums $(DH_OPTIONS)
$(Q)dh_builddeb $(DH_OPTIONS) -- $(addprefix -Z,$(KDEB_COMPRESS))
endef
.PHONY: $(binary-targets)
$(binary-targets): build-arch
$(Q)truncate -s0 $(call mk-files,$@)
$(if $(package),$(binary))
.PHONY: binary binary-indep binary-arch
binary: binary-arch binary-indep
binary-indep: build-indep
binary-arch: build-arch
$(MAKE) $(make-opts) \
run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb'
binary-arch: $(binary-targets)
$(Q)cat $(call mk-files,$^) > debian/files
.PHONY: build build-indep build-arch
build: build-arch build-indep
build-indep:
build-arch:
$(MAKE) $(make-opts) olddefconfig
$(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) all
$(Q)$(MAKE) $(make-opts) olddefconfig
$(Q)$(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) all
.PHONY: clean
clean:
rm -rf debian/files debian/linux-* debian/deb-env.vars*
$(MAKE) ARCH=$(ARCH) clean
$(Q)dh_clean
$(Q)rm -rf debian/deb-env.vars* debian/*.files
$(Q)$(MAKE) ARCH=$(ARCH) clean
# If DEB_HOST_ARCH is empty, it is likely that debian/rules was executed
# directly. Run 'dpkg-architecture --print-set --print-format=make' to
......@@ -41,6 +86,6 @@ ifndef DEB_HOST_ARCH
include debian/deb-env.vars
debian/deb-env.vars:
dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp
mv $@.tmp $@
$(Q)dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp
$(Q)mv $@.tmp $@
endif
......@@ -61,11 +61,37 @@ cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEAS
%{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install
cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE}
cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config
if %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='test -d ${srctree}/arch/${SRCARCH}/boot/dts' 2>/dev/null; then
%{make} %{makeflags} INSTALL_DTBS_PATH=%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb dtbs_install
fi
ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build
%if %{with_devel}
%{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}'
%endif
{
for x in System.map config kernel modules.builtin \
modules.builtin.modinfo modules.order vmlinuz; do
echo "/lib/modules/%{KERNELRELEASE}/${x}"
done
for x in alias alias.bin builtin.alias.bin builtin.bin dep dep.bin \
devname softdep symbols symbols.bin; do
echo "%ghost /lib/modules/%{KERNELRELEASE}/modules.${x}"
done
for x in System.map config vmlinuz; do
echo "%ghost /boot/${x}-%{KERNELRELEASE}"
done
if [ -d "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" ];then
echo "/lib/modules/%{KERNELRELEASE}/dtb"
find "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" -printf "%%%ghost /boot/dtb-%{KERNELRELEASE}/%%P\n"
fi
echo "%exclude /lib/modules/%{KERNELRELEASE}/build"
} > %{buildroot}/kernel.list
%clean
rm -rf %{buildroot}
......@@ -78,23 +104,23 @@ for file in vmlinuz System.map config; do
cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"
fi
done
if [ -d "/lib/modules/%{KERNELRELEASE}/dtb" ] && \
! diff -rq "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}" >/dev/null 2>&1; then
rm -rf "/boot/dtb-%{KERNELRELEASE}"
cp -r "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}"
fi
if [ ! -e "/lib/modules/%{KERNELRELEASE}/modules.dep" ]; then
/usr/sbin/depmod %{KERNELRELEASE}
fi
%preun
if [ -x /sbin/new-kernel-pkg ]; then
new-kernel-pkg --remove %{KERNELRELEASE} --rminitrd --initrdfile=/boot/initramfs-%{KERNELRELEASE}.img
elif [ -x /usr/bin/kernel-install ]; then
if [ -x /usr/bin/kernel-install ]; then
kernel-install remove %{KERNELRELEASE}
fi
%postun
if [ -x /sbin/update-bootloader ]; then
/sbin/update-bootloader --remove %{KERNELRELEASE}
fi
%files
%files -f %{buildroot}/kernel.list
%defattr (-, root, root)
/lib/modules/%{KERNELRELEASE}
%exclude /lib/modules/%{KERNELRELEASE}/build
%exclude /kernel.list
%files headers
%defattr (-, root, root)
......
......@@ -2,7 +2,7 @@
# Most of this file is copied from tools/lib/traceevent/Makefile
RM ?= rm
srctree = $(abs_srctree)
srctree := $(realpath $(srctree))
VERSION_SCRIPT := libbpf.map
LIBBPF_VERSION := $(shell \
......
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