├── .gitignore ├── LICENSE ├── Makefile.am ├── Makefile.sample ├── README.md ├── SECURITY.md ├── configure.ac ├── example ├── Kconfig ├── Makefile ├── README.example.md ├── arch │ ├── Kbuild │ ├── arm │ │ ├── Kconfig │ │ ├── Makefile │ │ └── include │ │ │ └── asm │ │ │ └── arch.h │ └── x86_64 │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── arch.c │ │ └── include │ │ └── asm │ │ └── arch.h ├── kbuild │ ├── Makefile.arch │ ├── Makefile.cflags │ ├── Makefile.head │ ├── Makefile.kconfig │ ├── Makefile.main │ ├── Makefile.prepare │ └── link-kernel-exec.sh ├── kernel │ ├── Kconfig │ ├── Makefile │ ├── include │ │ └── kernel │ │ │ └── optimization.h │ ├── main.c │ ├── opt0.c │ ├── opt1.c │ └── opt2.c └── tools │ └── Kconfig ├── fixdep ├── .gitignore ├── Makefile └── fixdep.c ├── kbuild-standalone.pc.in ├── kbuild ├── Makefile.env ├── Makefile.head ├── Makefile.include ├── Makefile.main ├── Makefile.output ├── _fixdep └── scripts │ ├── Kbuild.include │ ├── Makefile.build │ ├── Makefile.clean │ ├── Makefile.compiler │ ├── Makefile.host │ ├── Makefile.lib │ └── Makefile.userprogs ├── kconfig ├── .gitignore ├── Makefile ├── array_size.h ├── conf.c ├── confdata.c ├── expr.c ├── expr.h ├── gconf-cfg.sh ├── gconf.c ├── gconf.glade ├── hashtable.h ├── images.c ├── images.h ├── internal.h ├── lexer.l ├── lexer.lex.c ├── list.h ├── list_types.h ├── lkc.h ├── lkc_proto.h ├── lxdialog │ ├── BIG.FAT.WARNING │ ├── checklist.c │ ├── dialog.h │ ├── inputbox.c │ ├── menubox.c │ ├── textbox.c │ ├── util.c │ └── yesno.c ├── mconf-cfg.sh ├── mconf.c ├── menu.c ├── merge_config.sh ├── mnconf-common.c ├── mnconf-common.h ├── nconf-cfg.sh ├── nconf.c ├── nconf.gui.c ├── nconf.h ├── parser.tab.c ├── parser.tab.h ├── parser.y ├── preprocess.c ├── preprocess.h ├── qconf-cfg.sh ├── qconf.cc ├── qconf.h ├── streamline_config.pl ├── symbol.c ├── tests │ ├── auto_submenu │ │ ├── Kconfig │ │ ├── __init__.py │ │ └── expected_stdout │ ├── choice │ │ ├── Kconfig │ │ ├── __init__.py │ │ ├── alldef_expected_config │ │ ├── allmod_expected_config │ │ ├── allno_expected_config │ │ ├── allyes_expected_config │ │ ├── oldask0_expected_stdout │ │ ├── oldask1_config │ │ └── oldask1_expected_stdout │ ├── choice_randomize │ │ ├── Kconfig │ │ ├── __init__.py │ │ ├── expected_config0 │ │ ├── expected_config1 │ │ └── expected_config2 │ ├── choice_randomize2 │ │ ├── Kconfig │ │ ├── __init__.py │ │ ├── expected_config0 │ │ ├── expected_config1 │ │ └── expected_config2 │ ├── choice_value_with_m_dep │ │ ├── Kconfig │ │ ├── __init__.py │ │ ├── config │ │ ├── expected_config │ │ └── expected_stdout │ ├── conftest.py │ ├── err_recursive_dep │ │ ├── Kconfig │ │ ├── __init__.py │ │ └── expected_stderr │ ├── err_recursive_inc │ │ ├── Kconfig │ │ ├── Kconfig.inc1 │ │ ├── Kconfig.inc2 │ │ ├── Kconfig.inc3 │ │ ├── __init__.py │ │ └── expected_stderr │ ├── inter_choice │ │ ├── Kconfig │ │ ├── __init__.py │ │ ├── defconfig │ │ └── expected_config │ ├── new_choice_with_dep │ │ ├── Kconfig │ │ ├── __init__.py │ │ ├── config │ │ └── expected_stdout │ ├── no_write_if_dep_unmet │ │ ├── Kconfig │ │ ├── __init__.py │ │ ├── config │ │ └── expected_config │ ├── preprocess │ │ ├── builtin_func │ │ │ ├── Kconfig │ │ │ ├── __init__.py │ │ │ ├── expected_stderr │ │ │ └── expected_stdout │ │ ├── circular_expansion │ │ │ ├── Kconfig │ │ │ ├── __init__.py │ │ │ └── expected_stderr │ │ ├── escape │ │ │ ├── Kconfig │ │ │ ├── __init__.py │ │ │ └── expected_stderr │ │ └── variable │ │ │ ├── Kconfig │ │ │ ├── __init__.py │ │ │ └── expected_stderr │ └── pytest.ini └── util.c ├── sync_with_linux.sh └── unifdef ├── Makefile └── unifdef.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.a 21 | *.la 22 | *.lo 23 | 24 | # Shared objects (inc. Windows DLLs) 25 | *.dll 26 | *.so 27 | *.so.* 28 | *.dylib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | *.i*86 35 | *.x86_64 36 | *.hex 37 | 38 | # Debug files 39 | *.dSYM/ 40 | *.su 41 | *.idb 42 | *.pdb 43 | 44 | # Kernel Module Compile Results 45 | *.mod* 46 | *.cmd 47 | .tmp_versions/ 48 | modules.order 49 | Module.symvers 50 | Mkfile.old 51 | dkms.conf 52 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | EXTRA_DIST = configure.ac \ 5 | README.md \ 6 | Makefile.sample \ 7 | kbuild \ 8 | kconfig \ 9 | fixdep \ 10 | unifdef \ 11 | example 12 | 13 | doc_DATA = README.md 14 | pkgdir = $(datarootdir)/kbuild-standalone 15 | scriptsdir = $(pkgdir)/scripts 16 | 17 | pkg_SCRIPTS = kbuild/_fixdep 18 | pkg_DATA = kbuild/Makefile.env \ 19 | kbuild/Makefile.include \ 20 | kbuild/Makefile.head \ 21 | kbuild/Makefile.main \ 22 | kbuild/Makefile.output 23 | scripts_DATA = kbuild/scripts/Makefile.build \ 24 | kbuild/scripts/Makefile.clean \ 25 | kbuild/scripts/Makefile.lib \ 26 | kbuild/scripts/Makefile.host \ 27 | kbuild/scripts/Makefile.compiler \ 28 | kbuild/scripts/Kbuild.include 29 | 30 | pkgconfigdir = $(libdir)/pkgconfig 31 | pkgconfig_DATA = kbuild-standalone.pc 32 | 33 | localbins = kbuild-mconf kbuild-conf kbuild-fixdep kbuild-unifdef 34 | 35 | all-local: $(localbins) 36 | 37 | clean-local: 38 | rm -rf __build $(localbins) 39 | 40 | install-exec-hook: $(localbins) 41 | $(MKDIR_P) "$(DESTDIR)$(bindir)"; \ 42 | $(INSTALL_PROGRAM) $(localbins) "$(DESTDIR)$(bindir)" 43 | 44 | uninstall-hook: 45 | cd $(DESTDIR)$(bindir) && rm -f $(localbins) 46 | 47 | kbuild-mconf kbuild-conf kbuild-fixdep kbuild-unifdef: __build 48 | 49 | kbuild-fixdep: 50 | cp $(builddir)/__build/fixdep/fixdep $@ 51 | kbuild-conf: 52 | cp $(builddir)/__build/kconfig/conf $@ 53 | kbuild-mconf: 54 | cp $(builddir)/__build/kconfig/mconf $@ 55 | kbuild-unifdef: 56 | cp $(builddir)/__build/unifdef/unifdef $@ 57 | 58 | __build: 59 | $(MAKE) -C $(builddir) -f $(abs_top_srcdir)/Makefile.sample O=$(builddir)/__build 60 | 61 | .PHONY: __build 62 | -------------------------------------------------------------------------------- /Makefile.sample: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # Top makefile of kbuild standalone. This is also a sample makefile 5 | # to show how to use kbuild standalone. 6 | # 7 | # `KBUILD_STANDALONE_SRCDIRS:` source directories of this project. 8 | # `KBUILD_STANDALONE_TARGETS:` targets to build using kbuild standalone. 9 | # `_GOAL:` make goals list passed to `/Makefile`. 10 | # `_CONF:` config of a target, like `need-builtin=1`. 11 | 12 | KBUILD_STANDALONE_TARGETS := fixdep kconfig unifdef 13 | KBUILD_STANDALONE_SRCDIRS := $(KBUILD_STANDALONE_TARGETS) 14 | 15 | kconfig_GOAL := kconfig/mconf kconfig/conf 16 | 17 | # Suggest to use pkg-config to find the location where Makefile.include 18 | # should be found. If it is not found, use internal kbuild. 19 | makefile_include := $(shell pkg-config --variable=makefile_include kbuild-standalone) 20 | ifeq ($(makefile_include),) 21 | kbuild_standalone_path := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))/kbuild 22 | makefile_include := $(kbuild_standalone_path)/Makefile.include 23 | endif 24 | 25 | # include Makefile.include to invoke kbuild standalone. 26 | include $(makefile_include) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Standalone kconfig and kbuild 2 | 3 | ## Motivation 4 | 5 | KConfig and KBuild are powerful tools for building large projects written in 6 | mostly .c. They are parts of Linux kernel source code. Linux uses them to build 7 | itself. Some open source projects such as busybox and UBoot also use it as 8 | their building framework. However, sinces they are part of Linux kernel, they 9 | have to be forked and merged into the project who wish to use it. After 10 | forking, the connection between the project and Linux kernel is broken. 11 | Projects choose to use them has to maintain these tools by itself to get new 12 | features and fix bugs. 13 | 14 | The goal of this project is to provide standalone kconfig and kbuild. Other 15 | projects can `depend on` this project as basic tools for building like gcc and 16 | make, instead of merging them into their own source code. 17 | 18 | Currently, this project contains: 19 | * kconfig: Standalone conf and mconf executable which reads Kconfig source 20 | code and output .config. 21 | * kbuild: Basic kbuild makefile scripts are brought from Linux kernel. A wrapper 22 | is provided to make it work standalone. 23 | * fixdep, unifdef: Small tools in Linux kernel for building. 24 | 25 | ## kconfig 26 | 27 | ### Building kconfig standalone 28 | 29 | ``` 30 | $ git clone https://github.com/WangNan0/kbuild-standalone.git 31 | $ cd kbuild-standalone 32 | $ mkdir build 33 | $ cd build 34 | $ make -C ../ -f Makefile.sample O=`pwd` -j 35 | $ ls ./kconfig/*conf 36 | ./kconfig/conf ./kconfig/mconf 37 | ``` 38 | 39 | `conf` and `mconf` can be used to config linux kernel: 40 | 41 | ``` 42 | $ git clone https://github.com/torvalds/linux.git 43 | $ cd linux 44 | 45 | # menuconfig 46 | $ SRCARCH=x86 srctree=`pwd` CC=gcc /path/to/mconf ./Kconfig 47 | 48 | # allyesconfig 49 | SRCARCH=x86 srctree=`pwd` CC=gcc /path/to/conf --allyesconfig ./Kconfig 50 | 51 | # defconfig 52 | SRCARCH=arm srctree=`pwd` CC=arm-none-eabi-gcc /path/to/conf \ 53 | --defconfig=arch/arm/configs/vexpress_defconfig ./Kconfig 54 | ``` 55 | 56 | ## kbuild 57 | 58 | Makefile.sample is also an simple example about how kbuild standalone can be 59 | used in other project by simply setting following make variables: 60 | 61 | * `KBUILD_STANDALONE_SRCDIRS:` source directories of this project. 62 | * `KBUILD_STANDALONE_TARGETS:` targets to build using kbuild standalone. 63 | * `KBUILD_STANDALONE_PREPARE:` targets to build before `KBUILD_STANDALONE_TARGETS` 64 | * `_GOAL:` make goals list passed to `/Makefile`. 65 | * `_CONF:` config of a target, like `need-builtin=1`. 66 | 67 | Then include Makefile.include which can be found using pkg-config. 68 | 69 | ## Maintenance 70 | 71 | This project keeps syncing with Linux kernel. When Linux has a new release, 72 | we sync updates from Linux kernel to keep us identical with upstream. 73 | Therefore, we will not accept new feature or bugfix by our own. Instead, we 74 | try to make them upstream then sync them back. 75 | 76 | Version number of this project comes from source version of Linux kernel. 77 | It contains 2 or 3 digits. The first 2 digits are version and patchlevel 78 | of corresponding Linux kernel (for example, 5.6). The third digit is vesion 79 | of this project itself. Each time when bumping Linux kernel version, the third 80 | digit would be reset to 0 and ignored. 81 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | See https://docs.kernel.org/process/security-bugs.html 5 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020,2021 Wang Nan 3 | 4 | # configure.ac for installing kbuild standalone 5 | # We use autotools because autotools is well supported 6 | # by yocto. We can also use cmake but I am not very 7 | # familiar with it. 8 | 9 | AC_INIT([kbuild-standalone],[6.9],[pi3orama@163.com]) 10 | AC_CONFIG_SRCDIR([Makefile.am]) 11 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 12 | AC_CONFIG_FILES([Makefile]) 13 | AC_CONFIG_FILES([kbuild-standalone.pc]) 14 | AC_OUTPUT 15 | -------------------------------------------------------------------------------- /example/Kconfig: -------------------------------------------------------------------------------- 1 | # Example Kconfig file 2 | 3 | mainmenu "Example project for $(ARCH) configuration" 4 | 5 | source "arch/$(SRCARCH)/Kconfig" 6 | source "tools/Kconfig" 7 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # This is an example master Makefile for a relative large project 5 | 6 | PROJECT := example 7 | export PROJECT 8 | 9 | KBUILD_STANDALONE_TARGETS := arch kernel 10 | KBUILD_STANDALONE_SRCDIRS := $(KBUILD_STANDALONE_TARGETS) tools 11 | 12 | kernel_CONF := need-builtin=1 13 | arch_CONF := need-builtin=1 14 | 15 | makefile_include := $(shell pkg-config --variable=makefile_include kbuild-standalone) 16 | 17 | # Cmdline without explicit target goes to _all because we make 18 | # _all the first target. _all is default target defined in $(makefile_include) 19 | _all: 20 | 21 | ifeq ($(kbuild_stage),) 22 | include kbuild/Makefile.head 23 | endif 24 | 25 | ifeq ($(kbuild_stage),1) 26 | include kbuild/Makefile.prepare 27 | include kbuild/Makefile.arch 28 | include kbuild/Makefile.kconfig 29 | include kbuild/Makefile.cflags 30 | include kbuild/Makefile.main 31 | # include kbuild/Makefile.install 32 | endif 33 | 34 | include $(makefile_include) 35 | -------------------------------------------------------------------------------- /example/README.example.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | Here is a relative complex demo project using kbuild-standalone. It demonstrates 4 | a recommended configuration. 5 | 6 | It has following features: 7 | * Support `make menuconfig` and some defconfig targets as Linux kernel 8 | * Support more than one architecture 9 | * More than one source directories 10 | * Use config option to control files to be built 11 | * tools/ directory is not source directory but required by `menuconfig` 12 | * Link multiple built-in.a to executable with shell script 13 | * Trace dependency correctly 14 | 15 | Use following command to start playing with this demo: 16 | ``` 17 | $ mkdir build 18 | $ cd build 19 | $ make ARCH=x86_64 -C ../ O=`pwd` alldefconfig 20 | $ make ARCH=x86_64 -C ../ O=`pwd` kernel.exec 21 | ``` 22 | -------------------------------------------------------------------------------- /example/arch/Kbuild: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | obj-$(CONFIG_X86_64) += x86_64/ 5 | obj-$(CONFIG_ARM) += arm/ 6 | -------------------------------------------------------------------------------- /example/arch/arm/Kconfig: -------------------------------------------------------------------------------- 1 | # Example Kconfig file in ARCH 2 | 3 | config ARM 4 | bool 5 | default y 6 | 7 | source "kernel/Kconfig" 8 | -------------------------------------------------------------------------------- /example/arch/arm/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | obj-y := 5 | -------------------------------------------------------------------------------- /example/arch/arm/include/asm/arch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | #ifndef ARM_ARCH_H 7 | #define ARM_ARCH_H 8 | 9 | static inline const char *get_arch(void) 10 | { 11 | return "arm"; 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /example/arch/x86_64/Kconfig: -------------------------------------------------------------------------------- 1 | # Example Kconfig file in ARCH 2 | 3 | config X86_64 4 | bool 5 | default y 6 | 7 | source "kernel/Kconfig" 8 | -------------------------------------------------------------------------------- /example/arch/x86_64/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | obj-y := arch.o 5 | -------------------------------------------------------------------------------- /example/arch/x86_64/arch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | static const char arch[] = "x86_64"; 7 | 8 | const char *get_arch(void) 9 | { 10 | return &arch[0]; 11 | } 12 | -------------------------------------------------------------------------------- /example/arch/x86_64/include/asm/arch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | #ifndef X86_64_ARCH_H 7 | #define X86_64_ARCH_H 8 | 9 | extern const char *get_arch(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /example/kbuild/Makefile.arch: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | ifndef ARCH 5 | ARCH := x86_64 6 | endif 7 | 8 | # SRCARCH is required for Kconfig 9 | SRCARCH := $(ARCH) 10 | export SRCARCH ARCH 11 | -------------------------------------------------------------------------------- /example/kbuild/Makefile.cflags: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # An example makefile to show how to control gcc options 5 | 6 | optflgs += -g 7 | 8 | ifdef CONFIG_CC_OPTIMIZE_O2 9 | optflgs += -O2 10 | endif 11 | ifdef CONFIG_CC_OPTIMIZE_O1 12 | optflgs += -O1 13 | endif 14 | ifdef CONFIG_CC_OPTIMIZE_O0 15 | optflgs += -O0 16 | endif 17 | 18 | KBUILD_CFLAGS += $(optflgs) 19 | KBUULD_AFLAGS += -g 20 | -------------------------------------------------------------------------------- /example/kbuild/Makefile.head: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | # 4 | # Makefile.head is included before stage1: 5 | # ifeq ($(kbuild_stage),) 6 | # include kbuild/Makefile.head 7 | # endif 8 | # 9 | # Which can see raw configuration at first round, before 10 | # adjusted by other part of makefile. For example, MAKECMDGOALS 11 | # reflect user input only at this stage. 12 | 13 | ifneq ($(words $(MAKECMDGOALS)),0) 14 | ifneq ($(words $(MAKECMDGOALS)),1) 15 | $(error Only one make target is supported) 16 | endif 17 | endif 18 | -------------------------------------------------------------------------------- /example/kbuild/Makefile.kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | # This file create kconfig related targets 4 | 5 | 6 | PHONY += menuconfig alldefconfig syncconfig oldconfig 7 | 8 | ifeq ($(quiet),silent_) 9 | silent := -s 10 | endif 11 | 12 | KCONFIG_CONFIG ?= .config 13 | export KCONFIG_CONFIG 14 | 15 | menuconfig: 16 | $(Q)$(KBUILD_MCONF) $(silent) $(abs_srctree)/Kconfig 17 | 18 | alldefconfig: 19 | $(Q)$(KBUILD_CONF) $(silent) --$@ $(abs_srctree)/Kconfig 20 | 21 | oldconfig: 22 | $(Q)$(KBUILD_CONF) $(silent) --$@ $(abs_srctree)/Kconfig 23 | 24 | syncconfig: 25 | $(Q)$(KBUILD_CONF) $(silent) --$@ $(abs_srctree)/Kconfig 26 | 27 | $(KCONFIG_CONFIG): 28 | @echo >&2 '***' 29 | @echo >&2 '*** $@ not found!' 30 | @echo >&2 '*** Use make {old,menu,sync,all,xx_}defconfig to generate one' 31 | 32 | include/conf/auto.conf: syncconfig 33 | @: 34 | 35 | ifeq ($(filter menuconfig oldconfig alldefconfig syncconfig, $(MAKECMDGOALS)),) 36 | include include/config/auto.conf 37 | endif 38 | -------------------------------------------------------------------------------- /example/kbuild/Makefile.main: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # This is an example kernel main makefile 5 | 6 | KBUILD_CFLAGS += -Wall -Wextra 7 | 8 | INCLUDE := -I$(srctree)/kernel/include \ 9 | -I$(objtree)/kernel/include \ 10 | -I$(srctree)/arch/$(SRCARCH)/include \ 11 | -I$(objtree)/arch/$(SRCARCH)/include 12 | 13 | KBUILD_CPPFLAGS += -D__KERNEL__ 14 | 15 | # LINUXINCLUDE is API provided by kbuild 16 | LINUXINCLUDE += $(INCLUDE) 17 | 18 | export LINUXINCLUDE KBUILD_AFLAGS KBUILD_CPPFLAGS KBUILD_CFLAGS KBUILD_LIBS 19 | 20 | OUTPUT_THINLIBS := $(addsuffix /built-in.a,$(KBUILD_STANDALONE_TARGETS)) 21 | 22 | $(OUTPUT_THINLIBS): $(addprefix _build_,$(KBUILD_STANDALONE_TARGETS)) 23 | @: 24 | 25 | cmd_link_kernel = $(CONFIG_SHELL) $< $@ $(OUTPUT_THINLIBS) 26 | # Manually include cmd file because we are not in Makefile.build. 27 | # It is required to make if_changes works 28 | -include .kernel.exec.cmd 29 | kernel.exec: kbuild/link-kernel-exec.sh $(OUTPUT_THINLIBS) 30 | $(call if_changed,link_kernel) 31 | -------------------------------------------------------------------------------- /example/kbuild/Makefile.prepare: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | KBUILD_STANDALONE_PREPARE += gen_compiler_types_h 5 | 6 | define filechk_compiler_types.h 7 | mkdir -p $(srctree)/include/linux; touch $@ 8 | endef 9 | 10 | $(srctree)/include/linux/compiler_types.h: 11 | $(call filechk,compiler_types.h) 12 | 13 | gen_compiler_types_h: $(srctree)/include/linux/compiler_types.h 14 | @: 15 | 16 | PHONY += gen_compiler_types_h 17 | -------------------------------------------------------------------------------- /example/kbuild/link-kernel-exec.sh: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | set -e 5 | 6 | if [ "x${KBUILD_VERBOSE}" = "x1" ] 7 | then 8 | set -x 9 | fi 10 | 11 | . ./${KCONFIG_CONFIG} 12 | 13 | kernel_output=$1 14 | shift 1 15 | 16 | ${AR} rcsTP built-in.a "$@" 17 | ${CC} built-in.a -o $kernel_output 18 | -------------------------------------------------------------------------------- /example/kernel/Kconfig: -------------------------------------------------------------------------------- 1 | # Example Kconfig file for kernel 2 | 3 | choice 4 | 5 | prompt "GCC optimization level" 6 | default CC_OPTIMIZE_O2 7 | 8 | config CC_OPTIMIZE_O0 9 | bool "Use -O0" 10 | config CC_OPTIMIZE_O1 11 | bool "Use -O1" 12 | config CC_OPTIMIZE_O2 13 | bool "Use -O2" 14 | 15 | endchoice 16 | -------------------------------------------------------------------------------- /example/kernel/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # Example makefile in kernel subdir 5 | 6 | obj-y += main.o 7 | obj-$(CONFIG_CC_OPTIMIZE_O0) += opt0.o 8 | obj-$(CONFIG_CC_OPTIMIZE_O1) += opt1.o 9 | obj-$(CONFIG_CC_OPTIMIZE_O2) += opt2.o 10 | -------------------------------------------------------------------------------- /example/kernel/include/kernel/optimization.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | #ifndef KERNEL_OPTIMIZATION_H 7 | #define KERNEL_OPTIMIZATION_H 8 | 9 | extern const char *opt_level(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /example/kernel/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | printf("optimization level: %s\n", opt_level()); 13 | printf("arch: %s\n", get_arch()); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /example/kernel/opt0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | #include 7 | 8 | static const char _optlv[] = "O0"; 9 | 10 | const char *opt_level(void) 11 | { 12 | return &_optlv[0]; 13 | } 14 | -------------------------------------------------------------------------------- /example/kernel/opt1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | #include 7 | 8 | static const char _optlv[] = "O1"; 9 | 10 | const char *opt_level(void) 11 | { 12 | return &_optlv[0]; 13 | } 14 | -------------------------------------------------------------------------------- /example/kernel/opt2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-2.0 3 | * Copyright (C) 2020 Wang Nan 4 | */ 5 | 6 | #include 7 | 8 | static const char _optlv[] = "O2"; 9 | 10 | const char *opt_level(void) 11 | { 12 | return &_optlv[0]; 13 | } 14 | -------------------------------------------------------------------------------- /example/tools/Kconfig: -------------------------------------------------------------------------------- 1 | # Example Kconfig file 2 | 3 | menu "Example kconfig options in tools/" 4 | 5 | config EXAMPLE_OPTION 6 | bool "This is an example option in KBUILD_STANDALONE_SRCDIRS" 7 | default y 8 | 9 | endmenu 10 | -------------------------------------------------------------------------------- /fixdep/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | /fixdep 3 | /randstruct.seed 4 | -------------------------------------------------------------------------------- /fixdep/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # 3 | # fixdep: used to generate dependency information during build process 4 | 5 | hostprogs-always-y += fixdep 6 | 7 | # randstruct: the seed is needed before building the gcc-plugin or 8 | # before running a Clang kernel build. 9 | gen-randstruct-seed := $(srctree)/scripts/gen-randstruct-seed.sh 10 | quiet_cmd_create_randstruct_seed = GENSEED $@ 11 | cmd_create_randstruct_seed = \ 12 | $(CONFIG_SHELL) $(gen-randstruct-seed) \ 13 | $@ $(objtree)/include/generated/randstruct_hash.h 14 | $(obj)/randstruct.seed: $(gen-randstruct-seed) FORCE 15 | $(call if_changed,create_randstruct_seed) 16 | always-$(CONFIG_RANDSTRUCT) += randstruct.seed 17 | -------------------------------------------------------------------------------- /kbuild-standalone.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | makefile_include=@datarootdir@/kbuild-standalone/Makefile.include 4 | 5 | Name: kbuild standalone 6 | Description: A standalone solution for kbuild and kconfig 7 | Version: @VERSION@ 8 | -------------------------------------------------------------------------------- /kbuild/Makefile.env: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # environment of kbuild standalone: setting external tools to use. 5 | # use '?=' so it can be overwritten. 6 | 7 | CONFIG_SHELL ?= sh 8 | 9 | export CONFIG_SHELL 10 | 11 | HOSTCC ?= gcc 12 | HOSTCXX ?= g++ 13 | KBUILD_HOSTCFLAGS ?= -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \ 14 | -fomit-frame-pointer -std=gnu11 $(HOST_LFS_CFLAGS) \ 15 | $(HOSTCFLAGS) 16 | KBUILD_HOSTCXXFLAGS ?= -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS) 17 | KBUILD_HOSTLDFLAGS ?= $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS) 18 | KBUILD_HOSTLDLIBS ?= $(HOST_LFS_LIBS) $(HOSTLDLIBS) 19 | 20 | export HOSTCC HOSTCXX KBUILD_HOSTCFLAGS KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS 21 | export KBUILD_HOSTLDLIBS 22 | 23 | AS ?= $(CROSS_COMPILE)as 24 | LD ?= $(CROSS_COMPILE)ld 25 | CC ?= $(CROSS_COMPILE)gcc 26 | CPP ?= $(CC) -E 27 | AR ?= $(CROSS_COMPILE)ar 28 | NM ?= $(CROSS_COMPILE)nm 29 | STRIP ?= $(CROSS_COMPILE)strip 30 | OBJCOPY ?= $(CROSS_COMPILE)objcopy 31 | OBJDUMP ?= $(CROSS_COMPILE)objdump 32 | OBJSIZE ?= $(CROSS_COMPILE)size 33 | READELF ?= $(CROSS_COMPILE)readelf 34 | PAHOLE ?= pahole 35 | LEX ?= flex 36 | YACC ?= bison 37 | AWK ?= awk 38 | PERL ?= perl 39 | PYTHON ?= python 40 | PYTHON3 ?= python3 41 | CHECK ?= sparse 42 | BASH ?= bash 43 | 44 | KBUILD_CONF ?= kbuild-conf 45 | KBUILD_MCONF ?= kbuild-mconf 46 | KBUILD_FIXDEP ?= kbuild-fixdep 47 | KBUILD_UNIFDEF ?= kbuild-unifdef 48 | 49 | export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE READELF 50 | export PAHOLE LEX YACC AWK PERL PYTHON PYTHON3 CHECK BASH 51 | export KBUILD_CONF KBUILD_MCONF KBUILD_FIXDEP KBUILD_UNIFDEF 52 | -------------------------------------------------------------------------------- /kbuild/Makefile.head: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # Head part bring from linux top level Makefile 5 | 6 | # Do not use make's built-in rules and variables 7 | # (this increases performance and avoids hard-to-debug behaviour) 8 | MAKEFLAGS += -rR 9 | 10 | # Avoid funny character set dependencies 11 | unexport LC_ALL 12 | LC_COLLATE=C 13 | LC_NUMERIC=C 14 | export LC_COLLATE LC_NUMERIC 15 | 16 | # Avoid interference with shell env settings 17 | unexport GREP_OPTIONS 18 | 19 | ifeq ("$(origin V)", "command line") 20 | KBUILD_VERBOSE = $(V) 21 | endif 22 | ifndef KBUILD_VERBOSE 23 | KBUILD_VERBOSE = 0 24 | endif 25 | 26 | ifeq ($(KBUILD_VERBOSE),1) 27 | quiet = 28 | Q = 29 | else 30 | quiet=quiet_ 31 | Q = @ 32 | endif 33 | 34 | ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),) 35 | quiet=silent_ 36 | endif 37 | 38 | export quiet Q KBUILD_VERBOSE 39 | -------------------------------------------------------------------------------- /kbuild/Makefile.include: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # Default target when cmdline is empty 5 | PHONY := _all 6 | _all: 7 | 8 | # If the user is running make -s (silent mode), suppress echoing of 9 | # commands 10 | 11 | # kbuild_stage is part of API. User makefile controls variables and 12 | # make targets can be seen by kbuild through kbuild_stage. 13 | # An example user makefile: 14 | # 15 | # ... Definitions should be seen in all stages, like KBUILD_STANDALONE_TARGETS. 16 | # 17 | # ifeq ($(kbuild_stage),) 18 | # ... Definitions provided for Makefile.output, like KBUILD_STANDALONE_SRCDIRS. 19 | # endif 20 | # 21 | # ifeq ($(kbuild_stage),1) 22 | # ... Definitions for Makefile.main, like KBUILD_STANDALONE_PREPARE. 23 | # endif 24 | # 25 | # makefile_include := $(shell pkg-config --variable=makefile_include kbuild-standalone) 26 | # include $(makefile_include) 27 | # 28 | # ifeq ($(kbuild_stage),2) 29 | # ... Definitions after Makefile.main. 30 | # endif 31 | # 32 | 33 | ifeq ($(kbuild_stage),) 34 | # kbuild_stage is not set, this is first pass. Directly included 35 | # by original makefile. 36 | # abs_kbuildtree is directory of kbuild standalone 37 | # abs_srctree is the Makefile which include Makefile.include. 38 | # It should be the makefile directly include this file. 39 | abs_kbuildtree := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) 40 | abs_srctree := $(realpath $(dir $(firstword $(MAKEFILE_LIST)))) 41 | abs_top_makefile := $(realpath $(firstword $(MAKEFILE_LIST))) 42 | export abs_kbuildtree abs_srctree abs_top_makefile 43 | 44 | include $(abs_kbuildtree)/Makefile.head 45 | include $(abs_kbuildtree)/Makefile.output 46 | kbuild_stage := 1 47 | export kbuild_stage 48 | else 49 | kbuild_stage := 2 50 | export kbuild_stage 51 | include $(abs_kbuildtree)/Makefile.env 52 | include $(abs_kbuildtree)/Makefile.main 53 | endif 54 | 55 | PHONY += FORCE 56 | FORCE: 57 | 58 | # Declare the contents of the PHONY variable as phony. We keep that 59 | # information in a variable so we can use it in if_changed and friends. 60 | .PHONY: $(PHONY) 61 | -------------------------------------------------------------------------------- /kbuild/Makefile.main: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # Main part of kbuild standalone makefile 5 | # Build $(KBUILD_STANDALONE_TARGETS) using kbuild. 6 | 7 | building_out_of_srctree := 1 8 | 9 | srctree ?= .source 10 | objtree ?= . 11 | VPATH := $(srctree) $(abs_srctree) 12 | 13 | export building_out_of_srctree srctree objtree VPATH 14 | 15 | PHONY += all 16 | 17 | _all: all 18 | 19 | KBUILD_MODULES := 20 | KBUILD_BUILTIN := 1 21 | 22 | export KBUILD_MODULES KBUILD_BUILTIN 23 | 24 | include scripts/Kbuild.include 25 | 26 | build_targets := $(addprefix _build_,$(KBUILD_STANDALONE_TARGETS)) 27 | 28 | all: $(build_targets) 29 | 30 | $(build_targets): prepare 31 | $(MAKE) $(build)=$(patsubst _build_%,%,$@) $($(addsuffix _GOAL, $(patsubst _build_%,%,$@))) \ 32 | $($(addsuffix _CONF, $(patsubst _build_%,%,$@))) 33 | 34 | prepare: $(KBUILD_STANDALONE_PREPARE) 35 | 36 | PHONY += prepare 37 | -------------------------------------------------------------------------------- /kbuild/Makefile.output: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright (C) 2020 Wang Nan 3 | 4 | # Wrapper for kbuild standalone: create an transition source code directory. 5 | # Create symlinks for scripts and targets to make it similar to Linux kernel's 6 | # source code directory. 7 | 8 | ifeq ("$(origin O)", "command line") 9 | KBUILD_OUTPUT := $(O) 10 | else 11 | $(error Must provide an 'O' option) 12 | endif 13 | 14 | abs_objtree := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) && pwd) 15 | $(if $(abs_objtree),, \ 16 | $(error failed to create output directory "$(KBUILD_OUTPUT)")) 17 | 18 | abs_trans_srctree := $(shell mkdir -p $(abs_objtree)/.source && cd $(KBUILD_OUTPUT)/.source && pwd) 19 | $(if $(abs_trans_srctree),, \ 20 | $(error failed to create transition source directory "$(KBUILD_OUTPUT)/.source")) 21 | 22 | export abs_objtree abs_trans_srctree 23 | 24 | ifeq ($(abs_objtree),$(abs_srctree)) 25 | $(error In-tree-building is not supported. Set "O" to build directory) 26 | endif 27 | 28 | # Define these 2 important variables here so user makefile don't need to wait for 29 | # the second pass 'make ..' (kbuild_stage moves to 2) 30 | srctree := .source 31 | objtree := . 32 | 33 | export srctree objtree 34 | 35 | # Set include-dir for next stage, so we can include scripts/xxx 36 | # (abs_kbuildtree) and Makefile (abs_srctree). Put abs_trans_srctree at head 37 | # to avoid `scripts` directories in abs_srctree be searched internally. 38 | MAKEFLAGS += --include-dir=$(abs_trans_srctree) --include-dir=$(abs_srctree) --include-dir=$(abs_kbuildtree) 39 | MAKEFLAGS += --no-print-directory 40 | 41 | PHONY += $(MAKECMDGOALS) sub-make 42 | 43 | $(filter-out _all sub-make $(lastword $(MAKEFILE_LIST)), $(MAKECMDGOALS)) _all: sub-make 44 | @: 45 | 46 | # Invoke a second make in the output directory, passing relevant variables 47 | sub-make: prepare_objtree 48 | $(Q)$(MAKE) -C $(abs_objtree) -f $(abs_top_makefile) $(MAKECMDGOALS) 49 | 50 | prepare_targets := $(addprefix _prepare_trans_src_dir_, $(KBUILD_STANDALONE_SRCDIRS)) 51 | 52 | prepare_objtree: prepare_scripts $(prepare_targets) 53 | $(Q)if [ ! -e $(abs_objtree)/scripts/basic/fixdep ]; then \ 54 | mkdir -p $(abs_objtree)/scripts/basic; \ 55 | cp $(abs_kbuildtree)/_fixdep $(abs_objtree)/scripts/basic/fixdep; \ 56 | fi 57 | 58 | ifeq ($(abs_srctree),$(realpath $(abs_trans_srctree)/../.. )) 59 | _rel_srctree := ../.. 60 | else 61 | _rel_srctree := $(abs_srctree) 62 | endif 63 | 64 | $(prepare_targets): 65 | $(Q)if [ ! -L $(abs_trans_srctree)/$(patsubst _prepare_trans_src_dir_%,%,$@) ]; then \ 66 | ln -fsn $(_rel_srctree)/$(patsubst _prepare_trans_src_dir_%,%,$@) $(abs_trans_srctree); \ 67 | fi 68 | 69 | prepare_scripts: 70 | $(Q)if [ ! -L $(abs_trans_srctree)/scripts ]; then \ 71 | ln -fsn $(abs_kbuildtree)/scripts $(abs_trans_srctree) ; \ 72 | fi 73 | -------------------------------------------------------------------------------- /kbuild/_fixdep: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-License-Identifier: GPL-2.0 4 | # Copyright (C) 2020 Wang Nan 5 | 6 | 7 | # A fake fixdep for kbuild-standalone, make building continue without 8 | # real fixdep. 9 | # fixdep now is a fundatmental part of kbuild. Since kbuild code is kept 10 | # unchanged and fixdep is provided separatly, providing a fake fixdep 11 | # is a simple way to make building keep going. 12 | 13 | if [ -x "$(command -v kbuild-fixdep)" ] 14 | then 15 | exec kbuild-fixdep "$@" 16 | else 17 | exit 0 18 | fi 19 | -------------------------------------------------------------------------------- /kbuild/scripts/Kbuild.include: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | #### 3 | # kbuild: Generic definitions 4 | 5 | # Convenient variables 6 | comma := , 7 | quote := " 8 | squote := ' 9 | empty := 10 | space := $(empty) $(empty) 11 | space_escape := _-_SPACE_-_ 12 | pound := \# 13 | define newline 14 | 15 | 16 | endef 17 | 18 | ### 19 | # Comparison macros. 20 | # Usage: $(call test-lt, $(CONFIG_LLD_VERSION), 150000) 21 | # 22 | # Use $(intcmp ...) if supported. (Make >= 4.4) 23 | # Otherwise, fall back to the 'test' shell command. 24 | ifeq ($(intcmp 1,0,,,y),y) 25 | test-ge = $(intcmp $(strip $1)0, $(strip $2)0,,y,y) 26 | test-gt = $(intcmp $(strip $1)0, $(strip $2)0,,,y) 27 | else 28 | test-ge = $(shell test $(strip $1)0 -ge $(strip $2)0 && echo y) 29 | test-gt = $(shell test $(strip $1)0 -gt $(strip $2)0 && echo y) 30 | endif 31 | test-le = $(call test-ge, $2, $1) 32 | test-lt = $(call test-gt, $2, $1) 33 | 34 | ### 35 | # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o 36 | dot-target = $(dir $@).$(notdir $@) 37 | 38 | ### 39 | # Name of target with a '.tmp_' as filename prefix. foo/bar.o => foo/.tmp_bar.o 40 | tmp-target = $(dir $@).tmp_$(notdir $@) 41 | 42 | ### 43 | # The temporary file to save gcc -MMD generated dependencies must not 44 | # contain a comma 45 | depfile = $(subst $(comma),_,$(dot-target).d) 46 | 47 | ### 48 | # filename of target with directory and extension stripped 49 | basetarget = $(basename $(notdir $@)) 50 | 51 | ### 52 | # real prerequisites without phony targets 53 | real-prereqs = $(filter-out $(PHONY), $^) 54 | 55 | ### 56 | # Escape single quote for use in echo statements 57 | escsq = $(subst $(squote),'\$(squote)',$1) 58 | 59 | ### 60 | # Quote a string to pass it to C files. foo => '"foo"' 61 | stringify = $(squote)$(quote)$1$(quote)$(squote) 62 | 63 | ### 64 | # The path to Kbuild or Makefile. Kbuild has precedence over Makefile. 65 | kbuild-dir = $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) 66 | kbuild-file = $(or $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Makefile) 67 | 68 | ### 69 | # Read a file, replacing newlines with spaces 70 | # 71 | # Make 4.2 or later can read a file by using its builtin function. 72 | ifneq ($(filter-out 3.% 4.0 4.1, $(MAKE_VERSION)),) 73 | read-file = $(subst $(newline),$(space),$(file < $1)) 74 | else 75 | read-file = $(shell cat $1 2>/dev/null) 76 | endif 77 | 78 | ### 79 | # Easy method for doing a status message 80 | kecho := : 81 | quiet_kecho := echo 82 | silent_kecho := : 83 | kecho := $($(quiet)kecho) 84 | 85 | ### 86 | # filechk is used to check if the content of a generated file is updated. 87 | # Sample usage: 88 | # 89 | # filechk_sample = echo $(KERNELRELEASE) 90 | # version.h: FORCE 91 | # $(call filechk,sample) 92 | # 93 | # The rule defined shall write to stdout the content of the new file. 94 | # The existing file will be compared with the new one. 95 | # - If no file exist it is created 96 | # - If the content differ the new file is used 97 | # - If they are equal no change, and no timestamp update 98 | define filechk 99 | $(check-FORCE) 100 | $(Q)set -e; \ 101 | mkdir -p $(dir $@); \ 102 | trap "rm -f $(tmp-target)" EXIT; \ 103 | { $(filechk_$(1)); } > $(tmp-target); \ 104 | if [ ! -r $@ ] || ! cmp -s $@ $(tmp-target); then \ 105 | $(kecho) ' UPD $@'; \ 106 | mv -f $(tmp-target) $@; \ 107 | fi 108 | endef 109 | 110 | ### 111 | # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj= 112 | # Usage: 113 | # $(Q)$(MAKE) $(build)=dir 114 | build := -f $(srctree)/scripts/Makefile.build obj 115 | 116 | ### 117 | # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= 118 | # Usage: 119 | # $(Q)$(MAKE) $(clean)=dir 120 | clean := -f $(srctree)/scripts/Makefile.clean obj 121 | 122 | # pring log 123 | # 124 | # If quiet is "silent_", print nothing and sink stdout 125 | # If quiet is "quiet_", print short log 126 | # If quiet is empty, print short log and whole command 127 | silent_log_print = exec >/dev/null; 128 | quiet_log_print = $(if $(quiet_cmd_$1), echo ' $(call escsq,$(quiet_cmd_$1)$(why))';) 129 | log_print = echo '$(pound) $(call escsq,$(or $(quiet_cmd_$1),cmd_$1 $@)$(why))'; \ 130 | echo ' $(call escsq,$(cmd_$1))'; 131 | 132 | # Delete the target on interruption 133 | # 134 | # GNU Make automatically deletes the target if it has already been changed by 135 | # the interrupted recipe. So, you can safely stop the build by Ctrl-C (Make 136 | # will delete incomplete targets), and resume it later. 137 | # 138 | # However, this does not work when the stderr is piped to another program, like 139 | # $ make >&2 | tee log 140 | # Make dies with SIGPIPE before cleaning the targets. 141 | # 142 | # To address it, we clean the target in signal traps. 143 | # 144 | # Make deletes the target when it catches SIGHUP, SIGINT, SIGQUIT, SIGTERM. 145 | # So, we cover them, and also SIGPIPE just in case. 146 | # 147 | # Of course, this is unneeded for phony targets. 148 | delete-on-interrupt = \ 149 | $(if $(filter-out $(PHONY), $@), \ 150 | $(foreach sig, HUP INT QUIT TERM PIPE, \ 151 | trap 'rm -f $@; trap - $(sig); kill -s $(sig) $$$$' $(sig);)) 152 | 153 | # print and execute commands 154 | cmd = @$(if $(cmd_$(1)),set -e; $($(quiet)log_print) $(delete-on-interrupt) $(cmd_$(1)),:) 155 | 156 | ### 157 | # if_changed - execute command if any prerequisite is newer than 158 | # target, or command line has changed 159 | # if_changed_dep - as if_changed, but uses fixdep to reveal dependencies 160 | # including used config symbols 161 | # if_changed_rule - as if_changed but execute rule instead 162 | # See Documentation/kbuild/makefiles.rst for more info 163 | 164 | ifneq ($(KBUILD_NOCMDDEP),1) 165 | # Check if both commands are the same including their order. Result is empty 166 | # string if equal. User may override this check using make KBUILD_NOCMDDEP=1 167 | # If the target does not exist, the *.cmd file should not be included so 168 | # $(savedcmd_$@) gets empty. Then, target will be built even if $(newer-prereqs) 169 | # happens to become empty. 170 | cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(savedcmd_$@))), \ 171 | $(subst $(space),$(space_escape),$(strip $(cmd_$1)))) 172 | else 173 | # We still need to detect missing targets. 174 | cmd-check = $(if $(strip $(savedcmd_$@)),,1) 175 | endif 176 | 177 | # Replace >$< with >$$< to preserve $ when reloading the .cmd file 178 | # (needed for make) 179 | # Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file 180 | # (needed for make) 181 | # Replace >'< with >'\''< to be able to enclose the whole string in '...' 182 | # (needed for the shell) 183 | make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) 184 | 185 | # Find any prerequisites that are newer than target or that do not exist. 186 | # PHONY targets skipped in both cases. 187 | # If there is no prerequisite other than phony targets, $(newer-prereqs) becomes 188 | # empty even if the target does not exist. cmd-check saves this corner case. 189 | newer-prereqs = $(filter-out $(PHONY),$?) 190 | 191 | # It is a typical mistake to forget the FORCE prerequisite. Check it here so 192 | # no more breakage will slip in. 193 | check-FORCE = $(if $(filter FORCE, $^),,$(warning FORCE prerequisite is missing)) 194 | 195 | if-changed-cond = $(newer-prereqs)$(cmd-check)$(check-FORCE) 196 | 197 | # Execute command if command has changed or prerequisite(s) are updated. 198 | if_changed = $(if $(if-changed-cond),$(cmd_and_savecmd),@:) 199 | 200 | cmd_and_savecmd = \ 201 | $(cmd); \ 202 | printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd 203 | 204 | # Execute the command and also postprocess generated .d dependencies file. 205 | if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:) 206 | 207 | cmd_and_fixdep = \ 208 | $(cmd); \ 209 | scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\ 210 | rm -f $(depfile) 211 | 212 | # Usage: $(call if_changed_rule,foo) 213 | # Will check if $(cmd_foo) or any of the prerequisites changed, 214 | # and if so will execute $(rule_foo). 215 | if_changed_rule = $(if $(if-changed-cond),$(rule_$(1)),@:) 216 | 217 | ### 218 | # why - tell why a target got built 219 | # enabled by make V=2 220 | # Output (listed in the order they are checked): 221 | # (1) - due to target is PHONY 222 | # (2) - due to target missing 223 | # (3) - due to: file1.h file2.h 224 | # (4) - due to command line change 225 | # (5) - due to missing .cmd file 226 | # (6) - due to target not in $(targets) 227 | # (1) PHONY targets are always build 228 | # (2) No target, so we better build it 229 | # (3) Prerequisite is newer than target 230 | # (4) The command line stored in the file named dir/.target.cmd 231 | # differed from actual command line. This happens when compiler 232 | # options changes 233 | # (5) No dir/.target.cmd file (used to store command line) 234 | # (6) No dir/.target.cmd file and target not listed in $(targets) 235 | # This is a good hint that there is a bug in the kbuild file 236 | ifneq ($(findstring 2, $(KBUILD_VERBOSE)),) 237 | _why = \ 238 | $(if $(filter $@, $(PHONY)),- due to target is PHONY, \ 239 | $(if $(wildcard $@), \ 240 | $(if $(newer-prereqs),- due to: $(newer-prereqs), \ 241 | $(if $(cmd-check), \ 242 | $(if $(savedcmd_$@),- due to command line change, \ 243 | $(if $(filter $@, $(targets)), \ 244 | - due to missing .cmd file, \ 245 | - due to $(notdir $@) not in $$(targets) \ 246 | ) \ 247 | ) \ 248 | ) \ 249 | ), \ 250 | - due to target missing \ 251 | ) \ 252 | ) 253 | 254 | why = $(space)$(strip $(_why)) 255 | endif 256 | 257 | ############################################################################### 258 | 259 | # delete partially updated (i.e. corrupted) files on error 260 | .DELETE_ON_ERROR: 261 | 262 | # do not delete intermediate files automatically 263 | # 264 | # .NOTINTERMEDIATE is more correct, but only available on newer Make versions. 265 | # Make 4.4 introduced .NOTINTERMEDIATE, and it appears in .FEATURES, but the 266 | # global .NOTINTERMEDIATE does not work. We can use it on Make > 4.4. 267 | # Use .SECONDARY for older Make versions, but "newer-prereq" cannot detect 268 | # deleted files. 269 | ifneq ($(and $(filter notintermediate, $(.FEATURES)),$(filter-out 4.4,$(MAKE_VERSION))),) 270 | .NOTINTERMEDIATE: 271 | else 272 | .SECONDARY: 273 | endif 274 | -------------------------------------------------------------------------------- /kbuild/scripts/Makefile.clean: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # ========================================================================== 3 | # Cleaning up 4 | # ========================================================================== 5 | 6 | src := $(obj) 7 | 8 | PHONY := __clean 9 | __clean: 10 | 11 | include $(srctree)/scripts/Kbuild.include 12 | include $(kbuild-file) 13 | 14 | # Figure out what we need to build from the various variables 15 | # ========================================================================== 16 | 17 | subdir-ymn := $(sort $(subdir-y) $(subdir-m) $(subdir-) \ 18 | $(patsubst %/,%, $(filter %/, $(obj-y) $(obj-m) $(obj-)))) 19 | 20 | # Add subdir path 21 | 22 | subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn)) 23 | 24 | # build a list of files to remove, usually relative to the current 25 | # directory 26 | 27 | __clean-files := \ 28 | $(clean-files) $(targets) $(hostprogs) $(userprogs) \ 29 | $(extra-y) $(extra-m) $(extra-) \ 30 | $(always-y) $(always-m) $(always-) \ 31 | $(hostprogs-always-y) $(hostprogs-always-m) $(hostprogs-always-) \ 32 | $(userprogs-always-y) $(userprogs-always-m) $(userprogs-always-) 33 | 34 | __clean-files := $(filter-out $(no-clean-files), $(__clean-files)) 35 | 36 | __clean-files := $(wildcard $(addprefix $(obj)/, $(__clean-files))) 37 | 38 | # ========================================================================== 39 | 40 | # To make this rule robust against "Argument list too long" error, 41 | # remove $(obj)/ prefix, and restore it by a shell command. 42 | quiet_cmd_clean = CLEAN $(obj) 43 | cmd_clean = printf '$(obj)/%s ' $(patsubst $(obj)/%,%,$(__clean-files)) | xargs rm -rf 44 | 45 | __clean: $(subdir-ymn) 46 | ifneq ($(strip $(__clean-files)),) 47 | $(call cmd,clean) 48 | endif 49 | @: 50 | 51 | 52 | # =========================================================================== 53 | # Generic stuff 54 | # =========================================================================== 55 | 56 | # Descending 57 | # --------------------------------------------------------------------------- 58 | 59 | PHONY += $(subdir-ymn) 60 | $(subdir-ymn): 61 | $(Q)$(MAKE) $(clean)=$@ 62 | 63 | .PHONY: $(PHONY) 64 | -------------------------------------------------------------------------------- /kbuild/scripts/Makefile.compiler: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | 3 | # cc-cross-prefix 4 | # Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-) 5 | # Return first where a gcc is found in PATH. 6 | # If no gcc found in PATH with listed prefixes return nothing 7 | # 8 | # Note: '2>/dev/null' is here to force Make to invoke a shell. Otherwise, it 9 | # would try to directly execute the shell builtin 'command'. This workaround 10 | # should be kept for a long time since this issue was fixed only after the 11 | # GNU Make 4.2.1 release. 12 | cc-cross-prefix = $(firstword $(foreach c, $(1), \ 13 | $(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c)))) 14 | 15 | # output directory for tests below 16 | TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$ 17 | 18 | # try-run 19 | # Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise) 20 | # Exit code chooses option. "$$TMP" serves as a temporary file and is 21 | # automatically cleaned up. 22 | try-run = $(shell set -e; \ 23 | TMP=$(TMPOUT)/tmp; \ 24 | trap "rm -rf $(TMPOUT)" EXIT; \ 25 | mkdir -p $(TMPOUT); \ 26 | if ($(1)) >/dev/null 2>&1; \ 27 | then echo "$(2)"; \ 28 | else echo "$(3)"; \ 29 | fi) 30 | 31 | # as-option 32 | # Usage: aflags-y += $(call as-option,-Wa$(comma)-isa=foo,) 33 | 34 | as-option = $(call try-run,\ 35 | $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(1) -c -x assembler-with-cpp /dev/null -o "$$TMP",$(1),$(2)) 36 | 37 | # as-instr 38 | # Usage: aflags-y += $(call as-instr,instr,option1,option2) 39 | 40 | as-instr = $(call try-run,\ 41 | printf "%b\n" "$(1)" | $(CC) -Werror $(CLANG_FLAGS) $(KBUILD_AFLAGS) -Wa$(comma)--fatal-warnings -c -x assembler-with-cpp -o "$$TMP" -,$(2),$(3)) 42 | 43 | # __cc-option 44 | # Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586) 45 | __cc-option = $(call try-run,\ 46 | $(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4)) 47 | 48 | # cc-option 49 | # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) 50 | 51 | cc-option = $(call __cc-option, $(CC),\ 52 | $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS),$(1),$(2)) 53 | 54 | # cc-option-yn 55 | # Usage: flag := $(call cc-option-yn,-march=winchip-c6) 56 | cc-option-yn = $(call try-run,\ 57 | $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) 58 | 59 | # cc-disable-warning 60 | # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) 61 | cc-disable-warning = $(call try-run,\ 62 | $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) 63 | 64 | # gcc-min-version 65 | # Usage: cflags-$(call gcc-min-version, 70100) += -foo 66 | gcc-min-version = $(call test-ge, $(CONFIG_GCC_VERSION), $1) 67 | 68 | # clang-min-version 69 | # Usage: cflags-$(call clang-min-version, 110000) += -foo 70 | clang-min-version = $(call test-ge, $(CONFIG_CLANG_VERSION), $1) 71 | 72 | # ld-option 73 | # Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y) 74 | ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3)) 75 | -------------------------------------------------------------------------------- /kbuild/scripts/Makefile.host: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | # LEX 4 | # --------------------------------------------------------------------------- 5 | quiet_cmd_flex = LEX $@ 6 | cmd_flex = $(LEX) -o$@ -L $< 7 | 8 | $(obj)/%.lex.c: $(src)/%.l FORCE 9 | $(call if_changed,flex) 10 | 11 | # YACC 12 | # --------------------------------------------------------------------------- 13 | quiet_cmd_bison = YACC $(basename $@).[ch] 14 | cmd_bison = $(YACC) -o $(basename $@).c --defines=$(basename $@).h -t -l $< 15 | 16 | $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE 17 | $(call if_changed,bison) 18 | 19 | # ========================================================================== 20 | # Building binaries on the host system 21 | # Binaries are used during the compilation of the kernel, for example 22 | # to preprocess a data file. 23 | # 24 | # Both C and C++ are supported, but preferred language is C for such utilities. 25 | # Rust is also supported, but it may only be used in scenarios where a Rust 26 | # toolchain is required to be available (e.g. when `CONFIG_RUST` is enabled). 27 | # 28 | # Sample syntax (see Documentation/kbuild/makefiles.rst for reference) 29 | # hostprogs := bin2hex 30 | # Will compile bin2hex.c and create an executable named bin2hex 31 | # 32 | # hostprogs := lxdialog 33 | # lxdialog-objs := checklist.o lxdialog.o 34 | # Will compile lxdialog.c and checklist.c, and then link the executable 35 | # lxdialog, based on checklist.o and lxdialog.o 36 | # 37 | # hostprogs := qconf 38 | # qconf-cxxobjs := qconf.o 39 | # qconf-objs := menu.o 40 | # Will compile qconf as a C++ program, and menu as a C program. 41 | # They are linked as C++ code to the executable qconf 42 | # 43 | # hostprogs := target 44 | # target-rust := y 45 | # Will compile `target` as a Rust program, using `target.rs` as the crate root. 46 | # The crate may consist of several source files. 47 | 48 | # C code 49 | # Executables compiled from a single .c file 50 | host-csingle := $(foreach m,$(hostprogs), \ 51 | $(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-rust),,$(m))) 52 | 53 | # C executables linked based on several .o files 54 | host-cmulti := $(foreach m,$(hostprogs),\ 55 | $(if $($(m)-cxxobjs)$($(m)-rust),,$(if $($(m)-objs),$(m)))) 56 | 57 | # Object (.o) files compiled from .c files 58 | host-cobjs := $(sort $(foreach m,$(hostprogs),$($(m)-objs))) 59 | 60 | # C++ code 61 | # C++ executables compiled from at least one .cc file 62 | # and zero or more .c files 63 | host-cxxmulti := $(foreach m,$(hostprogs),$(if $($(m)-cxxobjs),$(m))) 64 | 65 | # C++ Object (.o) files compiled from .cc files 66 | host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs))) 67 | 68 | # Rust code 69 | # Executables compiled from a single Rust crate (which may consist of 70 | # one or more .rs files) 71 | host-rust := $(foreach m,$(hostprogs),$(if $($(m)-rust),$(m))) 72 | 73 | host-csingle := $(addprefix $(obj)/,$(host-csingle)) 74 | host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) 75 | host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) 76 | host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti)) 77 | host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs)) 78 | host-rust := $(addprefix $(obj)/,$(host-rust)) 79 | 80 | ##### 81 | # Handle options to gcc. Support building with separate output directory 82 | 83 | hostc_flags = -Wp,-MMD,$(depfile) \ 84 | $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ 85 | $(HOSTCFLAGS_$(target-stem).o) 86 | hostcxx_flags = -Wp,-MMD,$(depfile) \ 87 | $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ 88 | $(HOSTCXXFLAGS_$(target-stem).o) 89 | 90 | # `--out-dir` is required to avoid temporaries being created by `rustc` in the 91 | # current working directory, which may be not accessible in the out-of-tree 92 | # modules case. 93 | hostrust_flags = --out-dir $(dir $@) --emit=dep-info=$(depfile) \ 94 | -Clinker-flavor=gcc -Clinker=$(HOSTCC) \ 95 | -Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \ 96 | $(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \ 97 | $(HOSTRUSTFLAGS_$(target-stem)) 98 | 99 | # $(objtree)/$(obj) for including generated headers from checkin source files 100 | ifeq ($(KBUILD_EXTMOD),) 101 | ifdef building_out_of_srctree 102 | hostc_flags += -I $(objtree)/$(obj) 103 | hostcxx_flags += -I $(objtree)/$(obj) 104 | endif 105 | endif 106 | 107 | ##### 108 | # Compile programs on the host 109 | 110 | # Create executable from a single .c file 111 | # host-csingle -> Executable 112 | quiet_cmd_host-csingle = HOSTCC $@ 113 | cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(KBUILD_HOSTLDFLAGS) -o $@ $< \ 114 | $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) 115 | $(host-csingle): $(obj)/%: $(src)/%.c FORCE 116 | $(call if_changed_dep,host-csingle) 117 | 118 | # Link an executable based on list of .o files, all plain c 119 | # host-cmulti -> executable 120 | quiet_cmd_host-cmulti = HOSTLD $@ 121 | cmd_host-cmulti = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -o $@ \ 122 | $(addprefix $(obj)/, $($(target-stem)-objs)) \ 123 | $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) 124 | $(host-cmulti): FORCE 125 | $(call if_changed,host-cmulti) 126 | $(call multi_depend, $(host-cmulti), , -objs) 127 | 128 | # Create .o file from a single .c file 129 | # host-cobjs -> .o 130 | quiet_cmd_host-cobjs = HOSTCC $@ 131 | cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $< 132 | $(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE 133 | $(call if_changed_dep,host-cobjs) 134 | 135 | # Link an executable based on list of .o files, a mixture of .c and .cc 136 | # host-cxxmulti -> executable 137 | quiet_cmd_host-cxxmulti = HOSTLD $@ 138 | cmd_host-cxxmulti = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -o $@ \ 139 | $(foreach o,objs cxxobjs,\ 140 | $(addprefix $(obj)/, $($(target-stem)-$(o)))) \ 141 | $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) 142 | $(host-cxxmulti): FORCE 143 | $(call if_changed,host-cxxmulti) 144 | $(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs) 145 | 146 | # Create .o file from a single .cc (C++) file 147 | quiet_cmd_host-cxxobjs = HOSTCXX $@ 148 | cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $< 149 | $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE 150 | $(call if_changed_dep,host-cxxobjs) 151 | 152 | # Create executable from a single Rust crate (which may consist of 153 | # one or more `.rs` files) 154 | # host-rust -> Executable 155 | quiet_cmd_host-rust = HOSTRUSTC $@ 156 | cmd_host-rust = \ 157 | $(HOSTRUSTC) $(hostrust_flags) --emit=link=$@ $< 158 | $(host-rust): $(obj)/%: $(src)/%.rs FORCE 159 | +$(call if_changed_dep,host-rust) 160 | 161 | targets += $(host-csingle) $(host-cmulti) $(host-cobjs) \ 162 | $(host-cxxmulti) $(host-cxxobjs) $(host-rust) 163 | -------------------------------------------------------------------------------- /kbuild/scripts/Makefile.userprogs: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # 3 | # Build userspace programs for the target system 4 | # 5 | 6 | # Executables compiled from a single .c file 7 | user-csingle := $(foreach m, $(userprogs), $(if $($(m)-objs),,$(m))) 8 | 9 | # Executables linked based on several .o files 10 | user-cmulti := $(foreach m, $(userprogs), $(if $($(m)-objs),$(m))) 11 | 12 | # Objects compiled from .c files 13 | user-cobjs := $(sort $(foreach m, $(userprogs), $($(m)-objs))) 14 | 15 | user-csingle := $(addprefix $(obj)/, $(user-csingle)) 16 | user-cmulti := $(addprefix $(obj)/, $(user-cmulti)) 17 | user-cobjs := $(addprefix $(obj)/, $(user-cobjs)) 18 | 19 | user_ccflags = -Wp,-MMD,$(depfile) $(KBUILD_USERCFLAGS) $(userccflags) \ 20 | $($(target-stem)-userccflags) 21 | user_ldflags = $(KBUILD_USERLDFLAGS) $(userldflags) $($(target-stem)-userldflags) 22 | user_ldlibs = $(userldlibs) $($(target-stem)-userldlibs) 23 | 24 | # Create an executable from a single .c file 25 | quiet_cmd_user_cc_c = CC [U] $@ 26 | cmd_user_cc_c = $(CC) $(user_ccflags) $(user_ldflags) -o $@ $< \ 27 | $(user_ldlibs) 28 | $(user-csingle): $(obj)/%: $(src)/%.c FORCE 29 | $(call if_changed_dep,user_cc_c) 30 | 31 | # Link an executable based on list of .o files 32 | quiet_cmd_user_ld = LD [U] $@ 33 | cmd_user_ld = $(CC) $(user_ldflags) -o $@ \ 34 | $(addprefix $(obj)/, $($(target-stem)-objs)) $(user_ldlibs) 35 | $(user-cmulti): FORCE 36 | $(call if_changed,user_ld) 37 | $(call multi_depend, $(user-cmulti), , -objs) 38 | 39 | # Create .o file from a .c file 40 | quiet_cmd_user_cc_o_c = CC [U] $@ 41 | cmd_user_cc_o_c = $(CC) $(user_ccflags) -c -o $@ $< 42 | $(user-cobjs): $(obj)/%.o: $(src)/%.c FORCE 43 | $(call if_changed_dep,user_cc_o_c) 44 | 45 | targets += $(user-csingle) $(user-cmulti) $(user-cobjs) 46 | -------------------------------------------------------------------------------- /kconfig/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | /conf 3 | /[gmnq]conf 4 | /[gmnq]conf-bin 5 | /[gmnq]conf-cflags 6 | /[gmnq]conf-libs 7 | /qconf-moc.cc 8 | -------------------------------------------------------------------------------- /kconfig/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # =========================================================================== 3 | # Kernel configuration targets 4 | # These targets are used from top-level makefile 5 | 6 | ifdef KBUILD_KCONFIG 7 | Kconfig := $(KBUILD_KCONFIG) 8 | else 9 | Kconfig := Kconfig 10 | endif 11 | 12 | ifndef KBUILD_DEFCONFIG 13 | KBUILD_DEFCONFIG := defconfig 14 | endif 15 | 16 | ifeq ($(quiet),silent_) 17 | silent := -s 18 | endif 19 | 20 | export KCONFIG_DEFCONFIG_LIST := 21 | ifndef cross_compiling 22 | kernel-release := $(shell uname -r) 23 | KCONFIG_DEFCONFIG_LIST += \ 24 | /lib/modules/$(kernel-release)/.config \ 25 | /etc/kernel-config \ 26 | /boot/config-$(kernel-release) 27 | endif 28 | KCONFIG_DEFCONFIG_LIST += arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) 29 | 30 | ifneq ($(findstring c, $(KBUILD_EXTRA_WARN)),) 31 | export KCONFIG_WARN_UNKNOWN_SYMBOLS=1 32 | endif 33 | 34 | ifneq ($(findstring e, $(KBUILD_EXTRA_WARN)),) 35 | export KCONFIG_WERROR=1 36 | endif 37 | 38 | # We need this, in case the user has it in its environment 39 | unexport CONFIG_ 40 | 41 | config-prog := conf 42 | menuconfig-prog := mconf 43 | nconfig-prog := nconf 44 | gconfig-prog := gconf 45 | xconfig-prog := qconf 46 | 47 | define config_rule 48 | PHONY += $(1) 49 | $(1): $(obj)/$($(1)-prog) 50 | $(Q)$$< $(silent) $(Kconfig) 51 | 52 | PHONY += build_$(1) 53 | build_$(1): $(obj)/$($(1)-prog) 54 | endef 55 | 56 | $(foreach c, config menuconfig nconfig gconfig xconfig, $(eval $(call config_rule,$(c)))) 57 | 58 | PHONY += localmodconfig localyesconfig 59 | localyesconfig localmodconfig: $(obj)/conf 60 | $(Q)$(PERL) $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config 61 | $(Q)if [ -f .config ]; then \ 62 | cmp -s .tmp.config .config || \ 63 | (mv -f .config .config.old.1; \ 64 | mv -f .tmp.config .config; \ 65 | $< $(silent) --oldconfig $(Kconfig); \ 66 | mv -f .config.old.1 .config.old) \ 67 | else \ 68 | mv -f .tmp.config .config; \ 69 | $< $(silent) --oldconfig $(Kconfig); \ 70 | fi 71 | $(Q)rm -f .tmp.config 72 | 73 | # These targets map 1:1 to the commandline options of 'conf' 74 | # 75 | # Note: 76 | # syncconfig has become an internal implementation detail and is now 77 | # deprecated for external use 78 | simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \ 79 | alldefconfig randconfig listnewconfig olddefconfig syncconfig \ 80 | helpnewconfig yes2modconfig mod2yesconfig mod2noconfig 81 | 82 | PHONY += $(simple-targets) 83 | 84 | $(simple-targets): $(obj)/conf 85 | $(Q)$< $(silent) --$@ $(Kconfig) 86 | 87 | PHONY += savedefconfig defconfig 88 | 89 | savedefconfig: $(obj)/conf 90 | $(Q)$< $(silent) --$@=defconfig $(Kconfig) 91 | 92 | defconfig: $(obj)/conf 93 | ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),) 94 | @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" 95 | $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) 96 | else 97 | @$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'" 98 | $(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG) 99 | endif 100 | 101 | %_defconfig: $(obj)/conf 102 | $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) 103 | 104 | configfiles = $(wildcard $(srctree)/kernel/configs/$(1) $(srctree)/arch/$(SRCARCH)/configs/$(1)) 105 | all-config-fragments = $(call configfiles,*.config) 106 | config-fragments = $(call configfiles,$@) 107 | 108 | %.config: $(obj)/conf 109 | $(if $(config-fragments),, $(error $@ fragment does not exists on this architecture)) 110 | $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m $(KCONFIG_CONFIG) $(config-fragments) 111 | $(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig 112 | 113 | PHONY += tinyconfig 114 | tinyconfig: 115 | $(Q)KCONFIG_ALLCONFIG=kernel/configs/tiny-base.config $(MAKE) -f $(srctree)/Makefile allnoconfig 116 | $(Q)$(MAKE) -f $(srctree)/Makefile tiny.config 117 | 118 | # CHECK: -o cache_dir= working? 119 | PHONY += testconfig 120 | testconfig: $(obj)/conf 121 | $(Q)$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \ 122 | -o cache_dir=$(abspath $(obj)/tests/.cache) \ 123 | $(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no) 124 | clean-files += tests/.cache 125 | 126 | # Help text used by make help 127 | help: 128 | @echo 'Configuration targets:' 129 | @echo ' config - Update current config utilising a line-oriented program' 130 | @echo ' nconfig - Update current config utilising a ncurses menu based program' 131 | @echo ' menuconfig - Update current config utilising a menu based program' 132 | @echo ' xconfig - Update current config utilising a Qt based front-end' 133 | @echo ' gconfig - Update current config utilising a GTK+ based front-end' 134 | @echo ' oldconfig - Update current config utilising a provided .config as base' 135 | @echo ' localmodconfig - Update current config disabling modules not loaded' 136 | @echo ' except those preserved by LMC_KEEP environment variable' 137 | @echo ' localyesconfig - Update current config converting local mods to core' 138 | @echo ' except those preserved by LMC_KEEP environment variable' 139 | @echo ' defconfig - New config with default from ARCH supplied defconfig' 140 | @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' 141 | @echo ' allnoconfig - New config where all options are answered with no' 142 | @echo ' allyesconfig - New config where all options are accepted with yes' 143 | @echo ' allmodconfig - New config selecting modules when possible' 144 | @echo ' alldefconfig - New config with all symbols set to default' 145 | @echo ' randconfig - New config with random answer to all options' 146 | @echo ' yes2modconfig - Change answers from yes to mod if possible' 147 | @echo ' mod2yesconfig - Change answers from mod to yes if possible' 148 | @echo ' mod2noconfig - Change answers from mod to no if possible' 149 | @echo ' listnewconfig - List new options' 150 | @echo ' helpnewconfig - List new options and help text' 151 | @echo ' olddefconfig - Same as oldconfig but sets new symbols to their' 152 | @echo ' default value without prompting' 153 | @echo ' tinyconfig - Configure the tiniest possible kernel' 154 | @echo ' testconfig - Run Kconfig unit tests (requires python3 and pytest)' 155 | @echo '' 156 | @echo 'Configuration topic targets:' 157 | @$(foreach f, $(all-config-fragments), \ 158 | if help=$$(grep -m1 '^# Help: ' $(f)); then \ 159 | printf ' %-25s - %s\n' '$(notdir $(f))' "$${help#*: }"; \ 160 | fi;) 161 | 162 | # =========================================================================== 163 | # object files used by all kconfig flavours 164 | common-objs := confdata.o expr.o lexer.lex.o menu.o parser.tab.o \ 165 | preprocess.o symbol.o util.o 166 | 167 | $(obj)/lexer.lex.o: $(obj)/parser.tab.h 168 | HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src) 169 | HOSTCFLAGS_parser.tab.o := -I $(srctree)/$(src) 170 | 171 | # conf: Used for defconfig, oldconfig and related targets 172 | hostprogs += conf 173 | conf-objs := conf.o $(common-objs) 174 | 175 | # nconf: Used for the nconfig target based on ncurses 176 | hostprogs += nconf 177 | nconf-objs := nconf.o nconf.gui.o mnconf-common.o $(common-objs) 178 | 179 | HOSTLDLIBS_nconf = $(call read-file, $(obj)/nconf-libs) 180 | HOSTCFLAGS_nconf.o = $(call read-file, $(obj)/nconf-cflags) 181 | HOSTCFLAGS_nconf.gui.o = $(call read-file, $(obj)/nconf-cflags) 182 | 183 | $(obj)/nconf: | $(obj)/nconf-libs 184 | $(obj)/nconf.o $(obj)/nconf.gui.o: | $(obj)/nconf-cflags 185 | 186 | # mconf: Used for the menuconfig target based on lxdialog 187 | hostprogs += mconf 188 | lxdialog := $(addprefix lxdialog/, \ 189 | checklist.o inputbox.o menubox.o textbox.o util.o yesno.o) 190 | mconf-objs := mconf.o $(lxdialog) mnconf-common.o $(common-objs) 191 | 192 | HOSTLDLIBS_mconf = $(call read-file, $(obj)/mconf-libs) 193 | $(foreach f, mconf.o $(lxdialog), \ 194 | $(eval HOSTCFLAGS_$f = $$(call read-file, $(obj)/mconf-cflags))) 195 | 196 | $(obj)/mconf: | $(obj)/mconf-libs 197 | $(addprefix $(obj)/, mconf.o $(lxdialog)): | $(obj)/mconf-cflags 198 | 199 | # qconf: Used for the xconfig target based on Qt 200 | hostprogs += qconf 201 | qconf-cxxobjs := qconf.o qconf-moc.o 202 | qconf-objs := images.o $(common-objs) 203 | 204 | HOSTLDLIBS_qconf = $(call read-file, $(obj)/qconf-libs) 205 | HOSTCXXFLAGS_qconf.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags) 206 | HOSTCXXFLAGS_qconf-moc.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags) 207 | $(obj)/qconf: | $(obj)/qconf-libs 208 | $(obj)/qconf.o $(obj)/qconf-moc.o: | $(obj)/qconf-cflags 209 | 210 | quiet_cmd_moc = MOC $@ 211 | cmd_moc = $(call read-file, $(obj)/qconf-bin)/moc $< -o $@ 212 | 213 | $(obj)/qconf-moc.cc: $(src)/qconf.h FORCE | $(obj)/qconf-bin 214 | $(call if_changed,moc) 215 | 216 | targets += qconf-moc.cc 217 | 218 | # gconf: Used for the gconfig target based on GTK+ 219 | hostprogs += gconf 220 | gconf-objs := gconf.o images.o $(common-objs) 221 | 222 | HOSTLDLIBS_gconf = $(call read-file, $(obj)/gconf-libs) 223 | HOSTCFLAGS_gconf.o = $(call read-file, $(obj)/gconf-cflags) 224 | 225 | $(obj)/gconf: | $(obj)/gconf-libs 226 | $(obj)/gconf.o: | $(obj)/gconf-cflags 227 | 228 | # check if necessary packages are available, and configure build flags 229 | cmd_conf_cfg = $< $(addprefix $(obj)/$*conf-, cflags libs bin); touch $(obj)/$*conf-bin 230 | 231 | $(obj)/%conf-cflags $(obj)/%conf-libs $(obj)/%conf-bin: $(src)/%conf-cfg.sh 232 | $(call cmd,conf_cfg) 233 | 234 | clean-files += *conf-cflags *conf-libs *conf-bin 235 | -------------------------------------------------------------------------------- /kconfig/array_size.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef ARRAY_SIZE_H 3 | #define ARRAY_SIZE_H 4 | 5 | /** 6 | * ARRAY_SIZE - get the number of elements in array @arr 7 | * @arr: array to be sized 8 | */ 9 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 10 | 11 | #endif /* ARRAY_SIZE_H */ 12 | -------------------------------------------------------------------------------- /kconfig/expr.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2002 Roman Zippel 4 | */ 5 | 6 | #ifndef EXPR_H 7 | #define EXPR_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #include 14 | #include 15 | #include "list_types.h" 16 | #ifndef __cplusplus 17 | #include 18 | #endif 19 | 20 | #include "list_types.h" 21 | 22 | typedef enum tristate { 23 | no, mod, yes 24 | } tristate; 25 | 26 | enum expr_type { 27 | E_NONE, E_OR, E_AND, E_NOT, 28 | E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ, 29 | E_LIST, E_SYMBOL, E_RANGE 30 | }; 31 | 32 | union expr_data { 33 | struct expr *expr; 34 | struct symbol *sym; 35 | }; 36 | 37 | struct expr { 38 | enum expr_type type; 39 | union expr_data left, right; 40 | }; 41 | 42 | #define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) 43 | #define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) 44 | #define EXPR_NOT(dep) (2-(dep)) 45 | 46 | #define expr_list_for_each_sym(l, e, s) \ 47 | for (e = (l); e && (s = e->right.sym); e = e->left.expr) 48 | 49 | struct expr_value { 50 | struct expr *expr; 51 | tristate tri; 52 | }; 53 | 54 | struct symbol_value { 55 | void *val; 56 | tristate tri; 57 | }; 58 | 59 | enum symbol_type { 60 | S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING 61 | }; 62 | 63 | /* enum values are used as index to symbol.def[] */ 64 | enum { 65 | S_DEF_USER, /* main user value */ 66 | S_DEF_AUTO, /* values read from auto.conf */ 67 | S_DEF_DEF3, /* Reserved for UI usage */ 68 | S_DEF_DEF4, /* Reserved for UI usage */ 69 | S_DEF_COUNT 70 | }; 71 | 72 | /* 73 | * Represents a configuration symbol. 74 | * 75 | * Choices are represented as a special kind of symbol and have the 76 | * SYMBOL_CHOICE bit set in 'flags'. 77 | */ 78 | struct symbol { 79 | /* link node for the hash table */ 80 | struct hlist_node node; 81 | 82 | /* The name of the symbol, e.g. "FOO" for 'config FOO' */ 83 | char *name; 84 | 85 | /* S_BOOLEAN, S_TRISTATE, ... */ 86 | enum symbol_type type; 87 | 88 | /* 89 | * The calculated value of the symbol. The SYMBOL_VALID bit is set in 90 | * 'flags' when this is up to date. Note that this value might differ 91 | * from the user value set in e.g. a .config file, due to visibility. 92 | */ 93 | struct symbol_value curr; 94 | 95 | /* 96 | * Values for the symbol provided from outside. def[S_DEF_USER] holds 97 | * the .config value. 98 | */ 99 | struct symbol_value def[S_DEF_COUNT]; 100 | 101 | /* 102 | * An upper bound on the tristate value the user can set for the symbol 103 | * if it is a boolean or tristate. Calculated from prompt dependencies, 104 | * which also inherit dependencies from enclosing menus, choices, and 105 | * ifs. If 'n', the user value will be ignored. 106 | * 107 | * Symbols lacking prompts always have visibility 'n'. 108 | */ 109 | tristate visible; 110 | 111 | /* config entries associated with this symbol */ 112 | struct list_head menus; 113 | 114 | /* SYMBOL_* flags */ 115 | int flags; 116 | 117 | /* List of properties. See prop_type. */ 118 | struct property *prop; 119 | 120 | /* Dependencies from enclosing menus, choices, and ifs */ 121 | struct expr_value dir_dep; 122 | 123 | /* Reverse dependencies through being selected by other symbols */ 124 | struct expr_value rev_dep; 125 | 126 | /* 127 | * "Weak" reverse dependencies through being implied by other symbols 128 | */ 129 | struct expr_value implied; 130 | }; 131 | 132 | #define SYMBOL_CONST 0x0001 /* symbol is const */ 133 | #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ 134 | #define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ 135 | #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ 136 | #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ 137 | #define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ 138 | #define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ 139 | #define SYMBOL_CHANGED 0x0400 /* ? */ 140 | #define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */ 141 | #define SYMBOL_NO_WRITE 0x1000 /* Symbol for internal use only; it will not be written */ 142 | #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ 143 | #define SYMBOL_WARNED 0x8000 /* warning has been issued */ 144 | 145 | /* Set when symbol.def[] is used */ 146 | #define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ 147 | #define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ 148 | #define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ 149 | #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ 150 | #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ 151 | 152 | /* choice values need to be set before calculating this symbol value */ 153 | #define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 154 | 155 | #define SYMBOL_MAXLENGTH 256 156 | 157 | /* A property represent the config options that can be associated 158 | * with a config "symbol". 159 | * Sample: 160 | * config FOO 161 | * default y 162 | * prompt "foo prompt" 163 | * select BAR 164 | * config BAZ 165 | * int "BAZ Value" 166 | * range 1..255 167 | * 168 | * Please, also check parser.y:print_symbol() when modifying the 169 | * list of property types! 170 | */ 171 | enum prop_type { 172 | P_UNKNOWN, 173 | P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ 174 | P_COMMENT, /* text associated with a comment */ 175 | P_MENU, /* prompt associated with a menu or menuconfig symbol */ 176 | P_DEFAULT, /* default y */ 177 | P_CHOICE, /* choice value */ 178 | P_SELECT, /* select BAR */ 179 | P_IMPLY, /* imply BAR */ 180 | P_RANGE, /* range 7..100 (for a symbol) */ 181 | P_SYMBOL, /* where a symbol is defined */ 182 | }; 183 | 184 | struct property { 185 | struct property *next; /* next property - null if last */ 186 | enum prop_type type; /* type of property */ 187 | const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ 188 | struct expr_value visible; 189 | struct expr *expr; /* the optional conditional part of the property */ 190 | struct menu *menu; /* the menu the property are associated with 191 | * valid for: P_SELECT, P_RANGE, P_CHOICE, 192 | * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ 193 | const char *filename; /* what file was this property defined */ 194 | int lineno; /* what lineno was this property defined */ 195 | }; 196 | 197 | #define for_all_properties(sym, st, tok) \ 198 | for (st = sym->prop; st; st = st->next) \ 199 | if (st->type == (tok)) 200 | #define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) 201 | #define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) 202 | #define for_all_prompts(sym, st) \ 203 | for (st = sym->prop; st; st = st->next) \ 204 | if (st->text) 205 | 206 | /* 207 | * Represents a node in the menu tree, as seen in e.g. menuconfig (though used 208 | * for all front ends). Each symbol, menu, etc. defined in the Kconfig files 209 | * gets a node. A symbol defined in multiple locations gets one node at each 210 | * location. 211 | */ 212 | struct menu { 213 | /* The next menu node at the same level */ 214 | struct menu *next; 215 | 216 | /* The parent menu node, corresponding to e.g. a menu or choice */ 217 | struct menu *parent; 218 | 219 | /* The first child menu node, for e.g. menus and choices */ 220 | struct menu *list; 221 | 222 | /* 223 | * The symbol associated with the menu node. Choices are implemented as 224 | * a special kind of symbol. NULL for menus, comments, and ifs. 225 | */ 226 | struct symbol *sym; 227 | 228 | struct list_head link; /* link to symbol::menus */ 229 | 230 | /* 231 | * The prompt associated with the node. This holds the prompt for a 232 | * symbol as well as the text for a menu or comment, along with the 233 | * type (P_PROMPT, P_MENU, etc.) 234 | */ 235 | struct property *prompt; 236 | 237 | /* 238 | * 'visible if' dependencies. If more than one is given, they will be 239 | * ANDed together. 240 | */ 241 | struct expr *visibility; 242 | 243 | /* 244 | * Ordinary dependencies from e.g. 'depends on' and 'if', ANDed 245 | * together 246 | */ 247 | struct expr *dep; 248 | 249 | /* MENU_* flags */ 250 | unsigned int flags; 251 | 252 | /* Any help text associated with the node */ 253 | char *help; 254 | 255 | /* The location where the menu node appears in the Kconfig files */ 256 | const char *filename; 257 | int lineno; 258 | 259 | /* For use by front ends that need to store auxiliary data */ 260 | void *data; 261 | }; 262 | 263 | /* 264 | * Set on a menu node when the corresponding symbol changes state in some way. 265 | * Can be checked by front ends. 266 | */ 267 | #define MENU_CHANGED 0x0001 268 | 269 | #define MENU_ROOT 0x0002 270 | 271 | struct jump_key { 272 | struct list_head entries; 273 | size_t offset; 274 | struct menu *target; 275 | }; 276 | 277 | extern struct symbol symbol_yes, symbol_no, symbol_mod; 278 | extern struct symbol *modules_sym; 279 | extern int cdebug; 280 | struct expr *expr_alloc_symbol(struct symbol *sym); 281 | struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); 282 | struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); 283 | struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); 284 | struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); 285 | struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); 286 | struct expr *expr_copy(const struct expr *org); 287 | void expr_free(struct expr *e); 288 | void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); 289 | int expr_eq(struct expr *e1, struct expr *e2); 290 | tristate expr_calc_value(struct expr *e); 291 | struct expr *expr_trans_bool(struct expr *e); 292 | struct expr *expr_eliminate_dups(struct expr *e); 293 | struct expr *expr_transform(struct expr *e); 294 | int expr_contains_symbol(struct expr *dep, struct symbol *sym); 295 | bool expr_depends_symbol(struct expr *dep, struct symbol *sym); 296 | struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); 297 | 298 | void expr_fprint(struct expr *e, FILE *out); 299 | struct gstr; /* forward */ 300 | void expr_gstr_print(struct expr *e, struct gstr *gs); 301 | void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, 302 | tristate pr_type, const char *title); 303 | 304 | static inline int expr_is_yes(struct expr *e) 305 | { 306 | return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); 307 | } 308 | 309 | static inline int expr_is_no(struct expr *e) 310 | { 311 | return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); 312 | } 313 | 314 | #ifdef __cplusplus 315 | } 316 | #endif 317 | 318 | #endif /* EXPR_H */ 319 | -------------------------------------------------------------------------------- /kconfig/gconf-cfg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0 3 | 4 | cflags=$1 5 | libs=$2 6 | 7 | PKG="gtk+-2.0 gmodule-2.0 libglade-2.0" 8 | 9 | if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then 10 | echo >&2 "*" 11 | echo >&2 "* 'make gconfig' requires '${HOSTPKG_CONFIG}'. Please install it." 12 | echo >&2 "*" 13 | exit 1 14 | fi 15 | 16 | if ! ${HOSTPKG_CONFIG} --exists $PKG; then 17 | echo >&2 "*" 18 | echo >&2 "* Unable to find the GTK+ installation. Please make sure that" 19 | echo >&2 "* the GTK+ 2.0 development package is correctly installed." 20 | echo >&2 "* You need $PKG" 21 | echo >&2 "*" 22 | exit 1 23 | fi 24 | 25 | if ! ${HOSTPKG_CONFIG} --atleast-version=2.0.0 gtk+-2.0; then 26 | echo >&2 "*" 27 | echo >&2 "* GTK+ is present but version >= 2.0.0 is required." 28 | echo >&2 "*" 29 | exit 1 30 | fi 31 | 32 | ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags} 33 | ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs} 34 | -------------------------------------------------------------------------------- /kconfig/hashtable.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | #ifndef HASHTABLE_H 3 | #define HASHTABLE_H 4 | 5 | #include "array_size.h" 6 | #include "list.h" 7 | 8 | #define HASH_SIZE(name) (ARRAY_SIZE(name)) 9 | 10 | #define HASHTABLE_DECLARE(name, size) struct hlist_head name[size] 11 | 12 | #define HASHTABLE_DEFINE(name, size) \ 13 | HASHTABLE_DECLARE(name, size) = \ 14 | { [0 ... ((size) - 1)] = HLIST_HEAD_INIT } 15 | 16 | #define hash_head(table, key) (&(table)[(key) % HASH_SIZE(table)]) 17 | 18 | /** 19 | * hash_add - add an object to a hashtable 20 | * @table: hashtable to add to 21 | * @node: the &struct hlist_node of the object to be added 22 | * @key: the key of the object to be added 23 | */ 24 | #define hash_add(table, node, key) \ 25 | hlist_add_head(node, hash_head(table, key)) 26 | 27 | /** 28 | * hash_for_each - iterate over a hashtable 29 | * @table: hashtable to iterate 30 | * @obj: the type * to use as a loop cursor for each entry 31 | * @member: the name of the hlist_node within the struct 32 | */ 33 | #define hash_for_each(table, obj, member) \ 34 | for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \ 35 | hlist_for_each_entry(obj, &table[_bkt], member) 36 | 37 | /** 38 | * hash_for_each_possible - iterate over all possible objects hashing to the 39 | * same bucket 40 | * @table: hashtable to iterate 41 | * @obj: the type * to use as a loop cursor for each entry 42 | * @member: the name of the hlist_node within the struct 43 | * @key: the key of the objects to iterate over 44 | */ 45 | #define hash_for_each_possible(table, obj, member, key) \ 46 | hlist_for_each_entry(obj, hash_head(table, key), member) 47 | 48 | #endif /* HASHTABLE_H */ 49 | -------------------------------------------------------------------------------- /kconfig/images.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2002 Roman Zippel 4 | */ 5 | 6 | #include "images.h" 7 | 8 | const char * const xpm_load[] = { 9 | "22 22 5 1", 10 | ". c None", 11 | "# c #000000", 12 | "c c #838100", 13 | "a c #ffff00", 14 | "b c #ffffff", 15 | "......................", 16 | "......................", 17 | "......................", 18 | "............####....#.", 19 | "...........#....##.##.", 20 | "..................###.", 21 | ".................####.", 22 | ".####...........#####.", 23 | "#abab##########.......", 24 | "#babababababab#.......", 25 | "#ababababababa#.......", 26 | "#babababababab#.......", 27 | "#ababab###############", 28 | "#babab##cccccccccccc##", 29 | "#abab##cccccccccccc##.", 30 | "#bab##cccccccccccc##..", 31 | "#ab##cccccccccccc##...", 32 | "#b##cccccccccccc##....", 33 | "###cccccccccccc##.....", 34 | "##cccccccccccc##......", 35 | "###############.......", 36 | "......................"}; 37 | 38 | const char * const xpm_save[] = { 39 | "22 22 5 1", 40 | ". c None", 41 | "# c #000000", 42 | "a c #838100", 43 | "b c #c5c2c5", 44 | "c c #cdb6d5", 45 | "......................", 46 | ".####################.", 47 | ".#aa#bbbbbbbbbbbb#bb#.", 48 | ".#aa#bbbbbbbbbbbb#bb#.", 49 | ".#aa#bbbbbbbbbcbb####.", 50 | ".#aa#bbbccbbbbbbb#aa#.", 51 | ".#aa#bbbccbbbbbbb#aa#.", 52 | ".#aa#bbbbbbbbbbbb#aa#.", 53 | ".#aa#bbbbbbbbbbbb#aa#.", 54 | ".#aa#bbbbbbbbbbbb#aa#.", 55 | ".#aa#bbbbbbbbbbbb#aa#.", 56 | ".#aaa############aaa#.", 57 | ".#aaaaaaaaaaaaaaaaaa#.", 58 | ".#aaaaaaaaaaaaaaaaaa#.", 59 | ".#aaa#############aa#.", 60 | ".#aaa#########bbb#aa#.", 61 | ".#aaa#########bbb#aa#.", 62 | ".#aaa#########bbb#aa#.", 63 | ".#aaa#########bbb#aa#.", 64 | ".#aaa#########bbb#aa#.", 65 | "..##################..", 66 | "......................"}; 67 | 68 | const char * const xpm_back[] = { 69 | "22 22 3 1", 70 | ". c None", 71 | "# c #000083", 72 | "a c #838183", 73 | "......................", 74 | "......................", 75 | "......................", 76 | "......................", 77 | "......................", 78 | "...........######a....", 79 | "..#......##########...", 80 | "..##...####......##a..", 81 | "..###.###.........##..", 82 | "..######..........##..", 83 | "..#####...........##..", 84 | "..######..........##..", 85 | "..#######.........##..", 86 | "..########.......##a..", 87 | "...............a###...", 88 | "...............###....", 89 | "......................", 90 | "......................", 91 | "......................", 92 | "......................", 93 | "......................", 94 | "......................"}; 95 | 96 | const char * const xpm_tree_view[] = { 97 | "22 22 2 1", 98 | ". c None", 99 | "# c #000000", 100 | "......................", 101 | "......................", 102 | "......#...............", 103 | "......#...............", 104 | "......#...............", 105 | "......#...............", 106 | "......#...............", 107 | "......########........", 108 | "......#...............", 109 | "......#...............", 110 | "......#...............", 111 | "......#...............", 112 | "......#...............", 113 | "......########........", 114 | "......#...............", 115 | "......#...............", 116 | "......#...............", 117 | "......#...............", 118 | "......#...............", 119 | "......########........", 120 | "......................", 121 | "......................"}; 122 | 123 | const char * const xpm_single_view[] = { 124 | "22 22 2 1", 125 | ". c None", 126 | "# c #000000", 127 | "......................", 128 | "......................", 129 | "..........#...........", 130 | "..........#...........", 131 | "..........#...........", 132 | "..........#...........", 133 | "..........#...........", 134 | "..........#...........", 135 | "..........#...........", 136 | "..........#...........", 137 | "..........#...........", 138 | "..........#...........", 139 | "..........#...........", 140 | "..........#...........", 141 | "..........#...........", 142 | "..........#...........", 143 | "..........#...........", 144 | "..........#...........", 145 | "..........#...........", 146 | "..........#...........", 147 | "......................", 148 | "......................"}; 149 | 150 | const char * const xpm_split_view[] = { 151 | "22 22 2 1", 152 | ". c None", 153 | "# c #000000", 154 | "......................", 155 | "......................", 156 | "......#......#........", 157 | "......#......#........", 158 | "......#......#........", 159 | "......#......#........", 160 | "......#......#........", 161 | "......#......#........", 162 | "......#......#........", 163 | "......#......#........", 164 | "......#......#........", 165 | "......#......#........", 166 | "......#......#........", 167 | "......#......#........", 168 | "......#......#........", 169 | "......#......#........", 170 | "......#......#........", 171 | "......#......#........", 172 | "......#......#........", 173 | "......#......#........", 174 | "......................", 175 | "......................"}; 176 | 177 | const char * const xpm_symbol_no[] = { 178 | "12 12 2 1", 179 | " c white", 180 | ". c black", 181 | " ", 182 | " .......... ", 183 | " . . ", 184 | " . . ", 185 | " . . ", 186 | " . . ", 187 | " . . ", 188 | " . . ", 189 | " . . ", 190 | " . . ", 191 | " .......... ", 192 | " "}; 193 | 194 | const char * const xpm_symbol_mod[] = { 195 | "12 12 2 1", 196 | " c white", 197 | ". c black", 198 | " ", 199 | " .......... ", 200 | " . . ", 201 | " . . ", 202 | " . .. . ", 203 | " . .... . ", 204 | " . .... . ", 205 | " . .. . ", 206 | " . . ", 207 | " . . ", 208 | " .......... ", 209 | " "}; 210 | 211 | const char * const xpm_symbol_yes[] = { 212 | "12 12 2 1", 213 | " c white", 214 | ". c black", 215 | " ", 216 | " .......... ", 217 | " . . ", 218 | " . . ", 219 | " . . . ", 220 | " . .. . ", 221 | " . . .. . ", 222 | " . .... . ", 223 | " . .. . ", 224 | " . . ", 225 | " .......... ", 226 | " "}; 227 | 228 | const char * const xpm_choice_no[] = { 229 | "12 12 2 1", 230 | " c white", 231 | ". c black", 232 | " ", 233 | " .... ", 234 | " .. .. ", 235 | " . . ", 236 | " . . ", 237 | " . . ", 238 | " . . ", 239 | " . . ", 240 | " . . ", 241 | " .. .. ", 242 | " .... ", 243 | " "}; 244 | 245 | const char * const xpm_choice_yes[] = { 246 | "12 12 2 1", 247 | " c white", 248 | ". c black", 249 | " ", 250 | " .... ", 251 | " .. .. ", 252 | " . . ", 253 | " . .. . ", 254 | " . .... . ", 255 | " . .... . ", 256 | " . .. . ", 257 | " . . ", 258 | " .. .. ", 259 | " .... ", 260 | " "}; 261 | 262 | const char * const xpm_menu[] = { 263 | "12 12 2 1", 264 | " c white", 265 | ". c black", 266 | " ", 267 | " .......... ", 268 | " . . ", 269 | " . .. . ", 270 | " . .... . ", 271 | " . ...... . ", 272 | " . ...... . ", 273 | " . .... . ", 274 | " . .. . ", 275 | " . . ", 276 | " .......... ", 277 | " "}; 278 | 279 | const char * const xpm_menu_inv[] = { 280 | "12 12 2 1", 281 | " c white", 282 | ". c black", 283 | " ", 284 | " .......... ", 285 | " .......... ", 286 | " .. ...... ", 287 | " .. .... ", 288 | " .. .. ", 289 | " .. .. ", 290 | " .. .... ", 291 | " .. ...... ", 292 | " .......... ", 293 | " .......... ", 294 | " "}; 295 | 296 | const char * const xpm_menuback[] = { 297 | "12 12 2 1", 298 | " c white", 299 | ". c black", 300 | " ", 301 | " .......... ", 302 | " . . ", 303 | " . .. . ", 304 | " . .... . ", 305 | " . ...... . ", 306 | " . ...... . ", 307 | " . .... . ", 308 | " . .. . ", 309 | " . . ", 310 | " .......... ", 311 | " "}; 312 | 313 | const char * const xpm_void[] = { 314 | "12 12 2 1", 315 | " c white", 316 | ". c black", 317 | " ", 318 | " ", 319 | " ", 320 | " ", 321 | " ", 322 | " ", 323 | " ", 324 | " ", 325 | " ", 326 | " ", 327 | " ", 328 | " "}; 329 | -------------------------------------------------------------------------------- /kconfig/images.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2002 Roman Zippel 4 | */ 5 | 6 | #ifndef IMAGES_H 7 | #define IMAGES_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | extern const char * const xpm_load[]; 14 | extern const char * const xpm_save[]; 15 | extern const char * const xpm_back[]; 16 | extern const char * const xpm_tree_view[]; 17 | extern const char * const xpm_single_view[]; 18 | extern const char * const xpm_split_view[]; 19 | extern const char * const xpm_symbol_no[]; 20 | extern const char * const xpm_symbol_mod[]; 21 | extern const char * const xpm_symbol_yes[]; 22 | extern const char * const xpm_choice_no[]; 23 | extern const char * const xpm_choice_yes[]; 24 | extern const char * const xpm_menu[]; 25 | extern const char * const xpm_menu_inv[]; 26 | extern const char * const xpm_menuback[]; 27 | extern const char * const xpm_void[]; 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif /* IMAGES_H */ 34 | -------------------------------------------------------------------------------- /kconfig/internal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | #ifndef INTERNAL_H 3 | #define INTERNAL_H 4 | 5 | #include "hashtable.h" 6 | 7 | #define SYMBOL_HASHSIZE (1U << 14) 8 | 9 | extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE); 10 | 11 | #define for_all_symbols(sym) \ 12 | hash_for_each(sym_hashtable, sym, node) 13 | 14 | struct menu; 15 | 16 | extern struct menu *current_menu, *current_entry; 17 | 18 | extern const char *cur_filename; 19 | extern int cur_lineno; 20 | 21 | #endif /* INTERNAL_H */ 22 | -------------------------------------------------------------------------------- /kconfig/lexer.l: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2002 Roman Zippel 4 | */ 5 | %option nostdinit noyywrap never-interactive full ecs 6 | %option 8bit nodefault yylineno 7 | %x ASSIGN_VAL HELP STRING 8 | %{ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "lkc.h" 17 | #include "preprocess.h" 18 | 19 | #include "parser.tab.h" 20 | 21 | #define YY_DECL static int yylex1(void) 22 | 23 | #define START_STRSIZE 16 24 | 25 | /* The Kconfig file currently being parsed. */ 26 | const char *cur_filename; 27 | 28 | /* 29 | * The line number of the current statement. This does not match yylineno. 30 | * yylineno is used by the lexer, while cur_lineno is used by the parser. 31 | */ 32 | int cur_lineno; 33 | 34 | static int prev_prev_token = T_EOL; 35 | static int prev_token = T_EOL; 36 | static char *text; 37 | static int text_size, text_asize; 38 | 39 | struct buffer { 40 | struct buffer *parent; 41 | YY_BUFFER_STATE state; 42 | int yylineno; 43 | const char *filename; 44 | int source_lineno; 45 | }; 46 | 47 | static struct buffer *current_buf; 48 | 49 | static int last_ts, first_ts; 50 | 51 | static char *expand_token(const char *in, size_t n); 52 | static void append_expanded_string(const char *in); 53 | static void zconf_endhelp(void); 54 | static void zconf_endfile(void); 55 | 56 | static void new_string(void) 57 | { 58 | text = xmalloc(START_STRSIZE); 59 | text_asize = START_STRSIZE; 60 | text_size = 0; 61 | *text = 0; 62 | } 63 | 64 | static void append_string(const char *str, int size) 65 | { 66 | int new_size = text_size + size + 1; 67 | if (new_size > text_asize) { 68 | new_size += START_STRSIZE - 1; 69 | new_size &= -START_STRSIZE; 70 | text = xrealloc(text, new_size); 71 | text_asize = new_size; 72 | } 73 | memcpy(text + text_size, str, size); 74 | text_size += size; 75 | text[text_size] = 0; 76 | } 77 | 78 | static void alloc_string(const char *str, int size) 79 | { 80 | text = xmalloc(size + 1); 81 | memcpy(text, str, size); 82 | text[size] = 0; 83 | } 84 | 85 | static void warn_ignored_character(char chr) 86 | { 87 | fprintf(stderr, 88 | "%s:%d:warning: ignoring unsupported character '%c'\n", 89 | cur_filename, yylineno, chr); 90 | } 91 | %} 92 | 93 | n [A-Za-z0-9_-] 94 | 95 | %% 96 | char open_quote = 0; 97 | 98 | #.* /* ignore comment */ 99 | [ \t]* /* whitespaces */ 100 | \\\n /* escaped new line */ 101 | \n return T_EOL; 102 | "bool" return T_BOOL; 103 | "choice" return T_CHOICE; 104 | "comment" return T_COMMENT; 105 | "config" return T_CONFIG; 106 | "def_bool" return T_DEF_BOOL; 107 | "def_tristate" return T_DEF_TRISTATE; 108 | "default" return T_DEFAULT; 109 | "depends" return T_DEPENDS; 110 | "endchoice" return T_ENDCHOICE; 111 | "endif" return T_ENDIF; 112 | "endmenu" return T_ENDMENU; 113 | "help" return T_HELP; 114 | "hex" return T_HEX; 115 | "if" return T_IF; 116 | "imply" return T_IMPLY; 117 | "int" return T_INT; 118 | "mainmenu" return T_MAINMENU; 119 | "menu" return T_MENU; 120 | "menuconfig" return T_MENUCONFIG; 121 | "modules" return T_MODULES; 122 | "on" return T_ON; 123 | "optional" return T_OPTIONAL; 124 | "prompt" return T_PROMPT; 125 | "range" return T_RANGE; 126 | "select" return T_SELECT; 127 | "source" return T_SOURCE; 128 | "string" return T_STRING; 129 | "tristate" return T_TRISTATE; 130 | "visible" return T_VISIBLE; 131 | "||" return T_OR; 132 | "&&" return T_AND; 133 | "=" return T_EQUAL; 134 | "!=" return T_UNEQUAL; 135 | "<" return T_LESS; 136 | "<=" return T_LESS_EQUAL; 137 | ">" return T_GREATER; 138 | ">=" return T_GREATER_EQUAL; 139 | "!" return T_NOT; 140 | "(" return T_OPEN_PAREN; 141 | ")" return T_CLOSE_PAREN; 142 | ":=" return T_COLON_EQUAL; 143 | "+=" return T_PLUS_EQUAL; 144 | \"|\' { 145 | open_quote = yytext[0]; 146 | new_string(); 147 | BEGIN(STRING); 148 | } 149 | {n}+ { 150 | alloc_string(yytext, yyleng); 151 | yylval.string = text; 152 | return T_WORD; 153 | } 154 | ({n}|$)+ { 155 | /* this token includes at least one '$' */ 156 | yylval.string = expand_token(yytext, yyleng); 157 | if (strlen(yylval.string)) 158 | return T_WORD; 159 | free(yylval.string); 160 | } 161 | . warn_ignored_character(*yytext); 162 | 163 | { 164 | [^[:blank:]\n]+.* { 165 | alloc_string(yytext, yyleng); 166 | yylval.string = text; 167 | return T_ASSIGN_VAL; 168 | } 169 | \n { BEGIN(INITIAL); return T_EOL; } 170 | . 171 | } 172 | 173 | { 174 | "$".* append_expanded_string(yytext); 175 | [^$'"\\\n]+ { 176 | append_string(yytext, yyleng); 177 | } 178 | \\.? { 179 | append_string(yytext + 1, yyleng - 1); 180 | } 181 | \'|\" { 182 | if (open_quote == yytext[0]) { 183 | BEGIN(INITIAL); 184 | yylval.string = text; 185 | return T_WORD_QUOTE; 186 | } else 187 | append_string(yytext, 1); 188 | } 189 | \n { 190 | fprintf(stderr, 191 | "%s:%d:warning: multi-line strings not supported\n", 192 | cur_filename, cur_lineno); 193 | unput('\n'); 194 | BEGIN(INITIAL); 195 | yylval.string = text; 196 | return T_WORD_QUOTE; 197 | } 198 | <> { 199 | BEGIN(INITIAL); 200 | yylval.string = text; 201 | return T_WORD_QUOTE; 202 | } 203 | } 204 | 205 | { 206 | [ \t]+ { 207 | int ts, i; 208 | 209 | ts = 0; 210 | for (i = 0; i < yyleng; i++) { 211 | if (yytext[i] == '\t') 212 | ts = (ts & ~7) + 8; 213 | else 214 | ts++; 215 | } 216 | last_ts = ts; 217 | if (first_ts) { 218 | if (ts < first_ts) { 219 | zconf_endhelp(); 220 | return T_HELPTEXT; 221 | } 222 | ts -= first_ts; 223 | while (ts > 8) { 224 | append_string(" ", 8); 225 | ts -= 8; 226 | } 227 | append_string(" ", ts); 228 | } 229 | } 230 | [ \t]*\n/[^ \t\n] { 231 | zconf_endhelp(); 232 | return T_HELPTEXT; 233 | } 234 | [ \t]*\n { 235 | append_string("\n", 1); 236 | } 237 | [^ \t\n].* { 238 | while (yyleng) { 239 | if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) 240 | break; 241 | yyleng--; 242 | } 243 | append_string(yytext, yyleng); 244 | if (!first_ts) 245 | first_ts = last_ts; 246 | } 247 | <> { 248 | zconf_endhelp(); 249 | return T_HELPTEXT; 250 | } 251 | } 252 | 253 | <> { 254 | BEGIN(INITIAL); 255 | 256 | if (prev_token != T_EOL && prev_token != T_HELPTEXT) 257 | fprintf(stderr, "%s:%d:warning: no new line at end of file\n", 258 | cur_filename, yylineno); 259 | 260 | if (current_buf) { 261 | zconf_endfile(); 262 | return T_EOL; 263 | } 264 | fclose(yyin); 265 | yyterminate(); 266 | } 267 | 268 | %% 269 | 270 | /* second stage lexer */ 271 | int yylex(void) 272 | { 273 | int token; 274 | 275 | repeat: 276 | token = yylex1(); 277 | 278 | if (prev_token == T_EOL || prev_token == T_HELPTEXT) { 279 | if (token == T_EOL) 280 | /* Do not pass unneeded T_EOL to the parser. */ 281 | goto repeat; 282 | else 283 | /* 284 | * For the parser, update lineno at the first token 285 | * of each statement. Generally, \n is a statement 286 | * terminator in Kconfig, but it is not always true 287 | * because \n could be escaped by a backslash. 288 | */ 289 | cur_lineno = yylineno; 290 | } 291 | 292 | if (prev_prev_token == T_EOL && prev_token == T_WORD && 293 | (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL)) 294 | BEGIN(ASSIGN_VAL); 295 | 296 | prev_prev_token = prev_token; 297 | prev_token = token; 298 | 299 | return token; 300 | } 301 | 302 | static char *expand_token(const char *in, size_t n) 303 | { 304 | char *out; 305 | int c; 306 | char c2; 307 | const char *rest, *end; 308 | 309 | new_string(); 310 | append_string(in, n); 311 | 312 | /* 313 | * get the whole line because we do not know the end of token. 314 | * input() returns 0 (not EOF!) when it reachs the end of file. 315 | */ 316 | while ((c = input()) != 0) { 317 | if (c == '\n') { 318 | unput(c); 319 | break; 320 | } 321 | c2 = c; 322 | append_string(&c2, 1); 323 | } 324 | 325 | rest = text; 326 | out = expand_one_token(&rest); 327 | 328 | /* push back unused characters to the input stream */ 329 | end = rest + strlen(rest); 330 | while (end > rest) 331 | unput(*--end); 332 | 333 | free(text); 334 | 335 | return out; 336 | } 337 | 338 | static void append_expanded_string(const char *str) 339 | { 340 | const char *end; 341 | char *res; 342 | 343 | str++; 344 | 345 | res = expand_dollar(&str); 346 | 347 | /* push back unused characters to the input stream */ 348 | end = str + strlen(str); 349 | while (end > str) 350 | unput(*--end); 351 | 352 | append_string(res, strlen(res)); 353 | 354 | free(res); 355 | } 356 | 357 | void zconf_starthelp(void) 358 | { 359 | new_string(); 360 | last_ts = first_ts = 0; 361 | BEGIN(HELP); 362 | } 363 | 364 | static void zconf_endhelp(void) 365 | { 366 | yylval.string = text; 367 | BEGIN(INITIAL); 368 | } 369 | 370 | 371 | /* 372 | * Try to open specified file with following names: 373 | * ./name 374 | * $(srctree)/name 375 | * The latter is used when srctree is separate from objtree 376 | * when compiling the kernel. 377 | * Return NULL if file is not found. 378 | */ 379 | FILE *zconf_fopen(const char *name) 380 | { 381 | char *env, fullname[PATH_MAX+1]; 382 | FILE *f; 383 | 384 | f = fopen(name, "r"); 385 | if (!f && name != NULL && name[0] != '/') { 386 | env = getenv(SRCTREE); 387 | if (env) { 388 | snprintf(fullname, sizeof(fullname), 389 | "%s/%s", env, name); 390 | f = fopen(fullname, "r"); 391 | } 392 | } 393 | return f; 394 | } 395 | 396 | void zconf_initscan(const char *name) 397 | { 398 | yyin = zconf_fopen(name); 399 | if (!yyin) { 400 | fprintf(stderr, "can't find file %s\n", name); 401 | exit(1); 402 | } 403 | 404 | cur_filename = file_lookup(name); 405 | yylineno = 1; 406 | } 407 | 408 | void zconf_nextfile(const char *name) 409 | { 410 | struct buffer *buf = xmalloc(sizeof(*buf)); 411 | bool recur_include = false; 412 | 413 | buf->state = YY_CURRENT_BUFFER; 414 | buf->yylineno = yylineno; 415 | buf->filename = cur_filename; 416 | buf->source_lineno = cur_lineno; 417 | buf->parent = current_buf; 418 | current_buf = buf; 419 | yyin = zconf_fopen(name); 420 | if (!yyin) { 421 | fprintf(stderr, "%s:%d: can't open file \"%s\"\n", 422 | cur_filename, cur_lineno, name); 423 | exit(1); 424 | } 425 | yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); 426 | 427 | for (buf = current_buf; buf; buf = buf->parent) { 428 | if (!strcmp(buf->filename, name)) 429 | recur_include = true; 430 | } 431 | 432 | if (recur_include) { 433 | fprintf(stderr, 434 | "Recursive inclusion detected.\n" 435 | "Inclusion path:\n" 436 | " current file : %s\n", name); 437 | 438 | for (buf = current_buf; buf; buf = buf->parent) 439 | fprintf(stderr, " included from: %s:%d\n", 440 | buf->filename, buf->source_lineno); 441 | exit(1); 442 | } 443 | 444 | yylineno = 1; 445 | cur_filename = file_lookup(name); 446 | } 447 | 448 | static void zconf_endfile(void) 449 | { 450 | struct buffer *tmp; 451 | 452 | fclose(yyin); 453 | yy_delete_buffer(YY_CURRENT_BUFFER); 454 | yy_switch_to_buffer(current_buf->state); 455 | yylineno = current_buf->yylineno; 456 | cur_filename = current_buf->filename; 457 | tmp = current_buf; 458 | current_buf = current_buf->parent; 459 | free(tmp); 460 | } 461 | -------------------------------------------------------------------------------- /kconfig/list.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef LIST_H 3 | #define LIST_H 4 | 5 | #include 6 | 7 | #include "list_types.h" 8 | 9 | /* Are two types/vars the same type (ignoring qualifiers)? */ 10 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) 11 | 12 | /** 13 | * container_of - cast a member of a structure out to the containing structure 14 | * @ptr: the pointer to the member. 15 | * @type: the type of the container struct this is embedded in. 16 | * @member: the name of the member within the struct. 17 | * 18 | */ 19 | #define container_of(ptr, type, member) ({ \ 20 | void *__mptr = (void *)(ptr); \ 21 | _Static_assert(__same_type(*(ptr), ((type *)0)->member) || \ 22 | __same_type(*(ptr), void), \ 23 | "pointer type mismatch in container_of()"); \ 24 | ((type *)(__mptr - offsetof(type, member))); }) 25 | 26 | #define LIST_POISON1 ((void *) 0x100) 27 | #define LIST_POISON2 ((void *) 0x122) 28 | 29 | /* 30 | * Circular doubly linked list implementation. 31 | * 32 | * Some of the internal functions ("__xxx") are useful when 33 | * manipulating whole lists rather than single entries, as 34 | * sometimes we already know the next/prev entries and we can 35 | * generate better code by using them directly rather than 36 | * using the generic single-entry routines. 37 | */ 38 | 39 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 40 | 41 | #define LIST_HEAD(name) \ 42 | struct list_head name = LIST_HEAD_INIT(name) 43 | 44 | /** 45 | * INIT_LIST_HEAD - Initialize a list_head structure 46 | * @list: list_head structure to be initialized. 47 | * 48 | * Initializes the list_head to point to itself. If it is a list header, 49 | * the result is an empty list. 50 | */ 51 | static inline void INIT_LIST_HEAD(struct list_head *list) 52 | { 53 | list->next = list; 54 | list->prev = list; 55 | } 56 | 57 | /* 58 | * Insert a new entry between two known consecutive entries. 59 | * 60 | * This is only for internal list manipulation where we know 61 | * the prev/next entries already! 62 | */ 63 | static inline void __list_add(struct list_head *new, 64 | struct list_head *prev, 65 | struct list_head *next) 66 | { 67 | next->prev = new; 68 | new->next = next; 69 | new->prev = prev; 70 | prev->next = new; 71 | } 72 | 73 | /** 74 | * list_add - add a new entry 75 | * @new: new entry to be added 76 | * @head: list head to add it after 77 | * 78 | * Insert a new entry after the specified head. 79 | * This is good for implementing stacks. 80 | */ 81 | static inline void list_add(struct list_head *new, struct list_head *head) 82 | { 83 | __list_add(new, head, head->next); 84 | } 85 | 86 | /** 87 | * list_add_tail - add a new entry 88 | * @new: new entry to be added 89 | * @head: list head to add it before 90 | * 91 | * Insert a new entry before the specified head. 92 | * This is useful for implementing queues. 93 | */ 94 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 95 | { 96 | __list_add(new, head->prev, head); 97 | } 98 | 99 | /* 100 | * Delete a list entry by making the prev/next entries 101 | * point to each other. 102 | * 103 | * This is only for internal list manipulation where we know 104 | * the prev/next entries already! 105 | */ 106 | static inline void __list_del(struct list_head *prev, struct list_head *next) 107 | { 108 | next->prev = prev; 109 | prev->next = next; 110 | } 111 | 112 | static inline void __list_del_entry(struct list_head *entry) 113 | { 114 | __list_del(entry->prev, entry->next); 115 | } 116 | 117 | /** 118 | * list_del - deletes entry from list. 119 | * @entry: the element to delete from the list. 120 | * Note: list_empty() on entry does not return true after this, the entry is 121 | * in an undefined state. 122 | */ 123 | static inline void list_del(struct list_head *entry) 124 | { 125 | __list_del_entry(entry); 126 | entry->next = LIST_POISON1; 127 | entry->prev = LIST_POISON2; 128 | } 129 | 130 | /** 131 | * list_is_head - tests whether @list is the list @head 132 | * @list: the entry to test 133 | * @head: the head of the list 134 | */ 135 | static inline int list_is_head(const struct list_head *list, const struct list_head *head) 136 | { 137 | return list == head; 138 | } 139 | 140 | /** 141 | * list_empty - tests whether a list is empty 142 | * @head: the list to test. 143 | */ 144 | static inline int list_empty(const struct list_head *head) 145 | { 146 | return head->next == head; 147 | } 148 | 149 | /** 150 | * list_entry - get the struct for this entry 151 | * @ptr: the &struct list_head pointer. 152 | * @type: the type of the struct this is embedded in. 153 | * @member: the name of the list_head within the struct. 154 | */ 155 | #define list_entry(ptr, type, member) \ 156 | container_of(ptr, type, member) 157 | 158 | /** 159 | * list_first_entry - get the first element from a list 160 | * @ptr: the list head to take the element from. 161 | * @type: the type of the struct this is embedded in. 162 | * @member: the name of the list_head within the struct. 163 | * 164 | * Note, that list is expected to be not empty. 165 | */ 166 | #define list_first_entry(ptr, type, member) \ 167 | list_entry((ptr)->next, type, member) 168 | 169 | /** 170 | * list_next_entry - get the next element in list 171 | * @pos: the type * to cursor 172 | * @member: the name of the list_head within the struct. 173 | */ 174 | #define list_next_entry(pos, member) \ 175 | list_entry((pos)->member.next, typeof(*(pos)), member) 176 | 177 | /** 178 | * list_entry_is_head - test if the entry points to the head of the list 179 | * @pos: the type * to cursor 180 | * @head: the head for your list. 181 | * @member: the name of the list_head within the struct. 182 | */ 183 | #define list_entry_is_head(pos, head, member) \ 184 | (&pos->member == (head)) 185 | 186 | /** 187 | * list_for_each_entry - iterate over list of given type 188 | * @pos: the type * to use as a loop cursor. 189 | * @head: the head for your list. 190 | * @member: the name of the list_head within the struct. 191 | */ 192 | #define list_for_each_entry(pos, head, member) \ 193 | for (pos = list_first_entry(head, typeof(*pos), member); \ 194 | !list_entry_is_head(pos, head, member); \ 195 | pos = list_next_entry(pos, member)) 196 | 197 | /** 198 | * list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry 199 | * @pos: the type * to use as a loop cursor. 200 | * @n: another type * to use as temporary storage 201 | * @head: the head for your list. 202 | * @member: the name of the list_head within the struct. 203 | */ 204 | #define list_for_each_entry_safe(pos, n, head, member) \ 205 | for (pos = list_first_entry(head, typeof(*pos), member), \ 206 | n = list_next_entry(pos, member); \ 207 | !list_entry_is_head(pos, head, member); \ 208 | pos = n, n = list_next_entry(n, member)) 209 | 210 | /* 211 | * Double linked lists with a single pointer list head. 212 | * Mostly useful for hash tables where the two pointer list head is 213 | * too wasteful. 214 | * You lose the ability to access the tail in O(1). 215 | */ 216 | 217 | #define HLIST_HEAD_INIT { .first = NULL } 218 | 219 | /** 220 | * hlist_add_head - add a new entry at the beginning of the hlist 221 | * @n: new entry to be added 222 | * @h: hlist head to add it after 223 | * 224 | * Insert a new entry after the specified head. 225 | * This is good for implementing stacks. 226 | */ 227 | static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) 228 | { 229 | struct hlist_node *first = h->first; 230 | 231 | n->next = first; 232 | if (first) 233 | first->pprev = &n->next; 234 | h->first = n; 235 | n->pprev = &h->first; 236 | } 237 | 238 | #define hlist_entry(ptr, type, member) container_of(ptr, type, member) 239 | 240 | #define hlist_entry_safe(ptr, type, member) \ 241 | ({ typeof(ptr) ____ptr = (ptr); \ 242 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ 243 | }) 244 | 245 | /** 246 | * hlist_for_each_entry - iterate over list of given type 247 | * @pos: the type * to use as a loop cursor. 248 | * @head: the head for your list. 249 | * @member: the name of the hlist_node within the struct. 250 | */ 251 | #define hlist_for_each_entry(pos, head, member) \ 252 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ 253 | pos; \ 254 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) 255 | 256 | #endif /* LIST_H */ 257 | -------------------------------------------------------------------------------- /kconfig/list_types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef LIST_TYPES_H 3 | #define LIST_TYPES_H 4 | 5 | struct list_head { 6 | struct list_head *next, *prev; 7 | }; 8 | 9 | struct hlist_head { 10 | struct hlist_node *first; 11 | }; 12 | 13 | struct hlist_node { 14 | struct hlist_node *next, **pprev; 15 | }; 16 | 17 | #endif /* LIST_TYPES_H */ 18 | -------------------------------------------------------------------------------- /kconfig/lkc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2002 Roman Zippel 4 | */ 5 | 6 | #ifndef LKC_H 7 | #define LKC_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "expr.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #include "lkc_proto.h" 20 | 21 | #define SRCTREE "srctree" 22 | 23 | #ifndef CONFIG_ 24 | #define CONFIG_ "CONFIG_" 25 | #endif 26 | static inline const char *CONFIG_prefix(void) 27 | { 28 | return getenv( "CONFIG_" ) ?: CONFIG_; 29 | } 30 | #undef CONFIG_ 31 | #define CONFIG_ CONFIG_prefix() 32 | 33 | extern int yylineno; 34 | void zconfdump(FILE *out); 35 | void zconf_starthelp(void); 36 | FILE *zconf_fopen(const char *name); 37 | void zconf_initscan(const char *name); 38 | void zconf_nextfile(const char *name); 39 | 40 | /* confdata.c */ 41 | extern struct gstr autoconf_cmd; 42 | const char *conf_get_configname(void); 43 | void set_all_choice_values(struct symbol *csym); 44 | 45 | /* confdata.c and expr.c */ 46 | static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) 47 | { 48 | assert(len != 0); 49 | 50 | if (fwrite(str, len, count, out) != count) 51 | fprintf(stderr, "Error in writing or end of file.\n"); 52 | } 53 | 54 | /* util.c */ 55 | unsigned int strhash(const char *s); 56 | const char *file_lookup(const char *name); 57 | void *xmalloc(size_t size); 58 | void *xcalloc(size_t nmemb, size_t size); 59 | void *xrealloc(void *p, size_t size); 60 | char *xstrdup(const char *s); 61 | char *xstrndup(const char *s, size_t n); 62 | 63 | /* lexer.l */ 64 | int yylex(void); 65 | 66 | struct gstr { 67 | size_t len; 68 | char *s; 69 | /* 70 | * when max_width is not zero long lines in string s (if any) get 71 | * wrapped not to exceed the max_width value 72 | */ 73 | int max_width; 74 | }; 75 | struct gstr str_new(void); 76 | void str_free(struct gstr *gs); 77 | void str_append(struct gstr *gs, const char *s); 78 | void str_printf(struct gstr *gs, const char *fmt, ...); 79 | char *str_get(struct gstr *gs); 80 | 81 | /* menu.c */ 82 | void _menu_init(void); 83 | void menu_warn(struct menu *menu, const char *fmt, ...); 84 | struct menu *menu_add_menu(void); 85 | void menu_end_menu(void); 86 | void menu_add_entry(struct symbol *sym); 87 | void menu_add_dep(struct expr *dep); 88 | void menu_add_visibility(struct expr *dep); 89 | struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); 90 | void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); 91 | void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); 92 | void menu_finalize(void); 93 | void menu_set_type(int type); 94 | 95 | extern struct menu rootmenu; 96 | 97 | bool menu_is_empty(struct menu *menu); 98 | bool menu_is_visible(struct menu *menu); 99 | bool menu_has_prompt(struct menu *menu); 100 | const char *menu_get_prompt(struct menu *menu); 101 | struct menu *menu_get_parent_menu(struct menu *menu); 102 | int get_jump_key_char(void); 103 | struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); 104 | void menu_get_ext_help(struct menu *menu, struct gstr *help); 105 | 106 | /* symbol.c */ 107 | void sym_clear_all_valid(void); 108 | struct symbol *sym_choice_default(struct symbol *sym); 109 | struct property *sym_get_range_prop(struct symbol *sym); 110 | const char *sym_get_string_default(struct symbol *sym); 111 | struct symbol *sym_check_deps(struct symbol *sym); 112 | struct symbol *prop_get_symbol(struct property *prop); 113 | 114 | static inline tristate sym_get_tristate_value(struct symbol *sym) 115 | { 116 | return sym->curr.tri; 117 | } 118 | 119 | 120 | static inline struct symbol *sym_get_choice_value(struct symbol *sym) 121 | { 122 | return (struct symbol *)sym->curr.val; 123 | } 124 | 125 | static inline bool sym_is_choice(struct symbol *sym) 126 | { 127 | return sym->flags & SYMBOL_CHOICE ? true : false; 128 | } 129 | 130 | static inline bool sym_is_choice_value(struct symbol *sym) 131 | { 132 | return sym->flags & SYMBOL_CHOICEVAL ? true : false; 133 | } 134 | 135 | static inline bool sym_is_optional(struct symbol *sym) 136 | { 137 | return sym->flags & SYMBOL_OPTIONAL ? true : false; 138 | } 139 | 140 | static inline bool sym_has_value(struct symbol *sym) 141 | { 142 | return sym->flags & SYMBOL_DEF_USER ? true : false; 143 | } 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif /* LKC_H */ 150 | -------------------------------------------------------------------------------- /kconfig/lkc_proto.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef LKC_PROTO_H 3 | #define LKC_PROTO_H 4 | 5 | #include 6 | 7 | /* confdata.c */ 8 | void conf_parse(const char *name); 9 | int conf_read(const char *name); 10 | int conf_read_simple(const char *name, int); 11 | int conf_write_defconfig(const char *name); 12 | int conf_write(const char *name); 13 | int conf_write_autoconf(int overwrite); 14 | void conf_set_changed(bool val); 15 | bool conf_get_changed(void); 16 | void conf_set_changed_callback(void (*fn)(void)); 17 | void conf_set_message_callback(void (*fn)(const char *s)); 18 | bool conf_errors(void); 19 | 20 | /* symbol.c */ 21 | struct symbol * sym_lookup(const char *name, int flags); 22 | struct symbol * sym_find(const char *name); 23 | void print_symbol_for_listconfig(struct symbol *sym); 24 | struct symbol ** sym_re_search(const char *pattern); 25 | const char * sym_type_name(enum symbol_type type); 26 | void sym_calc_value(struct symbol *sym); 27 | bool sym_dep_errors(void); 28 | enum symbol_type sym_get_type(struct symbol *sym); 29 | bool sym_tristate_within_range(struct symbol *sym,tristate tri); 30 | bool sym_set_tristate_value(struct symbol *sym,tristate tri); 31 | tristate sym_toggle_tristate_value(struct symbol *sym); 32 | bool sym_string_valid(struct symbol *sym, const char *newval); 33 | bool sym_string_within_range(struct symbol *sym, const char *str); 34 | bool sym_set_string_value(struct symbol *sym, const char *newval); 35 | bool sym_is_changeable(struct symbol *sym); 36 | struct property * sym_get_choice_prop(struct symbol *sym); 37 | const char * sym_get_string_value(struct symbol *sym); 38 | 39 | const char * prop_get_type_name(enum prop_type type); 40 | 41 | /* expr.c */ 42 | void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); 43 | 44 | #endif /* LKC_PROTO_H */ 45 | -------------------------------------------------------------------------------- /kconfig/lxdialog/BIG.FAT.WARNING: -------------------------------------------------------------------------------- 1 | This is NOT the official version of dialog. This version has been 2 | significantly modified from the original. It is for use by the Linux 3 | kernel configuration script. Please do not bother Savio Lam with 4 | questions about this program. 5 | -------------------------------------------------------------------------------- /kconfig/lxdialog/checklist.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0+ 2 | /* 3 | * checklist.c -- implements the checklist box 4 | * 5 | * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 6 | * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension 7 | * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two 8 | * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) 9 | */ 10 | 11 | #include "dialog.h" 12 | 13 | static int list_width, check_x, item_x; 14 | 15 | /* 16 | * Print list item 17 | */ 18 | static void print_item(WINDOW * win, int choice, int selected) 19 | { 20 | int i; 21 | char *list_item = malloc(list_width + 1); 22 | 23 | strncpy(list_item, item_str(), list_width - item_x); 24 | list_item[list_width - item_x] = '\0'; 25 | 26 | /* Clear 'residue' of last item */ 27 | wattrset(win, dlg.menubox.atr); 28 | wmove(win, choice, 0); 29 | for (i = 0; i < list_width; i++) 30 | waddch(win, ' '); 31 | 32 | wmove(win, choice, check_x); 33 | wattrset(win, selected ? dlg.check_selected.atr 34 | : dlg.check.atr); 35 | if (!item_is_tag(':')) 36 | wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' '); 37 | 38 | wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr); 39 | mvwaddch(win, choice, item_x, list_item[0]); 40 | wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); 41 | waddstr(win, list_item + 1); 42 | if (selected) { 43 | wmove(win, choice, check_x + 1); 44 | wrefresh(win); 45 | } 46 | free(list_item); 47 | } 48 | 49 | /* 50 | * Print the scroll indicators. 51 | */ 52 | static void print_arrows(WINDOW * win, int choice, int item_no, int scroll, 53 | int y, int x, int height) 54 | { 55 | wmove(win, y, x); 56 | 57 | if (scroll > 0) { 58 | wattrset(win, dlg.uarrow.atr); 59 | waddch(win, ACS_UARROW); 60 | waddstr(win, "(-)"); 61 | } else { 62 | wattrset(win, dlg.menubox.atr); 63 | waddch(win, ACS_HLINE); 64 | waddch(win, ACS_HLINE); 65 | waddch(win, ACS_HLINE); 66 | waddch(win, ACS_HLINE); 67 | } 68 | 69 | y = y + height + 1; 70 | wmove(win, y, x); 71 | 72 | if ((height < item_no) && (scroll + choice < item_no - 1)) { 73 | wattrset(win, dlg.darrow.atr); 74 | waddch(win, ACS_DARROW); 75 | waddstr(win, "(+)"); 76 | } else { 77 | wattrset(win, dlg.menubox_border.atr); 78 | waddch(win, ACS_HLINE); 79 | waddch(win, ACS_HLINE); 80 | waddch(win, ACS_HLINE); 81 | waddch(win, ACS_HLINE); 82 | } 83 | } 84 | 85 | /* 86 | * Display the termination buttons 87 | */ 88 | static void print_buttons(WINDOW * dialog, int height, int width, int selected) 89 | { 90 | int x = width / 2 - 11; 91 | int y = height - 2; 92 | 93 | print_button(dialog, "Select", y, x, selected == 0); 94 | print_button(dialog, " Help ", y, x + 14, selected == 1); 95 | 96 | wmove(dialog, y, x + 1 + 14 * selected); 97 | wrefresh(dialog); 98 | } 99 | 100 | /* 101 | * Display a dialog box with a list of options that can be turned on or off 102 | * in the style of radiolist (only one option turned on at a time). 103 | */ 104 | int dialog_checklist(const char *title, const char *prompt, int height, 105 | int width, int list_height) 106 | { 107 | int i, x, y, box_x, box_y; 108 | int key = 0, button = 0, choice = 0, scroll = 0, max_choice; 109 | WINDOW *dialog, *list; 110 | 111 | /* which item to highlight */ 112 | item_foreach() { 113 | if (item_is_tag('X')) 114 | choice = item_n(); 115 | if (item_is_selected()) { 116 | choice = item_n(); 117 | break; 118 | } 119 | } 120 | 121 | do_resize: 122 | if (getmaxy(stdscr) < (height + CHECKLIST_HEIGHT_MIN)) 123 | return -ERRDISPLAYTOOSMALL; 124 | if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN)) 125 | return -ERRDISPLAYTOOSMALL; 126 | 127 | max_choice = MIN(list_height, item_count()); 128 | 129 | /* center dialog box on screen */ 130 | x = (getmaxx(stdscr) - width) / 2; 131 | y = (getmaxy(stdscr) - height) / 2; 132 | 133 | draw_shadow(stdscr, y, x, height, width); 134 | 135 | dialog = newwin(height, width, y, x); 136 | keypad(dialog, TRUE); 137 | 138 | draw_box(dialog, 0, 0, height, width, 139 | dlg.dialog.atr, dlg.border.atr); 140 | wattrset(dialog, dlg.border.atr); 141 | mvwaddch(dialog, height - 3, 0, ACS_LTEE); 142 | for (i = 0; i < width - 2; i++) 143 | waddch(dialog, ACS_HLINE); 144 | wattrset(dialog, dlg.dialog.atr); 145 | waddch(dialog, ACS_RTEE); 146 | 147 | print_title(dialog, title, width); 148 | 149 | wattrset(dialog, dlg.dialog.atr); 150 | print_autowrap(dialog, prompt, width - 2, 1, 3); 151 | 152 | list_width = width - 6; 153 | box_y = height - list_height - 5; 154 | box_x = (width - list_width) / 2 - 1; 155 | 156 | /* create new window for the list */ 157 | list = subwin(dialog, list_height, list_width, y + box_y + 1, 158 | x + box_x + 1); 159 | 160 | keypad(list, TRUE); 161 | 162 | /* draw a box around the list items */ 163 | draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, 164 | dlg.menubox_border.atr, dlg.menubox.atr); 165 | 166 | /* Find length of longest item in order to center checklist */ 167 | check_x = 0; 168 | item_foreach() 169 | check_x = MAX(check_x, strlen(item_str()) + 4); 170 | check_x = MIN(check_x, list_width); 171 | 172 | check_x = (list_width - check_x) / 2; 173 | item_x = check_x + 4; 174 | 175 | if (choice >= list_height) { 176 | scroll = choice - list_height + 1; 177 | choice -= scroll; 178 | } 179 | 180 | /* Print the list */ 181 | for (i = 0; i < max_choice; i++) { 182 | item_set(scroll + i); 183 | print_item(list, i, i == choice); 184 | } 185 | 186 | print_arrows(dialog, choice, item_count(), scroll, 187 | box_y, box_x + check_x + 5, list_height); 188 | 189 | print_buttons(dialog, height, width, 0); 190 | 191 | wmove(list, choice, check_x + 1); 192 | wrefresh(list); 193 | 194 | while (key != KEY_ESC) { 195 | key = wgetch(dialog); 196 | 197 | for (i = 0; i < max_choice; i++) { 198 | item_set(i + scroll); 199 | if (toupper(key) == toupper(item_str()[0])) 200 | break; 201 | } 202 | 203 | if (i < max_choice || key == KEY_UP || key == KEY_DOWN || 204 | key == '+' || key == '-') { 205 | if (key == KEY_UP || key == '-') { 206 | if (!choice) { 207 | if (!scroll) 208 | continue; 209 | /* Scroll list down */ 210 | if (list_height > 1) { 211 | /* De-highlight current first item */ 212 | item_set(scroll); 213 | print_item(list, 0, FALSE); 214 | scrollok(list, TRUE); 215 | wscrl(list, -1); 216 | scrollok(list, FALSE); 217 | } 218 | scroll--; 219 | item_set(scroll); 220 | print_item(list, 0, TRUE); 221 | print_arrows(dialog, choice, item_count(), 222 | scroll, box_y, box_x + check_x + 5, list_height); 223 | 224 | wnoutrefresh(dialog); 225 | wrefresh(list); 226 | 227 | continue; /* wait for another key press */ 228 | } else 229 | i = choice - 1; 230 | } else if (key == KEY_DOWN || key == '+') { 231 | if (choice == max_choice - 1) { 232 | if (scroll + choice >= item_count() - 1) 233 | continue; 234 | /* Scroll list up */ 235 | if (list_height > 1) { 236 | /* De-highlight current last item before scrolling up */ 237 | item_set(scroll + max_choice - 1); 238 | print_item(list, 239 | max_choice - 1, 240 | FALSE); 241 | scrollok(list, TRUE); 242 | wscrl(list, 1); 243 | scrollok(list, FALSE); 244 | } 245 | scroll++; 246 | item_set(scroll + max_choice - 1); 247 | print_item(list, max_choice - 1, TRUE); 248 | 249 | print_arrows(dialog, choice, item_count(), 250 | scroll, box_y, box_x + check_x + 5, list_height); 251 | 252 | wnoutrefresh(dialog); 253 | wrefresh(list); 254 | 255 | continue; /* wait for another key press */ 256 | } else 257 | i = choice + 1; 258 | } 259 | if (i != choice) { 260 | /* De-highlight current item */ 261 | item_set(scroll + choice); 262 | print_item(list, choice, FALSE); 263 | /* Highlight new item */ 264 | choice = i; 265 | item_set(scroll + choice); 266 | print_item(list, choice, TRUE); 267 | wnoutrefresh(dialog); 268 | wrefresh(list); 269 | } 270 | continue; /* wait for another key press */ 271 | } 272 | switch (key) { 273 | case 'H': 274 | case 'h': 275 | case '?': 276 | button = 1; 277 | /* fall-through */ 278 | case 'S': 279 | case 's': 280 | case ' ': 281 | case '\n': 282 | item_foreach() 283 | item_set_selected(0); 284 | item_set(scroll + choice); 285 | item_set_selected(1); 286 | delwin(list); 287 | delwin(dialog); 288 | return button; 289 | case TAB: 290 | case KEY_LEFT: 291 | case KEY_RIGHT: 292 | button = ((key == KEY_LEFT ? --button : ++button) < 0) 293 | ? 1 : (button > 1 ? 0 : button); 294 | 295 | print_buttons(dialog, height, width, button); 296 | wrefresh(dialog); 297 | break; 298 | case 'X': 299 | case 'x': 300 | key = KEY_ESC; 301 | break; 302 | case KEY_ESC: 303 | key = on_key_esc(dialog); 304 | break; 305 | case KEY_RESIZE: 306 | delwin(list); 307 | delwin(dialog); 308 | on_key_resize(); 309 | goto do_resize; 310 | } 311 | 312 | /* Now, update everything... */ 313 | doupdate(); 314 | } 315 | delwin(list); 316 | delwin(dialog); 317 | return key; /* ESC pressed */ 318 | } 319 | -------------------------------------------------------------------------------- /kconfig/lxdialog/dialog.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0+ */ 2 | /* 3 | * dialog.h -- common declarations for all dialog modules 4 | * 5 | * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef __sun__ 17 | #define CURS_MACROS 18 | #endif 19 | #include 20 | 21 | #define TR(params) _tracef params 22 | 23 | #define KEY_ESC 27 24 | #define TAB 9 25 | #define MAX_LEN 2048 26 | #define BUF_SIZE (10*1024) 27 | #define MIN(x,y) (x < y ? x : y) 28 | #define MAX(x,y) (x > y ? x : y) 29 | 30 | #ifndef ACS_ULCORNER 31 | #define ACS_ULCORNER '+' 32 | #endif 33 | #ifndef ACS_LLCORNER 34 | #define ACS_LLCORNER '+' 35 | #endif 36 | #ifndef ACS_URCORNER 37 | #define ACS_URCORNER '+' 38 | #endif 39 | #ifndef ACS_LRCORNER 40 | #define ACS_LRCORNER '+' 41 | #endif 42 | #ifndef ACS_HLINE 43 | #define ACS_HLINE '-' 44 | #endif 45 | #ifndef ACS_VLINE 46 | #define ACS_VLINE '|' 47 | #endif 48 | #ifndef ACS_LTEE 49 | #define ACS_LTEE '+' 50 | #endif 51 | #ifndef ACS_RTEE 52 | #define ACS_RTEE '+' 53 | #endif 54 | #ifndef ACS_UARROW 55 | #define ACS_UARROW '^' 56 | #endif 57 | #ifndef ACS_DARROW 58 | #define ACS_DARROW 'v' 59 | #endif 60 | 61 | /* error return codes */ 62 | #define ERRDISPLAYTOOSMALL (KEY_MAX + 1) 63 | 64 | /* 65 | * Color definitions 66 | */ 67 | struct dialog_color { 68 | chtype atr; /* Color attribute */ 69 | int fg; /* foreground */ 70 | int bg; /* background */ 71 | int hl; /* highlight this item */ 72 | }; 73 | 74 | struct subtitle_list { 75 | struct subtitle_list *next; 76 | const char *text; 77 | }; 78 | 79 | struct dialog_info { 80 | const char *backtitle; 81 | struct subtitle_list *subtitles; 82 | struct dialog_color screen; 83 | struct dialog_color shadow; 84 | struct dialog_color dialog; 85 | struct dialog_color title; 86 | struct dialog_color border; 87 | struct dialog_color button_active; 88 | struct dialog_color button_inactive; 89 | struct dialog_color button_key_active; 90 | struct dialog_color button_key_inactive; 91 | struct dialog_color button_label_active; 92 | struct dialog_color button_label_inactive; 93 | struct dialog_color inputbox; 94 | struct dialog_color position_indicator; 95 | struct dialog_color menubox; 96 | struct dialog_color menubox_border; 97 | struct dialog_color item; 98 | struct dialog_color item_selected; 99 | struct dialog_color tag; 100 | struct dialog_color tag_selected; 101 | struct dialog_color tag_key; 102 | struct dialog_color tag_key_selected; 103 | struct dialog_color check; 104 | struct dialog_color check_selected; 105 | struct dialog_color uarrow; 106 | struct dialog_color darrow; 107 | }; 108 | 109 | /* 110 | * Global variables 111 | */ 112 | extern struct dialog_info dlg; 113 | extern char dialog_input_result[]; 114 | extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */ 115 | 116 | /* 117 | * Function prototypes 118 | */ 119 | 120 | /* item list as used by checklist and menubox */ 121 | void item_reset(void); 122 | void item_make(const char *fmt, ...); 123 | void item_add_str(const char *fmt, ...); 124 | void item_set_tag(char tag); 125 | void item_set_data(void *p); 126 | void item_set_selected(int val); 127 | int item_activate_selected(void); 128 | void *item_data(void); 129 | char item_tag(void); 130 | 131 | /* item list manipulation for lxdialog use */ 132 | #define MAXITEMSTR 200 133 | struct dialog_item { 134 | char str[MAXITEMSTR]; /* prompt displayed */ 135 | char tag; 136 | void *data; /* pointer to menu item - used by menubox+checklist */ 137 | int selected; /* Set to 1 by dialog_*() function if selected. */ 138 | }; 139 | 140 | /* list of lialog_items */ 141 | struct dialog_list { 142 | struct dialog_item node; 143 | struct dialog_list *next; 144 | }; 145 | 146 | extern struct dialog_list *item_cur; 147 | extern struct dialog_list item_nil; 148 | extern struct dialog_list *item_head; 149 | 150 | int item_count(void); 151 | void item_set(int n); 152 | int item_n(void); 153 | const char *item_str(void); 154 | int item_is_selected(void); 155 | int item_is_tag(char tag); 156 | #define item_foreach() \ 157 | for (item_cur = item_head ? item_head: item_cur; \ 158 | item_cur && (item_cur != &item_nil); item_cur = item_cur->next) 159 | 160 | /* generic key handlers */ 161 | int on_key_esc(WINDOW *win); 162 | int on_key_resize(void); 163 | 164 | /* minimum (re)size values */ 165 | #define CHECKLIST_HEIGHT_MIN 6 /* For dialog_checklist() */ 166 | #define CHECKLIST_WIDTH_MIN 6 167 | #define INPUTBOX_HEIGHT_MIN 2 /* For dialog_inputbox() */ 168 | #define INPUTBOX_WIDTH_MIN 2 169 | #define MENUBOX_HEIGHT_MIN 15 /* For dialog_menu() */ 170 | #define MENUBOX_WIDTH_MIN 65 171 | #define TEXTBOX_HEIGHT_MIN 8 /* For dialog_textbox() */ 172 | #define TEXTBOX_WIDTH_MIN 8 173 | #define YESNO_HEIGHT_MIN 4 /* For dialog_yesno() */ 174 | #define YESNO_WIDTH_MIN 4 175 | #define WINDOW_HEIGHT_MIN 19 /* For init_dialog() */ 176 | #define WINDOW_WIDTH_MIN 80 177 | 178 | int init_dialog(const char *backtitle); 179 | void set_dialog_backtitle(const char *backtitle); 180 | void set_dialog_subtitles(struct subtitle_list *subtitles); 181 | void end_dialog(int x, int y); 182 | void attr_clear(WINDOW * win, int height, int width, chtype attr); 183 | void dialog_clear(void); 184 | void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x); 185 | void print_button(WINDOW * win, const char *label, int y, int x, int selected); 186 | void print_title(WINDOW *dialog, const char *title, int width); 187 | void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box, 188 | chtype border); 189 | void draw_shadow(WINDOW * win, int y, int x, int height, int width); 190 | 191 | int first_alpha(const char *string, const char *exempt); 192 | int dialog_yesno(const char *title, const char *prompt, int height, int width); 193 | int dialog_msgbox(const char *title, const char *prompt, int height, 194 | int width, int pause); 195 | int dialog_textbox(const char *title, const char *tbuf, int initial_height, 196 | int initial_width, int *_vscroll, int *_hscroll, 197 | int (*extra_key_cb)(int, size_t, size_t, void *), void *data); 198 | int dialog_menu(const char *title, const char *prompt, 199 | const void *selected, int *s_scroll); 200 | int dialog_checklist(const char *title, const char *prompt, int height, 201 | int width, int list_height); 202 | int dialog_inputbox(const char *title, const char *prompt, int height, 203 | int width, const char *init); 204 | -------------------------------------------------------------------------------- /kconfig/lxdialog/inputbox.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0+ 2 | /* 3 | * inputbox.c -- implements the input box 4 | * 5 | * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 6 | * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) 7 | */ 8 | 9 | #include "dialog.h" 10 | 11 | char dialog_input_result[MAX_LEN + 1]; 12 | 13 | /* 14 | * Print the termination buttons 15 | */ 16 | static void print_buttons(WINDOW * dialog, int height, int width, int selected) 17 | { 18 | int x = width / 2 - 11; 19 | int y = height - 2; 20 | 21 | print_button(dialog, " Ok ", y, x, selected == 0); 22 | print_button(dialog, " Help ", y, x + 14, selected == 1); 23 | 24 | wmove(dialog, y, x + 1 + 14 * selected); 25 | wrefresh(dialog); 26 | } 27 | 28 | /* 29 | * Display a dialog box for inputing a string 30 | */ 31 | int dialog_inputbox(const char *title, const char *prompt, int height, int width, 32 | const char *init) 33 | { 34 | int i, x, y, box_y, box_x, box_width; 35 | int input_x = 0, key = 0, button = -1; 36 | int show_x, len, pos; 37 | char *instr = dialog_input_result; 38 | WINDOW *dialog; 39 | 40 | if (!init) 41 | instr[0] = '\0'; 42 | else 43 | strcpy(instr, init); 44 | 45 | do_resize: 46 | if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGHT_MIN)) 47 | return -ERRDISPLAYTOOSMALL; 48 | if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) 49 | return -ERRDISPLAYTOOSMALL; 50 | 51 | /* center dialog box on screen */ 52 | x = (getmaxx(stdscr) - width) / 2; 53 | y = (getmaxy(stdscr) - height) / 2; 54 | 55 | draw_shadow(stdscr, y, x, height, width); 56 | 57 | dialog = newwin(height, width, y, x); 58 | keypad(dialog, TRUE); 59 | 60 | draw_box(dialog, 0, 0, height, width, 61 | dlg.dialog.atr, dlg.border.atr); 62 | wattrset(dialog, dlg.border.atr); 63 | mvwaddch(dialog, height - 3, 0, ACS_LTEE); 64 | for (i = 0; i < width - 2; i++) 65 | waddch(dialog, ACS_HLINE); 66 | wattrset(dialog, dlg.dialog.atr); 67 | waddch(dialog, ACS_RTEE); 68 | 69 | print_title(dialog, title, width); 70 | 71 | wattrset(dialog, dlg.dialog.atr); 72 | print_autowrap(dialog, prompt, width - 2, 1, 3); 73 | 74 | /* Draw the input field box */ 75 | box_width = width - 6; 76 | getyx(dialog, y, x); 77 | box_y = y + 2; 78 | box_x = (width - box_width) / 2; 79 | draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, 80 | dlg.dialog.atr, dlg.border.atr); 81 | 82 | print_buttons(dialog, height, width, 0); 83 | 84 | /* Set up the initial value */ 85 | wmove(dialog, box_y, box_x); 86 | wattrset(dialog, dlg.inputbox.atr); 87 | 88 | len = strlen(instr); 89 | pos = len; 90 | 91 | if (len >= box_width) { 92 | show_x = len - box_width + 1; 93 | input_x = box_width - 1; 94 | for (i = 0; i < box_width - 1; i++) 95 | waddch(dialog, instr[show_x + i]); 96 | } else { 97 | show_x = 0; 98 | input_x = len; 99 | waddstr(dialog, instr); 100 | } 101 | 102 | wmove(dialog, box_y, box_x + input_x); 103 | 104 | wrefresh(dialog); 105 | 106 | while (key != KEY_ESC) { 107 | key = wgetch(dialog); 108 | 109 | if (button == -1) { /* Input box selected */ 110 | switch (key) { 111 | case TAB: 112 | case KEY_UP: 113 | case KEY_DOWN: 114 | break; 115 | case KEY_BACKSPACE: 116 | case 8: /* ^H */ 117 | case 127: /* ^? */ 118 | if (pos) { 119 | wattrset(dialog, dlg.inputbox.atr); 120 | if (input_x == 0) { 121 | show_x--; 122 | } else 123 | input_x--; 124 | 125 | if (pos < len) { 126 | for (i = pos - 1; i < len; i++) { 127 | instr[i] = instr[i+1]; 128 | } 129 | } 130 | 131 | pos--; 132 | len--; 133 | instr[len] = '\0'; 134 | wmove(dialog, box_y, box_x); 135 | for (i = 0; i < box_width; i++) { 136 | if (!instr[show_x + i]) { 137 | waddch(dialog, ' '); 138 | break; 139 | } 140 | waddch(dialog, instr[show_x + i]); 141 | } 142 | wmove(dialog, box_y, input_x + box_x); 143 | wrefresh(dialog); 144 | } 145 | continue; 146 | case KEY_LEFT: 147 | if (pos > 0) { 148 | if (input_x > 0) { 149 | wmove(dialog, box_y, --input_x + box_x); 150 | } else if (input_x == 0) { 151 | show_x--; 152 | wmove(dialog, box_y, box_x); 153 | for (i = 0; i < box_width; i++) { 154 | if (!instr[show_x + i]) { 155 | waddch(dialog, ' '); 156 | break; 157 | } 158 | waddch(dialog, instr[show_x + i]); 159 | } 160 | wmove(dialog, box_y, box_x); 161 | } 162 | pos--; 163 | } 164 | continue; 165 | case KEY_RIGHT: 166 | if (pos < len) { 167 | if (input_x < box_width - 1) { 168 | wmove(dialog, box_y, ++input_x + box_x); 169 | } else if (input_x == box_width - 1) { 170 | show_x++; 171 | wmove(dialog, box_y, box_x); 172 | for (i = 0; i < box_width; i++) { 173 | if (!instr[show_x + i]) { 174 | waddch(dialog, ' '); 175 | break; 176 | } 177 | waddch(dialog, instr[show_x + i]); 178 | } 179 | wmove(dialog, box_y, input_x + box_x); 180 | } 181 | pos++; 182 | } 183 | continue; 184 | default: 185 | if (key < 0x100 && isprint(key)) { 186 | if (len < MAX_LEN) { 187 | wattrset(dialog, dlg.inputbox.atr); 188 | if (pos < len) { 189 | for (i = len; i > pos; i--) 190 | instr[i] = instr[i-1]; 191 | instr[pos] = key; 192 | } else { 193 | instr[len] = key; 194 | } 195 | pos++; 196 | len++; 197 | instr[len] = '\0'; 198 | 199 | if (input_x == box_width - 1) { 200 | show_x++; 201 | } else { 202 | input_x++; 203 | } 204 | 205 | wmove(dialog, box_y, box_x); 206 | for (i = 0; i < box_width; i++) { 207 | if (!instr[show_x + i]) { 208 | waddch(dialog, ' '); 209 | break; 210 | } 211 | waddch(dialog, instr[show_x + i]); 212 | } 213 | wmove(dialog, box_y, input_x + box_x); 214 | wrefresh(dialog); 215 | } else 216 | flash(); /* Alarm user about overflow */ 217 | continue; 218 | } 219 | } 220 | } 221 | switch (key) { 222 | case 'O': 223 | case 'o': 224 | delwin(dialog); 225 | return 0; 226 | case 'H': 227 | case 'h': 228 | delwin(dialog); 229 | return 1; 230 | case KEY_UP: 231 | case KEY_LEFT: 232 | switch (button) { 233 | case -1: 234 | button = 1; /* Indicates "Help" button is selected */ 235 | print_buttons(dialog, height, width, 1); 236 | break; 237 | case 0: 238 | button = -1; /* Indicates input box is selected */ 239 | print_buttons(dialog, height, width, 0); 240 | wmove(dialog, box_y, box_x + input_x); 241 | wrefresh(dialog); 242 | break; 243 | case 1: 244 | button = 0; /* Indicates "OK" button is selected */ 245 | print_buttons(dialog, height, width, 0); 246 | break; 247 | } 248 | break; 249 | case TAB: 250 | case KEY_DOWN: 251 | case KEY_RIGHT: 252 | switch (button) { 253 | case -1: 254 | button = 0; /* Indicates "OK" button is selected */ 255 | print_buttons(dialog, height, width, 0); 256 | break; 257 | case 0: 258 | button = 1; /* Indicates "Help" button is selected */ 259 | print_buttons(dialog, height, width, 1); 260 | break; 261 | case 1: 262 | button = -1; /* Indicates input box is selected */ 263 | print_buttons(dialog, height, width, 0); 264 | wmove(dialog, box_y, box_x + input_x); 265 | wrefresh(dialog); 266 | break; 267 | } 268 | break; 269 | case ' ': 270 | case '\n': 271 | delwin(dialog); 272 | return (button == -1 ? 0 : button); 273 | case 'X': 274 | case 'x': 275 | key = KEY_ESC; 276 | break; 277 | case KEY_ESC: 278 | key = on_key_esc(dialog); 279 | break; 280 | case KEY_RESIZE: 281 | delwin(dialog); 282 | on_key_resize(); 283 | goto do_resize; 284 | } 285 | } 286 | 287 | delwin(dialog); 288 | return KEY_ESC; /* ESC pressed */ 289 | } 290 | -------------------------------------------------------------------------------- /kconfig/lxdialog/textbox.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0+ 2 | /* 3 | * textbox.c -- implements the text box 4 | * 5 | * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 6 | * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) 7 | */ 8 | 9 | #include "dialog.h" 10 | 11 | static int hscroll; 12 | static int begin_reached, end_reached, page_length; 13 | static const char *buf, *page; 14 | static size_t start, end; 15 | 16 | /* 17 | * Go back 'n' lines in text. Called by dialog_textbox(). 18 | * 'page' will be updated to point to the desired line in 'buf'. 19 | */ 20 | static void back_lines(int n) 21 | { 22 | int i; 23 | 24 | begin_reached = 0; 25 | /* Go back 'n' lines */ 26 | for (i = 0; i < n; i++) { 27 | if (*page == '\0') { 28 | if (end_reached) { 29 | end_reached = 0; 30 | continue; 31 | } 32 | } 33 | if (page == buf) { 34 | begin_reached = 1; 35 | return; 36 | } 37 | page--; 38 | do { 39 | if (page == buf) { 40 | begin_reached = 1; 41 | return; 42 | } 43 | page--; 44 | } while (*page != '\n'); 45 | page++; 46 | } 47 | } 48 | 49 | /* 50 | * Return current line of text. Called by dialog_textbox() and print_line(). 51 | * 'page' should point to start of current line before calling, and will be 52 | * updated to point to start of next line. 53 | */ 54 | static char *get_line(void) 55 | { 56 | int i = 0; 57 | static char line[MAX_LEN + 1]; 58 | 59 | end_reached = 0; 60 | while (*page != '\n') { 61 | if (*page == '\0') { 62 | end_reached = 1; 63 | break; 64 | } else if (i < MAX_LEN) 65 | line[i++] = *(page++); 66 | else { 67 | /* Truncate lines longer than MAX_LEN characters */ 68 | if (i == MAX_LEN) 69 | line[i++] = '\0'; 70 | page++; 71 | } 72 | } 73 | if (i <= MAX_LEN) 74 | line[i] = '\0'; 75 | if (!end_reached) 76 | page++; /* move past '\n' */ 77 | 78 | return line; 79 | } 80 | 81 | /* 82 | * Print a new line of text. 83 | */ 84 | static void print_line(WINDOW *win, int row, int width) 85 | { 86 | char *line; 87 | 88 | line = get_line(); 89 | line += MIN(strlen(line), hscroll); /* Scroll horizontally */ 90 | wmove(win, row, 0); /* move cursor to correct line */ 91 | waddch(win, ' '); 92 | waddnstr(win, line, MIN(strlen(line), width - 2)); 93 | 94 | /* Clear 'residue' of previous line */ 95 | wclrtoeol(win); 96 | } 97 | 98 | /* 99 | * Print a new page of text. 100 | */ 101 | static void print_page(WINDOW *win, int height, int width) 102 | { 103 | int i, passed_end = 0; 104 | 105 | page_length = 0; 106 | for (i = 0; i < height; i++) { 107 | print_line(win, i, width); 108 | if (!passed_end) 109 | page_length++; 110 | if (end_reached && !passed_end) 111 | passed_end = 1; 112 | } 113 | wnoutrefresh(win); 114 | } 115 | 116 | /* 117 | * Print current position 118 | */ 119 | static void print_position(WINDOW *win) 120 | { 121 | int percent; 122 | 123 | wattrset(win, dlg.position_indicator.atr); 124 | wbkgdset(win, dlg.position_indicator.atr & A_COLOR); 125 | percent = (page - buf) * 100 / strlen(buf); 126 | wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); 127 | wprintw(win, "(%3d%%)", percent); 128 | } 129 | 130 | /* 131 | * refresh window content 132 | */ 133 | static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, 134 | int cur_y, int cur_x) 135 | { 136 | start = page - buf; 137 | 138 | print_page(box, boxh, boxw); 139 | print_position(dialog); 140 | wmove(dialog, cur_y, cur_x); /* Restore cursor position */ 141 | wrefresh(dialog); 142 | 143 | end = page - buf; 144 | } 145 | 146 | /* 147 | * Display text from a file in a dialog box. 148 | * 149 | * keys is a null-terminated array 150 | */ 151 | int dialog_textbox(const char *title, const char *tbuf, int initial_height, 152 | int initial_width, int *_vscroll, int *_hscroll, 153 | int (*extra_key_cb)(int, size_t, size_t, void *), void *data) 154 | { 155 | int i, x, y, cur_x, cur_y, key = 0; 156 | int height, width, boxh, boxw; 157 | WINDOW *dialog, *box; 158 | bool done = false; 159 | 160 | begin_reached = 1; 161 | end_reached = 0; 162 | page_length = 0; 163 | hscroll = 0; 164 | buf = tbuf; 165 | page = buf; /* page is pointer to start of page to be displayed */ 166 | 167 | if (_vscroll && *_vscroll) { 168 | begin_reached = 0; 169 | 170 | for (i = 0; i < *_vscroll; i++) 171 | get_line(); 172 | } 173 | if (_hscroll) 174 | hscroll = *_hscroll; 175 | 176 | do_resize: 177 | getmaxyx(stdscr, height, width); 178 | if (height < TEXTBOX_HEIGHT_MIN || width < TEXTBOX_WIDTH_MIN) 179 | return -ERRDISPLAYTOOSMALL; 180 | if (initial_height != 0) 181 | height = initial_height; 182 | else 183 | if (height > 4) 184 | height -= 4; 185 | else 186 | height = 0; 187 | if (initial_width != 0) 188 | width = initial_width; 189 | else 190 | if (width > 5) 191 | width -= 5; 192 | else 193 | width = 0; 194 | 195 | /* center dialog box on screen */ 196 | x = (getmaxx(stdscr) - width) / 2; 197 | y = (getmaxy(stdscr) - height) / 2; 198 | 199 | draw_shadow(stdscr, y, x, height, width); 200 | 201 | dialog = newwin(height, width, y, x); 202 | keypad(dialog, TRUE); 203 | 204 | /* Create window for box region, used for scrolling text */ 205 | boxh = height - 4; 206 | boxw = width - 2; 207 | box = subwin(dialog, boxh, boxw, y + 1, x + 1); 208 | wattrset(box, dlg.dialog.atr); 209 | wbkgdset(box, dlg.dialog.atr & A_COLOR); 210 | 211 | keypad(box, TRUE); 212 | 213 | /* register the new window, along with its borders */ 214 | draw_box(dialog, 0, 0, height, width, 215 | dlg.dialog.atr, dlg.border.atr); 216 | 217 | wattrset(dialog, dlg.border.atr); 218 | mvwaddch(dialog, height - 3, 0, ACS_LTEE); 219 | for (i = 0; i < width - 2; i++) 220 | waddch(dialog, ACS_HLINE); 221 | wattrset(dialog, dlg.dialog.atr); 222 | wbkgdset(dialog, dlg.dialog.atr & A_COLOR); 223 | waddch(dialog, ACS_RTEE); 224 | 225 | print_title(dialog, title, width); 226 | 227 | print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE); 228 | wnoutrefresh(dialog); 229 | getyx(dialog, cur_y, cur_x); /* Save cursor position */ 230 | 231 | /* Print first page of text */ 232 | attr_clear(box, boxh, boxw, dlg.dialog.atr); 233 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 234 | 235 | while (!done) { 236 | key = wgetch(dialog); 237 | switch (key) { 238 | case 'E': /* Exit */ 239 | case 'e': 240 | case 'X': 241 | case 'x': 242 | case 'q': 243 | case '\n': 244 | done = true; 245 | break; 246 | case 'g': /* First page */ 247 | case KEY_HOME: 248 | if (!begin_reached) { 249 | begin_reached = 1; 250 | page = buf; 251 | refresh_text_box(dialog, box, boxh, boxw, 252 | cur_y, cur_x); 253 | } 254 | break; 255 | case 'G': /* Last page */ 256 | case KEY_END: 257 | 258 | end_reached = 1; 259 | /* point to last char in buf */ 260 | page = buf + strlen(buf); 261 | back_lines(boxh); 262 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 263 | break; 264 | case 'K': /* Previous line */ 265 | case 'k': 266 | case KEY_UP: 267 | if (begin_reached) 268 | break; 269 | 270 | back_lines(page_length + 1); 271 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 272 | break; 273 | case 'B': /* Previous page */ 274 | case 'b': 275 | case 'u': 276 | case KEY_PPAGE: 277 | if (begin_reached) 278 | break; 279 | back_lines(page_length + boxh); 280 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 281 | break; 282 | case 'J': /* Next line */ 283 | case 'j': 284 | case KEY_DOWN: 285 | if (end_reached) 286 | break; 287 | 288 | back_lines(page_length - 1); 289 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 290 | break; 291 | case KEY_NPAGE: /* Next page */ 292 | case ' ': 293 | case 'd': 294 | if (end_reached) 295 | break; 296 | 297 | begin_reached = 0; 298 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 299 | break; 300 | case '0': /* Beginning of line */ 301 | case 'H': /* Scroll left */ 302 | case 'h': 303 | case KEY_LEFT: 304 | if (hscroll <= 0) 305 | break; 306 | 307 | if (key == '0') 308 | hscroll = 0; 309 | else 310 | hscroll--; 311 | /* Reprint current page to scroll horizontally */ 312 | back_lines(page_length); 313 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 314 | break; 315 | case 'L': /* Scroll right */ 316 | case 'l': 317 | case KEY_RIGHT: 318 | if (hscroll >= MAX_LEN) 319 | break; 320 | hscroll++; 321 | /* Reprint current page to scroll horizontally */ 322 | back_lines(page_length); 323 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); 324 | break; 325 | case KEY_ESC: 326 | if (on_key_esc(dialog) == KEY_ESC) 327 | done = true; 328 | break; 329 | case KEY_RESIZE: 330 | back_lines(height); 331 | delwin(box); 332 | delwin(dialog); 333 | on_key_resize(); 334 | goto do_resize; 335 | default: 336 | if (extra_key_cb && extra_key_cb(key, start, end, data)) { 337 | done = true; 338 | break; 339 | } 340 | } 341 | } 342 | delwin(box); 343 | delwin(dialog); 344 | if (_vscroll) { 345 | const char *s; 346 | 347 | s = buf; 348 | *_vscroll = 0; 349 | back_lines(page_length); 350 | while (s < page && (s = strchr(s, '\n'))) { 351 | (*_vscroll)++; 352 | s++; 353 | } 354 | } 355 | if (_hscroll) 356 | *_hscroll = hscroll; 357 | return key; 358 | } 359 | -------------------------------------------------------------------------------- /kconfig/lxdialog/yesno.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0+ 2 | /* 3 | * yesno.c -- implements the yes/no box 4 | * 5 | * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 6 | * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) 7 | */ 8 | 9 | #include "dialog.h" 10 | 11 | /* 12 | * Display termination buttons 13 | */ 14 | static void print_buttons(WINDOW * dialog, int height, int width, int selected) 15 | { 16 | int x = width / 2 - 10; 17 | int y = height - 2; 18 | 19 | print_button(dialog, " Yes ", y, x, selected == 0); 20 | print_button(dialog, " No ", y, x + 13, selected == 1); 21 | 22 | wmove(dialog, y, x + 1 + 13 * selected); 23 | wrefresh(dialog); 24 | } 25 | 26 | /* 27 | * Display a dialog box with two buttons - Yes and No 28 | */ 29 | int dialog_yesno(const char *title, const char *prompt, int height, int width) 30 | { 31 | int i, x, y, key = 0, button = 0; 32 | WINDOW *dialog; 33 | 34 | do_resize: 35 | if (getmaxy(stdscr) < (height + YESNO_HEIGHT_MIN)) 36 | return -ERRDISPLAYTOOSMALL; 37 | if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) 38 | return -ERRDISPLAYTOOSMALL; 39 | 40 | /* center dialog box on screen */ 41 | x = (getmaxx(stdscr) - width) / 2; 42 | y = (getmaxy(stdscr) - height) / 2; 43 | 44 | draw_shadow(stdscr, y, x, height, width); 45 | 46 | dialog = newwin(height, width, y, x); 47 | keypad(dialog, TRUE); 48 | 49 | draw_box(dialog, 0, 0, height, width, 50 | dlg.dialog.atr, dlg.border.atr); 51 | wattrset(dialog, dlg.border.atr); 52 | mvwaddch(dialog, height - 3, 0, ACS_LTEE); 53 | for (i = 0; i < width - 2; i++) 54 | waddch(dialog, ACS_HLINE); 55 | wattrset(dialog, dlg.dialog.atr); 56 | waddch(dialog, ACS_RTEE); 57 | 58 | print_title(dialog, title, width); 59 | 60 | wattrset(dialog, dlg.dialog.atr); 61 | print_autowrap(dialog, prompt, width - 2, 1, 3); 62 | 63 | print_buttons(dialog, height, width, 0); 64 | 65 | while (key != KEY_ESC) { 66 | key = wgetch(dialog); 67 | switch (key) { 68 | case 'Y': 69 | case 'y': 70 | delwin(dialog); 71 | return 0; 72 | case 'N': 73 | case 'n': 74 | delwin(dialog); 75 | return 1; 76 | 77 | case TAB: 78 | case KEY_LEFT: 79 | case KEY_RIGHT: 80 | button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); 81 | 82 | print_buttons(dialog, height, width, button); 83 | wrefresh(dialog); 84 | break; 85 | case ' ': 86 | case '\n': 87 | delwin(dialog); 88 | return button; 89 | case KEY_ESC: 90 | key = on_key_esc(dialog); 91 | break; 92 | case KEY_RESIZE: 93 | delwin(dialog); 94 | on_key_resize(); 95 | goto do_resize; 96 | } 97 | } 98 | 99 | delwin(dialog); 100 | return key; /* ESC pressed */ 101 | } 102 | -------------------------------------------------------------------------------- /kconfig/mconf-cfg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0 3 | 4 | cflags=$1 5 | libs=$2 6 | 7 | PKG="ncursesw" 8 | PKG2="ncurses" 9 | 10 | if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then 11 | if ${HOSTPKG_CONFIG} --exists $PKG; then 12 | ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags} 13 | ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs} 14 | exit 0 15 | fi 16 | 17 | if ${HOSTPKG_CONFIG} --exists ${PKG2}; then 18 | ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags} 19 | ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs} 20 | exit 0 21 | fi 22 | fi 23 | 24 | # Check the default paths in case pkg-config is not installed. 25 | # (Even if it is installed, some distributions such as openSUSE cannot 26 | # find ncurses by pkg-config.) 27 | if [ -f /usr/include/ncursesw/ncurses.h ]; then 28 | echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags} 29 | echo -lncursesw > ${libs} 30 | exit 0 31 | fi 32 | 33 | if [ -f /usr/include/ncurses/ncurses.h ]; then 34 | echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags} 35 | echo -lncurses > ${libs} 36 | exit 0 37 | fi 38 | 39 | # As a final fallback before giving up, check if $HOSTCC knows of a default 40 | # ncurses installation (e.g. from a vendor-specific sysroot). 41 | if echo '#include ' | ${HOSTCC} -E - >/dev/null 2>&1; then 42 | echo -D_GNU_SOURCE > ${cflags} 43 | echo -lncurses > ${libs} 44 | exit 0 45 | fi 46 | 47 | echo >&2 "*" 48 | echo >&2 "* Unable to find the ncurses package." 49 | echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" 50 | echo >&2 "* depending on your distribution)." 51 | echo >&2 "*" 52 | echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" 53 | echo >&2 "* ncurses installed in a non-default location." 54 | echo >&2 "*" 55 | exit 1 56 | -------------------------------------------------------------------------------- /kconfig/merge_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0 3 | # 4 | # merge_config.sh - Takes a list of config fragment values, and merges 5 | # them one by one. Provides warnings on overridden values, and specified 6 | # values that did not make it to the resulting .config file (due to missed 7 | # dependencies or config symbol removal). 8 | # 9 | # Portions reused from kconf_check and generate_cfg: 10 | # http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check 11 | # http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg 12 | # 13 | # Copyright (c) 2009-2010 Wind River Systems, Inc. 14 | # Copyright 2011 Linaro 15 | 16 | set -e 17 | 18 | clean_up() { 19 | rm -f $TMP_FILE 20 | rm -f $MERGE_FILE 21 | } 22 | 23 | usage() { 24 | echo "Usage: $0 [OPTIONS] [CONFIG [...]]" 25 | echo " -h display this help text" 26 | echo " -m only merge the fragments, do not execute the make command" 27 | echo " -n use allnoconfig instead of alldefconfig" 28 | echo " -r list redundant entries when merging fragments" 29 | echo " -y make builtin have precedence over modules" 30 | echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead." 31 | echo " -s strict mode. Fail if the fragment redefines any value." 32 | echo " -Q disable warning messages for overridden options." 33 | echo 34 | echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable." 35 | } 36 | 37 | RUNMAKE=true 38 | ALLTARGET=alldefconfig 39 | WARNREDUN=false 40 | BUILTIN=false 41 | OUTPUT=. 42 | STRICT=false 43 | CONFIG_PREFIX=${CONFIG_-CONFIG_} 44 | WARNOVERRIDE=echo 45 | 46 | while true; do 47 | case $1 in 48 | "-n") 49 | ALLTARGET=allnoconfig 50 | shift 51 | continue 52 | ;; 53 | "-m") 54 | RUNMAKE=false 55 | shift 56 | continue 57 | ;; 58 | "-h") 59 | usage 60 | exit 61 | ;; 62 | "-r") 63 | WARNREDUN=true 64 | shift 65 | continue 66 | ;; 67 | "-y") 68 | BUILTIN=true 69 | shift 70 | continue 71 | ;; 72 | "-O") 73 | if [ -d $2 ];then 74 | OUTPUT=$(echo $2 | sed 's/\/*$//') 75 | else 76 | echo "output directory $2 does not exist" 1>&2 77 | exit 1 78 | fi 79 | shift 2 80 | continue 81 | ;; 82 | "-s") 83 | STRICT=true 84 | shift 85 | continue 86 | ;; 87 | "-Q") 88 | WARNOVERRIDE=true 89 | shift 90 | continue 91 | ;; 92 | *) 93 | break 94 | ;; 95 | esac 96 | done 97 | 98 | if [ "$#" -lt 1 ] ; then 99 | usage 100 | exit 101 | fi 102 | 103 | if [ -z "$KCONFIG_CONFIG" ]; then 104 | if [ "$OUTPUT" != . ]; then 105 | KCONFIG_CONFIG=$(readlink -m -- "$OUTPUT/.config") 106 | else 107 | KCONFIG_CONFIG=.config 108 | fi 109 | fi 110 | 111 | INITFILE=$1 112 | shift; 113 | 114 | if [ ! -r "$INITFILE" ]; then 115 | echo "The base file '$INITFILE' does not exist. Exit." >&2 116 | exit 1 117 | fi 118 | 119 | MERGE_LIST=$* 120 | SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p" 121 | SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p" 122 | 123 | TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) 124 | MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX) 125 | 126 | echo "Using $INITFILE as base" 127 | 128 | trap clean_up EXIT 129 | 130 | cat $INITFILE > $TMP_FILE 131 | 132 | # Merge files, printing warnings on overridden values 133 | for ORIG_MERGE_FILE in $MERGE_LIST ; do 134 | echo "Merging $ORIG_MERGE_FILE" 135 | if [ ! -r "$ORIG_MERGE_FILE" ]; then 136 | echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2 137 | exit 1 138 | fi 139 | cat $ORIG_MERGE_FILE > $MERGE_FILE 140 | CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE) 141 | 142 | for CFG in $CFG_LIST ; do 143 | grep -q -w $CFG $TMP_FILE || continue 144 | PREV_VAL=$(grep -w $CFG $TMP_FILE) 145 | NEW_VAL=$(grep -w $CFG $MERGE_FILE) 146 | BUILTIN_FLAG=false 147 | if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then 148 | ${WARNOVERRIDE} Previous value: $PREV_VAL 149 | ${WARNOVERRIDE} New value: $NEW_VAL 150 | ${WARNOVERRIDE} -y passed, will not demote y to m 151 | ${WARNOVERRIDE} 152 | BUILTIN_FLAG=true 153 | elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then 154 | ${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE: 155 | ${WARNOVERRIDE} Previous value: $PREV_VAL 156 | ${WARNOVERRIDE} New value: $NEW_VAL 157 | ${WARNOVERRIDE} 158 | if [ "$STRICT" = "true" ]; then 159 | STRICT_MODE_VIOLATED=true 160 | fi 161 | elif [ "$WARNREDUN" = "true" ]; then 162 | ${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE: 163 | fi 164 | if [ "$BUILTIN_FLAG" = "false" ]; then 165 | sed -i "/$CFG[ =]/d" $TMP_FILE 166 | else 167 | sed -i "/$CFG[ =]/d" $MERGE_FILE 168 | fi 169 | done 170 | cat $MERGE_FILE >> $TMP_FILE 171 | done 172 | 173 | if [ "$STRICT_MODE_VIOLATED" = "true" ]; then 174 | echo "The fragment redefined a value and strict mode had been passed." 175 | exit 1 176 | fi 177 | 178 | if [ "$RUNMAKE" = "false" ]; then 179 | cp -T -- "$TMP_FILE" "$KCONFIG_CONFIG" 180 | echo "#" 181 | echo "# merged configuration written to $KCONFIG_CONFIG (needs make)" 182 | echo "#" 183 | exit 184 | fi 185 | 186 | # If we have an output dir, setup the O= argument, otherwise leave 187 | # it blank, since O=. will create an unnecessary ./source softlink 188 | OUTPUT_ARG="" 189 | if [ "$OUTPUT" != "." ] ; then 190 | OUTPUT_ARG="O=$OUTPUT" 191 | fi 192 | 193 | 194 | # Use the merged file as the starting point for: 195 | # alldefconfig: Fills in any missing symbols with Kconfig default 196 | # allnoconfig: Fills in any missing symbols with # CONFIG_* is not set 197 | make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET 198 | 199 | 200 | # Check all specified config values took (might have missed-dependency issues) 201 | for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do 202 | 203 | REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) 204 | ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true) 205 | if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then 206 | echo "Value requested for $CFG not in final .config" 207 | echo "Requested value: $REQUESTED_VAL" 208 | echo "Actual value: $ACTUAL_VAL" 209 | echo "" 210 | fi 211 | done 212 | -------------------------------------------------------------------------------- /kconfig/mnconf-common.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | #include "expr.h" 3 | #include "list.h" 4 | #include "mnconf-common.h" 5 | 6 | int jump_key_char; 7 | 8 | int next_jump_key(int key) 9 | { 10 | if (key < '1' || key > '9') 11 | return '1'; 12 | 13 | key++; 14 | 15 | if (key > '9') 16 | key = '1'; 17 | 18 | return key; 19 | } 20 | 21 | int handle_search_keys(int key, size_t start, size_t end, void *_data) 22 | { 23 | struct search_data *data = _data; 24 | struct jump_key *pos; 25 | int index = 0; 26 | 27 | if (key < '1' || key > '9') 28 | return 0; 29 | 30 | list_for_each_entry(pos, data->head, entries) { 31 | index = next_jump_key(index); 32 | 33 | if (pos->offset < start) 34 | continue; 35 | 36 | if (pos->offset >= end) 37 | break; 38 | 39 | if (key == index) { 40 | data->target = pos->target; 41 | return 1; 42 | } 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | int get_jump_key_char(void) 49 | { 50 | jump_key_char = next_jump_key(jump_key_char); 51 | 52 | return jump_key_char; 53 | } 54 | -------------------------------------------------------------------------------- /kconfig/mnconf-common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | #ifndef MNCONF_COMMON_H 3 | #define MNCONF_COMMON_H 4 | 5 | #include 6 | 7 | struct search_data { 8 | struct list_head *head; 9 | struct menu *target; 10 | }; 11 | 12 | extern int jump_key_char; 13 | 14 | int next_jump_key(int key); 15 | int handle_search_keys(int key, size_t start, size_t end, void *_data); 16 | int get_jump_key_char(void); 17 | 18 | #endif /* MNCONF_COMMON_H */ 19 | -------------------------------------------------------------------------------- /kconfig/nconf-cfg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0 3 | 4 | cflags=$1 5 | libs=$2 6 | 7 | PKG="ncursesw menuw panelw" 8 | PKG2="ncurses menu panel" 9 | 10 | if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then 11 | if ${HOSTPKG_CONFIG} --exists $PKG; then 12 | ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags} 13 | ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs} 14 | exit 0 15 | fi 16 | 17 | if ${HOSTPKG_CONFIG} --exists $PKG2; then 18 | ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags} 19 | ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs} 20 | exit 0 21 | fi 22 | fi 23 | 24 | # Check the default paths in case pkg-config is not installed. 25 | # (Even if it is installed, some distributions such as openSUSE cannot 26 | # find ncurses by pkg-config.) 27 | if [ -f /usr/include/ncursesw/ncurses.h ]; then 28 | echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags} 29 | echo -lncursesw -lmenuw -lpanelw > ${libs} 30 | exit 0 31 | fi 32 | 33 | if [ -f /usr/include/ncurses/ncurses.h ]; then 34 | echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags} 35 | echo -lncurses -lmenu -lpanel > ${libs} 36 | exit 0 37 | fi 38 | 39 | if [ -f /usr/include/ncurses.h ]; then 40 | echo -D_GNU_SOURCE > ${cflags} 41 | echo -lncurses -lmenu -lpanel > ${libs} 42 | exit 0 43 | fi 44 | 45 | echo >&2 "*" 46 | echo >&2 "* Unable to find the ncurses package." 47 | echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" 48 | echo >&2 "* depending on your distribution)." 49 | echo >&2 "*" 50 | echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" 51 | echo >&2 "* ncurses installed in a non-default location." 52 | echo >&2 "*" 53 | exit 1 54 | -------------------------------------------------------------------------------- /kconfig/nconf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2008 Nir Tzachar 4 | * 5 | * Derived from menuconfig. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #define max(a, b) ({\ 26 | typeof(a) _a = a;\ 27 | typeof(b) _b = b;\ 28 | _a > _b ? _a : _b; }) 29 | 30 | #define min(a, b) ({\ 31 | typeof(a) _a = a;\ 32 | typeof(b) _b = b;\ 33 | _a < _b ? _a : _b; }) 34 | 35 | extern int attr_normal; 36 | extern int attr_main_heading; 37 | extern int attr_main_menu_box; 38 | extern int attr_main_menu_fore; 39 | extern int attr_main_menu_back; 40 | extern int attr_main_menu_grey; 41 | extern int attr_main_menu_heading; 42 | extern int attr_scrollwin_text; 43 | extern int attr_scrollwin_heading; 44 | extern int attr_scrollwin_box; 45 | extern int attr_dialog_text; 46 | extern int attr_dialog_menu_fore; 47 | extern int attr_dialog_menu_back; 48 | extern int attr_dialog_box; 49 | extern int attr_input_box; 50 | extern int attr_input_heading; 51 | extern int attr_input_text; 52 | extern int attr_input_field; 53 | extern int attr_function_text; 54 | extern int attr_function_highlight; 55 | 56 | typedef enum { 57 | F_HELP = 1, 58 | F_SYMBOL = 2, 59 | F_INSTS = 3, 60 | F_CONF = 4, 61 | F_BACK = 5, 62 | F_SAVE = 6, 63 | F_LOAD = 7, 64 | F_SEARCH = 8, 65 | F_EXIT = 9, 66 | } function_key; 67 | 68 | void set_colors(void); 69 | 70 | typedef int (*extra_key_cb_fn)(int, size_t, size_t, void *); 71 | 72 | /* this changes the windows attributes !!! */ 73 | void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs); 74 | int get_line_length(const char *line); 75 | int get_line_no(const char *text); 76 | const char *get_line(const char *text, int line_no); 77 | void fill_window(WINDOW *win, const char *text); 78 | int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...); 79 | int dialog_inputbox(WINDOW *main_window, 80 | const char *title, const char *prompt, 81 | const char *init, char **resultp, int *result_len); 82 | void refresh_all_windows(WINDOW *main_window); 83 | int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text, 84 | int *vscroll, int *hscroll, 85 | extra_key_cb_fn extra_key_cb, void *data); 86 | void show_scroll_win(WINDOW *main_window, 87 | const char *title, 88 | const char *text); 89 | -------------------------------------------------------------------------------- /kconfig/parser.tab.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.5.1. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation, 6 | Inc. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . */ 20 | 21 | /* As a special exception, you may create a larger work that contains 22 | part or all of the Bison parser skeleton and distribute that work 23 | under terms of your choice, so long as that work isn't itself a 24 | parser generator using the skeleton or a modified version thereof 25 | as a parser skeleton. Alternatively, if you modify or redistribute 26 | the parser skeleton itself, you may (at your option) remove this 27 | special exception, which will cause the skeleton and the resulting 28 | Bison output files to be licensed under the GNU General Public 29 | License without this special exception. 30 | 31 | This special exception was added by the Free Software Foundation in 32 | version 2.2 of Bison. */ 33 | 34 | /* Undocumented macros, especially those whose name start with YY_, 35 | are private implementation details. Do not rely on them. */ 36 | 37 | #ifndef YY_YY_SCRIPTS_KCONFIG_PARSER_TAB_H_INCLUDED 38 | # define YY_YY_SCRIPTS_KCONFIG_PARSER_TAB_H_INCLUDED 39 | /* Debug traces. */ 40 | #ifndef YYDEBUG 41 | # define YYDEBUG 1 42 | #endif 43 | #if YYDEBUG 44 | extern int yydebug; 45 | #endif 46 | 47 | /* Token type. */ 48 | #ifndef YYTOKENTYPE 49 | # define YYTOKENTYPE 50 | enum yytokentype 51 | { 52 | T_HELPTEXT = 258, 53 | T_WORD = 259, 54 | T_WORD_QUOTE = 260, 55 | T_BOOL = 261, 56 | T_CHOICE = 262, 57 | T_CLOSE_PAREN = 263, 58 | T_COLON_EQUAL = 264, 59 | T_COMMENT = 265, 60 | T_CONFIG = 266, 61 | T_DEFAULT = 267, 62 | T_DEF_BOOL = 268, 63 | T_DEF_TRISTATE = 269, 64 | T_DEPENDS = 270, 65 | T_ENDCHOICE = 271, 66 | T_ENDIF = 272, 67 | T_ENDMENU = 273, 68 | T_HELP = 274, 69 | T_HEX = 275, 70 | T_IF = 276, 71 | T_IMPLY = 277, 72 | T_INT = 278, 73 | T_MAINMENU = 279, 74 | T_MENU = 280, 75 | T_MENUCONFIG = 281, 76 | T_MODULES = 282, 77 | T_ON = 283, 78 | T_OPEN_PAREN = 284, 79 | T_OPTIONAL = 285, 80 | T_PLUS_EQUAL = 286, 81 | T_PROMPT = 287, 82 | T_RANGE = 288, 83 | T_SELECT = 289, 84 | T_SOURCE = 290, 85 | T_STRING = 291, 86 | T_TRISTATE = 292, 87 | T_VISIBLE = 293, 88 | T_EOL = 294, 89 | T_ASSIGN_VAL = 295, 90 | T_OR = 296, 91 | T_AND = 297, 92 | T_EQUAL = 298, 93 | T_UNEQUAL = 299, 94 | T_LESS = 300, 95 | T_LESS_EQUAL = 301, 96 | T_GREATER = 302, 97 | T_GREATER_EQUAL = 303, 98 | T_NOT = 304 99 | }; 100 | #endif 101 | 102 | /* Value type. */ 103 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 104 | union YYSTYPE 105 | { 106 | 107 | char *string; 108 | struct symbol *symbol; 109 | struct expr *expr; 110 | struct menu *menu; 111 | enum symbol_type type; 112 | enum variable_flavor flavor; 113 | 114 | 115 | }; 116 | typedef union YYSTYPE YYSTYPE; 117 | # define YYSTYPE_IS_TRIVIAL 1 118 | # define YYSTYPE_IS_DECLARED 1 119 | #endif 120 | 121 | 122 | extern YYSTYPE yylval; 123 | 124 | int yyparse (void); 125 | 126 | #endif /* !YY_YY_SCRIPTS_KCONFIG_PARSER_TAB_H_INCLUDED */ 127 | -------------------------------------------------------------------------------- /kconfig/preprocess.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | #ifndef PREPROCESS_H 3 | #define PREPROCESS_H 4 | 5 | enum variable_flavor { 6 | VAR_SIMPLE, 7 | VAR_RECURSIVE, 8 | VAR_APPEND, 9 | }; 10 | 11 | struct gstr; 12 | void env_write_dep(struct gstr *gs); 13 | void variable_add(const char *name, const char *value, 14 | enum variable_flavor flavor); 15 | void variable_all_del(void); 16 | char *expand_dollar(const char **str); 17 | char *expand_one_token(const char **str); 18 | 19 | #endif /* PREPROCESS_H */ 20 | -------------------------------------------------------------------------------- /kconfig/qconf-cfg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0 3 | 4 | cflags=$1 5 | libs=$2 6 | bin=$3 7 | 8 | PKG5="Qt5Core Qt5Gui Qt5Widgets" 9 | PKG6="Qt6Core Qt6Gui Qt6Widgets" 10 | 11 | if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then 12 | echo >&2 "*" 13 | echo >&2 "* 'make xconfig' requires '${HOSTPKG_CONFIG}'. Please install it." 14 | echo >&2 "*" 15 | exit 1 16 | fi 17 | 18 | if ${HOSTPKG_CONFIG} --exists $PKG6; then 19 | ${HOSTPKG_CONFIG} --cflags ${PKG6} > ${cflags} 20 | # Qt6 requires C++17. 21 | echo -std=c++17 >> ${cflags} 22 | ${HOSTPKG_CONFIG} --libs ${PKG6} > ${libs} 23 | ${HOSTPKG_CONFIG} --variable=libexecdir Qt6Core > ${bin} 24 | exit 0 25 | fi 26 | 27 | if ${HOSTPKG_CONFIG} --exists $PKG5; then 28 | ${HOSTPKG_CONFIG} --cflags ${PKG5} > ${cflags} 29 | ${HOSTPKG_CONFIG} --libs ${PKG5} > ${libs} 30 | ${HOSTPKG_CONFIG} --variable=host_bins Qt5Core > ${bin} 31 | exit 0 32 | fi 33 | 34 | echo >&2 "*" 35 | echo >&2 "* Could not find Qt6 or Qt5 via ${HOSTPKG_CONFIG}." 36 | echo >&2 "* Please install Qt6 or Qt5 and make sure it's in PKG_CONFIG_PATH" 37 | echo >&2 "* You need $PKG6 for Qt6" 38 | echo >&2 "* You need $PKG5 for Qt5" 39 | echo >&2 "*" 40 | exit 1 41 | -------------------------------------------------------------------------------- /kconfig/qconf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2002 Roman Zippel 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "expr.h" 19 | 20 | class ConfigList; 21 | class ConfigItem; 22 | class ConfigMainWindow; 23 | 24 | class ConfigSettings : public QSettings { 25 | public: 26 | ConfigSettings(); 27 | QList readSizes(const QString& key, bool *ok); 28 | bool writeSizes(const QString& key, const QList& value); 29 | }; 30 | 31 | enum colIdx { 32 | promptColIdx, nameColIdx, dataColIdx 33 | }; 34 | enum listMode { 35 | singleMode, menuMode, symbolMode, fullMode, listMode 36 | }; 37 | enum optionMode { 38 | normalOpt = 0, allOpt, promptOpt 39 | }; 40 | 41 | class ConfigList : public QTreeWidget { 42 | Q_OBJECT 43 | typedef class QTreeWidget Parent; 44 | public: 45 | ConfigList(QWidget *parent, const char *name = 0); 46 | ~ConfigList(); 47 | void reinit(void); 48 | ConfigItem* findConfigItem(struct menu *); 49 | void setSelected(QTreeWidgetItem *item, bool enable) { 50 | for (int i = 0; i < selectedItems().size(); i++) 51 | selectedItems().at(i)->setSelected(false); 52 | 53 | item->setSelected(enable); 54 | } 55 | 56 | protected: 57 | void keyPressEvent(QKeyEvent *e); 58 | void mousePressEvent(QMouseEvent *e); 59 | void mouseReleaseEvent(QMouseEvent *e); 60 | void mouseMoveEvent(QMouseEvent *e); 61 | void mouseDoubleClickEvent(QMouseEvent *e); 62 | void focusInEvent(QFocusEvent *e); 63 | void contextMenuEvent(QContextMenuEvent *e); 64 | 65 | public slots: 66 | void setRootMenu(struct menu *menu); 67 | 68 | void updateList(); 69 | void setValue(ConfigItem* item, tristate val); 70 | void changeValue(ConfigItem* item); 71 | void updateSelection(void); 72 | void saveSettings(void); 73 | void setOptionMode(QAction *action); 74 | void setShowName(bool on); 75 | 76 | signals: 77 | void menuChanged(struct menu *menu); 78 | void menuSelected(struct menu *menu); 79 | void itemSelected(struct menu *menu); 80 | void parentSelected(void); 81 | void gotFocus(struct menu *); 82 | void showNameChanged(bool on); 83 | 84 | public: 85 | void updateListAll(void) 86 | { 87 | updateAll = true; 88 | updateList(); 89 | updateAll = false; 90 | } 91 | void setAllOpen(bool open); 92 | void setParentMenu(void); 93 | 94 | bool menuSkip(struct menu *); 95 | 96 | void updateMenuList(ConfigItem *parent, struct menu*); 97 | void updateMenuList(struct menu *menu); 98 | 99 | bool updateAll; 100 | 101 | bool showName; 102 | enum listMode mode; 103 | enum optionMode optMode; 104 | struct menu *rootEntry; 105 | QPalette disabledColorGroup; 106 | QPalette inactivedColorGroup; 107 | QMenu* headerPopup; 108 | 109 | static QList allLists; 110 | static void updateListForAll(); 111 | static void updateListAllForAll(); 112 | 113 | static QAction *showNormalAction, *showAllAction, *showPromptAction; 114 | }; 115 | 116 | class ConfigItem : public QTreeWidgetItem { 117 | typedef class QTreeWidgetItem Parent; 118 | public: 119 | ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v) 120 | : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false) 121 | { 122 | init(); 123 | } 124 | ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) 125 | : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false) 126 | { 127 | init(); 128 | } 129 | ConfigItem(ConfigList *parent, ConfigItem *after, bool v) 130 | : Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true) 131 | { 132 | init(); 133 | } 134 | ~ConfigItem(void); 135 | void init(void); 136 | void updateMenu(void); 137 | void testUpdateMenu(bool v); 138 | ConfigList* listView() const 139 | { 140 | return (ConfigList*)Parent::treeWidget(); 141 | } 142 | ConfigItem* firstChild() const 143 | { 144 | return (ConfigItem *)Parent::child(0); 145 | } 146 | ConfigItem* nextSibling() 147 | { 148 | ConfigItem *ret = NULL; 149 | ConfigItem *_parent = (ConfigItem *)parent(); 150 | 151 | if(_parent) { 152 | ret = (ConfigItem *)_parent->child(_parent->indexOfChild(this)+1); 153 | } else { 154 | QTreeWidget *_treeWidget = treeWidget(); 155 | ret = (ConfigItem *)_treeWidget->topLevelItem(_treeWidget->indexOfTopLevelItem(this)+1); 156 | } 157 | 158 | return ret; 159 | } 160 | // TODO: Implement paintCell 161 | 162 | ConfigItem* nextItem; 163 | struct menu *menu; 164 | bool visible; 165 | bool goParent; 166 | 167 | static QIcon symbolYesIcon, symbolModIcon, symbolNoIcon; 168 | static QIcon choiceYesIcon, choiceNoIcon; 169 | static QIcon menuIcon, menubackIcon; 170 | }; 171 | 172 | class ConfigItemDelegate : public QStyledItemDelegate 173 | { 174 | private: 175 | struct menu *menu; 176 | public: 177 | ConfigItemDelegate(QObject *parent = nullptr) 178 | : QStyledItemDelegate(parent) {} 179 | QWidget *createEditor(QWidget *parent, 180 | const QStyleOptionViewItem &option, 181 | const QModelIndex &index) const override; 182 | void setModelData(QWidget *editor, QAbstractItemModel *model, 183 | const QModelIndex &index) const override; 184 | }; 185 | 186 | class ConfigInfoView : public QTextBrowser { 187 | Q_OBJECT 188 | typedef class QTextBrowser Parent; 189 | QMenu *contextMenu; 190 | public: 191 | ConfigInfoView(QWidget* parent, const char *name = 0); 192 | bool showDebug(void) const { return _showDebug; } 193 | 194 | public slots: 195 | void setInfo(struct menu *menu); 196 | void saveSettings(void); 197 | void setShowDebug(bool); 198 | void clicked (const QUrl &url); 199 | 200 | signals: 201 | void showDebugChanged(bool); 202 | void menuSelected(struct menu *); 203 | 204 | protected: 205 | void symbolInfo(void); 206 | void menuInfo(void); 207 | QString debug_info(struct symbol *sym); 208 | static QString print_filter(const QString &str); 209 | static void expr_print_help(void *data, struct symbol *sym, const char *str); 210 | void contextMenuEvent(QContextMenuEvent *event); 211 | 212 | struct symbol *sym; 213 | struct menu *_menu; 214 | bool _showDebug; 215 | }; 216 | 217 | class ConfigSearchWindow : public QDialog { 218 | Q_OBJECT 219 | typedef class QDialog Parent; 220 | public: 221 | ConfigSearchWindow(ConfigMainWindow *parent); 222 | 223 | public slots: 224 | void saveSettings(void); 225 | void search(void); 226 | 227 | protected: 228 | QLineEdit* editField; 229 | QPushButton* searchButton; 230 | QSplitter* split; 231 | ConfigList *list; 232 | ConfigInfoView* info; 233 | 234 | struct symbol **result; 235 | }; 236 | 237 | class ConfigMainWindow : public QMainWindow { 238 | Q_OBJECT 239 | 240 | char *configname; 241 | static QAction *saveAction; 242 | static void conf_changed(void); 243 | public: 244 | ConfigMainWindow(void); 245 | public slots: 246 | void changeMenu(struct menu *); 247 | void changeItens(struct menu *); 248 | void setMenuLink(struct menu *); 249 | void listFocusChanged(void); 250 | void goBack(void); 251 | void loadConfig(void); 252 | bool saveConfig(void); 253 | void saveConfigAs(void); 254 | void searchConfig(void); 255 | void showSingleView(void); 256 | void showSplitView(void); 257 | void showFullView(void); 258 | void showIntro(void); 259 | void showAbout(void); 260 | void saveSettings(void); 261 | 262 | protected: 263 | void closeEvent(QCloseEvent *e); 264 | 265 | ConfigSearchWindow *searchWindow; 266 | ConfigList *menuList; 267 | ConfigList *configList; 268 | ConfigInfoView *helpText; 269 | QAction *backAction; 270 | QAction *singleViewAction; 271 | QAction *splitViewAction; 272 | QAction *fullViewAction; 273 | QSplitter *split1; 274 | QSplitter *split2; 275 | }; 276 | -------------------------------------------------------------------------------- /kconfig/tests/auto_submenu/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | config A 4 | bool "A" 5 | default y 6 | 7 | config A0 8 | bool "A0" 9 | depends on A 10 | default y 11 | help 12 | This depends on A, so should be a submenu of A. 13 | 14 | config A0_0 15 | bool "A1_0" 16 | depends on A0 17 | help 18 | Submenus are created recursively. 19 | This should be a submenu of A0. 20 | 21 | config A1 22 | bool "A1" 23 | depends on A 24 | default y 25 | help 26 | This should line up with A0. 27 | 28 | choice 29 | prompt "choice" 30 | depends on A1 31 | help 32 | Choice should become a submenu as well. 33 | 34 | config A1_0 35 | bool "A1_0" 36 | 37 | config A1_1 38 | bool "A1_1" 39 | 40 | endchoice 41 | 42 | config B 43 | bool "B" 44 | help 45 | This is independent of A. 46 | 47 | config C 48 | bool "C" 49 | depends on A 50 | help 51 | This depends on A, but not a consecutive item, so can/should not 52 | be a submenu. 53 | -------------------------------------------------------------------------------- /kconfig/tests/auto_submenu/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Create submenu for symbols that depend on the preceding one. 4 | 5 | If a symbols has dependency on the preceding symbol, the menu entry 6 | should become the submenu of the preceding one, and displayed with 7 | deeper indentation. 8 | """ 9 | 10 | 11 | def test(conf): 12 | assert conf.oldaskconfig() == 0 13 | assert conf.stdout_contains('expected_stdout') 14 | -------------------------------------------------------------------------------- /kconfig/tests/auto_submenu/expected_stdout: -------------------------------------------------------------------------------- 1 | A (A) [Y/n/?] (NEW) 2 | A0 (A0) [Y/n/?] (NEW) 3 | A1_0 (A0_0) [N/y/?] (NEW) 4 | A1 (A1) [Y/n/?] (NEW) 5 | choice 6 | > 1. A1_0 (A1_0) (NEW) 7 | 2. A1_1 (A1_1) (NEW) 8 | choice[1-2?]: 9 | B (B) [N/y/?] (NEW) 10 | C (C) [N/y/?] (NEW) 11 | -------------------------------------------------------------------------------- /kconfig/tests/choice/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | config MODULES 4 | bool "Enable loadable module support" 5 | modules 6 | default y 7 | 8 | choice 9 | prompt "boolean choice" 10 | default BOOL_CHOICE1 11 | 12 | config BOOL_CHOICE0 13 | bool "choice 0" 14 | 15 | config BOOL_CHOICE1 16 | bool "choice 1" 17 | 18 | endchoice 19 | 20 | choice 21 | prompt "optional boolean choice" 22 | optional 23 | default OPT_BOOL_CHOICE1 24 | 25 | config OPT_BOOL_CHOICE0 26 | bool "choice 0" 27 | 28 | config OPT_BOOL_CHOICE1 29 | bool "choice 1" 30 | 31 | endchoice 32 | 33 | choice 34 | prompt "tristate choice" 35 | default TRI_CHOICE1 36 | 37 | config TRI_CHOICE0 38 | tristate "choice 0" 39 | 40 | config TRI_CHOICE1 41 | tristate "choice 1" 42 | 43 | endchoice 44 | 45 | choice 46 | prompt "optional tristate choice" 47 | optional 48 | default OPT_TRI_CHOICE1 49 | 50 | config OPT_TRI_CHOICE0 51 | tristate "choice 0" 52 | 53 | config OPT_TRI_CHOICE1 54 | tristate "choice 1" 55 | 56 | endchoice 57 | -------------------------------------------------------------------------------- /kconfig/tests/choice/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Basic choice tests. 4 | 5 | The handling of 'choice' is a bit complicated part in Kconfig. 6 | 7 | The behavior of 'y' choice is intuitive. If choice values are tristate, 8 | the choice can be 'm' where each value can be enabled independently. 9 | Also, if a choice is marked as 'optional', the whole choice can be 10 | invisible. 11 | """ 12 | 13 | 14 | def test_oldask0(conf): 15 | assert conf.oldaskconfig() == 0 16 | assert conf.stdout_contains('oldask0_expected_stdout') 17 | 18 | 19 | def test_oldask1(conf): 20 | assert conf.oldaskconfig('oldask1_config') == 0 21 | assert conf.stdout_contains('oldask1_expected_stdout') 22 | 23 | 24 | def test_allyes(conf): 25 | assert conf.allyesconfig() == 0 26 | assert conf.config_contains('allyes_expected_config') 27 | 28 | 29 | def test_allmod(conf): 30 | assert conf.allmodconfig() == 0 31 | assert conf.config_contains('allmod_expected_config') 32 | 33 | 34 | def test_allno(conf): 35 | assert conf.allnoconfig() == 0 36 | assert conf.config_contains('allno_expected_config') 37 | 38 | 39 | def test_alldef(conf): 40 | assert conf.alldefconfig() == 0 41 | assert conf.config_contains('alldef_expected_config') 42 | -------------------------------------------------------------------------------- /kconfig/tests/choice/alldef_expected_config: -------------------------------------------------------------------------------- 1 | CONFIG_MODULES=y 2 | # CONFIG_BOOL_CHOICE0 is not set 3 | CONFIG_BOOL_CHOICE1=y 4 | # CONFIG_TRI_CHOICE0 is not set 5 | # CONFIG_TRI_CHOICE1 is not set 6 | -------------------------------------------------------------------------------- /kconfig/tests/choice/allmod_expected_config: -------------------------------------------------------------------------------- 1 | CONFIG_MODULES=y 2 | # CONFIG_BOOL_CHOICE0 is not set 3 | CONFIG_BOOL_CHOICE1=y 4 | # CONFIG_OPT_BOOL_CHOICE0 is not set 5 | CONFIG_OPT_BOOL_CHOICE1=y 6 | CONFIG_TRI_CHOICE0=m 7 | CONFIG_TRI_CHOICE1=m 8 | CONFIG_OPT_TRI_CHOICE0=m 9 | CONFIG_OPT_TRI_CHOICE1=m 10 | -------------------------------------------------------------------------------- /kconfig/tests/choice/allno_expected_config: -------------------------------------------------------------------------------- 1 | # CONFIG_MODULES is not set 2 | # CONFIG_BOOL_CHOICE0 is not set 3 | CONFIG_BOOL_CHOICE1=y 4 | # CONFIG_TRI_CHOICE0 is not set 5 | CONFIG_TRI_CHOICE1=y 6 | -------------------------------------------------------------------------------- /kconfig/tests/choice/allyes_expected_config: -------------------------------------------------------------------------------- 1 | CONFIG_MODULES=y 2 | # CONFIG_BOOL_CHOICE0 is not set 3 | CONFIG_BOOL_CHOICE1=y 4 | # CONFIG_OPT_BOOL_CHOICE0 is not set 5 | CONFIG_OPT_BOOL_CHOICE1=y 6 | # CONFIG_TRI_CHOICE0 is not set 7 | CONFIG_TRI_CHOICE1=y 8 | # CONFIG_OPT_TRI_CHOICE0 is not set 9 | CONFIG_OPT_TRI_CHOICE1=y 10 | -------------------------------------------------------------------------------- /kconfig/tests/choice/oldask0_expected_stdout: -------------------------------------------------------------------------------- 1 | Enable loadable module support (MODULES) [Y/n/?] (NEW) 2 | boolean choice 3 | 1. choice 0 (BOOL_CHOICE0) (NEW) 4 | > 2. choice 1 (BOOL_CHOICE1) (NEW) 5 | choice[1-2?]: 6 | optional boolean choice [N/y/?] (NEW) 7 | tristate choice [M/y/?] (NEW) 8 | choice 0 (TRI_CHOICE0) [N/m/?] (NEW) 9 | choice 1 (TRI_CHOICE1) [N/m/?] (NEW) 10 | optional tristate choice [N/m/y/?] (NEW) 11 | -------------------------------------------------------------------------------- /kconfig/tests/choice/oldask1_config: -------------------------------------------------------------------------------- 1 | # CONFIG_MODULES is not set 2 | CONFIG_OPT_BOOL_CHOICE0=y 3 | -------------------------------------------------------------------------------- /kconfig/tests/choice/oldask1_expected_stdout: -------------------------------------------------------------------------------- 1 | Enable loadable module support (MODULES) [N/y/?] 2 | boolean choice 3 | 1. choice 0 (BOOL_CHOICE0) (NEW) 4 | > 2. choice 1 (BOOL_CHOICE1) (NEW) 5 | choice[1-2?]: 6 | optional boolean choice [Y/n/?] (NEW) 7 | optional boolean choice 8 | > 1. choice 0 (OPT_BOOL_CHOICE0) 9 | 2. choice 1 (OPT_BOOL_CHOICE1) (NEW) 10 | choice[1-2?]: 11 | tristate choice 12 | 1. choice 0 (TRI_CHOICE0) (NEW) 13 | > 2. choice 1 (TRI_CHOICE1) (NEW) 14 | choice[1-2?]: 15 | optional tristate choice [N/y/?] 16 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize/Kconfig: -------------------------------------------------------------------------------- 1 | choice 2 | prompt "choose A or B" 3 | 4 | config A 5 | bool "A" 6 | 7 | config B 8 | bool "B" 9 | 10 | endchoice 11 | 12 | choice 13 | prompt "choose X or Y" 14 | depends on B 15 | 16 | config X 17 | bool "X" 18 | 19 | config Y 20 | bool "Y" 21 | 22 | endchoice 23 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | """ 3 | Randomize all dependent choices 4 | 5 | This is a somewhat tricky case for randconfig; the visibility of one choice is 6 | determined by a member of another choice. Randconfig should be able to generate 7 | all possible patterns. 8 | """ 9 | 10 | 11 | def test(conf): 12 | 13 | expected0 = False 14 | expected1 = False 15 | expected2 = False 16 | 17 | for i in range(100): 18 | assert conf.randconfig(seed=i) == 0 19 | 20 | if conf.config_matches('expected_config0'): 21 | expected0 = True 22 | elif conf.config_matches('expected_config1'): 23 | expected1 = True 24 | elif conf.config_matches('expected_config2'): 25 | expected2 = True 26 | else: 27 | assert False 28 | 29 | if expected0 and expected1 and expected2: 30 | break 31 | 32 | assert expected0 33 | assert expected1 34 | assert expected2 35 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize/expected_config0: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Main menu 4 | # 5 | CONFIG_A=y 6 | # CONFIG_B is not set 7 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize/expected_config1: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Main menu 4 | # 5 | # CONFIG_A is not set 6 | CONFIG_B=y 7 | CONFIG_X=y 8 | # CONFIG_Y is not set 9 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize/expected_config2: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Main menu 4 | # 5 | # CONFIG_A is not set 6 | CONFIG_B=y 7 | # CONFIG_X is not set 8 | CONFIG_Y=y 9 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize2/Kconfig: -------------------------------------------------------------------------------- 1 | choice 2 | prompt "This is always invisible" 3 | depends on n 4 | 5 | config DUMMY 6 | bool "DUMMY" 7 | 8 | endchoice 9 | 10 | choice 11 | prompt "Choose A or B" 12 | 13 | config A 14 | bool "A" 15 | 16 | config B 17 | bool "B" 18 | 19 | endchoice 20 | 21 | config FOO 22 | bool "FOO" 23 | depends on A 24 | 25 | choice 26 | prompt "Choose X" 27 | depends on FOO 28 | 29 | config X 30 | bool "X" 31 | 32 | endchoice 33 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize2/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | """ 3 | Randomize choices with correct dependencies 4 | 5 | When shuffling a choice may potentially disrupt certain dependencies, symbol 6 | values must be recalculated. 7 | 8 | Related Linux commits: 9 | - c8fb7d7e48d11520ad24808cfce7afb7b9c9f798 10 | """ 11 | 12 | 13 | def test(conf): 14 | for i in range(20): 15 | assert conf.randconfig(seed=i) == 0 16 | assert (conf.config_matches('expected_config0') or 17 | conf.config_matches('expected_config1') or 18 | conf.config_matches('expected_config2')) 19 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize2/expected_config0: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Main menu 4 | # 5 | CONFIG_A=y 6 | # CONFIG_B is not set 7 | CONFIG_FOO=y 8 | CONFIG_X=y 9 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize2/expected_config1: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Main menu 4 | # 5 | CONFIG_A=y 6 | # CONFIG_B is not set 7 | # CONFIG_FOO is not set 8 | -------------------------------------------------------------------------------- /kconfig/tests/choice_randomize2/expected_config2: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Main menu 4 | # 5 | # CONFIG_A is not set 6 | CONFIG_B=y 7 | -------------------------------------------------------------------------------- /kconfig/tests/choice_value_with_m_dep/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | config MODULES 4 | def_bool y 5 | modules 6 | 7 | config DEP 8 | tristate 9 | default m 10 | 11 | choice 12 | prompt "Tristate Choice" 13 | 14 | config CHOICE0 15 | tristate "Choice 0" 16 | 17 | config CHOICE1 18 | tristate "Choice 1" 19 | depends on DEP 20 | 21 | endchoice 22 | -------------------------------------------------------------------------------- /kconfig/tests/choice_value_with_m_dep/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Hide tristate choice values with mod dependency in y choice. 4 | 5 | If tristate choice values depend on symbols set to 'm', they should be 6 | hidden when the choice containing them is changed from 'm' to 'y' 7 | (i.e. exclusive choice). 8 | 9 | Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074 10 | """ 11 | 12 | 13 | def test(conf): 14 | assert conf.oldaskconfig('config', 'y') == 0 15 | assert conf.config_contains('expected_config') 16 | assert conf.stdout_contains('expected_stdout') 17 | -------------------------------------------------------------------------------- /kconfig/tests/choice_value_with_m_dep/config: -------------------------------------------------------------------------------- 1 | CONFIG_CHOICE0=m 2 | CONFIG_CHOICE1=m 3 | -------------------------------------------------------------------------------- /kconfig/tests/choice_value_with_m_dep/expected_config: -------------------------------------------------------------------------------- 1 | CONFIG_MODULES=y 2 | CONFIG_DEP=m 3 | CONFIG_CHOICE0=y 4 | -------------------------------------------------------------------------------- /kconfig/tests/choice_value_with_m_dep/expected_stdout: -------------------------------------------------------------------------------- 1 | Tristate Choice [M/y/?] y 2 | Tristate Choice 3 | > 1. Choice 0 (CHOICE0) 4 | choice[1]: 1 5 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_dep/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | # depends on itself 4 | 5 | config A 6 | bool "A" 7 | depends on A 8 | 9 | # select itself 10 | 11 | config B 12 | bool 13 | select B 14 | 15 | # depends on each other 16 | 17 | config C1 18 | bool "C1" 19 | depends on C2 20 | 21 | config C2 22 | bool "C2" 23 | depends on C1 24 | 25 | # depends on and select 26 | 27 | config D1 28 | bool "D1" 29 | depends on D2 30 | select D2 31 | 32 | config D2 33 | bool 34 | 35 | # depends on and imply 36 | 37 | config E1 38 | bool "E1" 39 | depends on E2 40 | imply E2 41 | 42 | config E2 43 | bool "E2" 44 | 45 | # property 46 | 47 | config F1 48 | bool "F1" 49 | default F2 50 | 51 | config F2 52 | bool "F2" 53 | depends on F1 54 | 55 | # menu 56 | 57 | menu "menu depending on its content" 58 | depends on G 59 | 60 | config G 61 | bool "G" 62 | 63 | endmenu 64 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_dep/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Detect recursive dependency error. 4 | 5 | Recursive dependency should be treated as an error. 6 | """ 7 | 8 | def test(conf): 9 | assert conf.oldaskconfig() == 1 10 | assert conf.stderr_contains('expected_stderr') 11 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_dep/expected_stderr: -------------------------------------------------------------------------------- 1 | Kconfig:5:error: recursive dependency detected! 2 | Kconfig:5: symbol A depends on A 3 | For a resolution refer to Documentation/kbuild/kconfig-language.rst 4 | subsection "Kconfig recursive dependency limitations" 5 | 6 | Kconfig:11:error: recursive dependency detected! 7 | Kconfig:11: symbol B is selected by B 8 | For a resolution refer to Documentation/kbuild/kconfig-language.rst 9 | subsection "Kconfig recursive dependency limitations" 10 | 11 | Kconfig:17:error: recursive dependency detected! 12 | Kconfig:17: symbol C1 depends on C2 13 | Kconfig:21: symbol C2 depends on C1 14 | For a resolution refer to Documentation/kbuild/kconfig-language.rst 15 | subsection "Kconfig recursive dependency limitations" 16 | 17 | Kconfig:27:error: recursive dependency detected! 18 | Kconfig:27: symbol D1 depends on D2 19 | Kconfig:32: symbol D2 is selected by D1 20 | For a resolution refer to Documentation/kbuild/kconfig-language.rst 21 | subsection "Kconfig recursive dependency limitations" 22 | 23 | Kconfig:37:error: recursive dependency detected! 24 | Kconfig:37: symbol E1 depends on E2 25 | Kconfig:42: symbol E2 is implied by E1 26 | For a resolution refer to Documentation/kbuild/kconfig-language.rst 27 | subsection "Kconfig recursive dependency limitations" 28 | 29 | Kconfig:49:error: recursive dependency detected! 30 | Kconfig:49: symbol F1 default value contains F2 31 | Kconfig:51: symbol F2 depends on F1 32 | For a resolution refer to Documentation/kbuild/kconfig-language.rst 33 | subsection "Kconfig recursive dependency limitations" 34 | 35 | Kconfig:60:error: recursive dependency detected! 36 | Kconfig:60: symbol G depends on G 37 | For a resolution refer to Documentation/kbuild/kconfig-language.rst 38 | subsection "Kconfig recursive dependency limitations" 39 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_inc/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | source "Kconfig.inc1" 3 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_inc/Kconfig.inc1: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | 3 | 4 | 5 | source "Kconfig.inc2" 6 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_inc/Kconfig.inc2: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | 3 | 4 | source "Kconfig.inc3" 5 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_inc/Kconfig.inc3: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | source "Kconfig.inc1" 3 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_inc/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Detect recursive inclusion error. 4 | 5 | If recursive inclusion is detected, it should fail with error messages. 6 | """ 7 | 8 | 9 | def test(conf): 10 | assert conf.oldaskconfig() != 0 11 | assert conf.stderr_contains('expected_stderr') 12 | -------------------------------------------------------------------------------- /kconfig/tests/err_recursive_inc/expected_stderr: -------------------------------------------------------------------------------- 1 | Recursive inclusion detected. 2 | Inclusion path: 3 | current file : Kconfig.inc1 4 | included from: Kconfig.inc3:2 5 | included from: Kconfig.inc2:4 6 | included from: Kconfig.inc1:5 7 | -------------------------------------------------------------------------------- /kconfig/tests/inter_choice/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | config MODULES 4 | def_bool y 5 | modules 6 | 7 | choice 8 | prompt "Choice" 9 | 10 | config CHOICE_VAL0 11 | tristate "Choice 0" 12 | 13 | config CHOIVE_VAL1 14 | tristate "Choice 1" 15 | 16 | endchoice 17 | 18 | choice 19 | prompt "Another choice" 20 | depends on CHOICE_VAL0 21 | 22 | config DUMMY 23 | bool "dummy" 24 | 25 | endchoice 26 | -------------------------------------------------------------------------------- /kconfig/tests/inter_choice/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Do not affect user-assigned choice value by another choice. 4 | 5 | Handling of state flags for choices is complecated. In old days, 6 | the defconfig result of a choice could be affected by another choice 7 | if those choices interact by 'depends on', 'select', etc. 8 | 9 | Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a 10 | """ 11 | 12 | 13 | def test(conf): 14 | assert conf.defconfig('defconfig') == 0 15 | assert conf.config_contains('expected_config') 16 | -------------------------------------------------------------------------------- /kconfig/tests/inter_choice/defconfig: -------------------------------------------------------------------------------- 1 | CONFIG_CHOICE_VAL0=y 2 | -------------------------------------------------------------------------------- /kconfig/tests/inter_choice/expected_config: -------------------------------------------------------------------------------- 1 | CONFIG_MODULES=y 2 | CONFIG_CHOICE_VAL0=y 3 | # CONFIG_CHOIVE_VAL1 is not set 4 | CONFIG_DUMMY=y 5 | -------------------------------------------------------------------------------- /kconfig/tests/new_choice_with_dep/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | config A 4 | bool "A" 5 | help 6 | This is a new symbol. 7 | 8 | choice 9 | prompt "Choice ?" 10 | depends on A 11 | help 12 | "depends on A" has been newly added. 13 | 14 | config CHOICE_B 15 | bool "Choice B" 16 | 17 | config CHOICE_C 18 | bool "Choice C" 19 | help 20 | This is a new symbol, so should be asked. 21 | 22 | endchoice 23 | 24 | choice 25 | prompt "Choice2 ?" 26 | 27 | config CHOICE_D 28 | bool "Choice D" 29 | 30 | config CHOICE_E 31 | bool "Choice E" 32 | 33 | config CHOICE_F 34 | bool "Choice F" 35 | depends on A 36 | help 37 | This is a new symbol, so should be asked. 38 | 39 | endchoice 40 | -------------------------------------------------------------------------------- /kconfig/tests/new_choice_with_dep/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Ask new choice values when they become visible. 4 | 5 | If new choice values are added with new dependency, and they become 6 | visible during user configuration, oldconfig should recognize them 7 | as (NEW), and ask the user for choice. 8 | 9 | Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5 10 | """ 11 | 12 | 13 | def test(conf): 14 | assert conf.oldconfig('config', 'y') == 0 15 | assert conf.stdout_contains('expected_stdout') 16 | -------------------------------------------------------------------------------- /kconfig/tests/new_choice_with_dep/config: -------------------------------------------------------------------------------- 1 | CONFIG_CHOICE_B=y 2 | # CONFIG_CHOICE_D is not set 3 | CONFIG_CHOICE_E=y 4 | -------------------------------------------------------------------------------- /kconfig/tests/new_choice_with_dep/expected_stdout: -------------------------------------------------------------------------------- 1 | A (A) [N/y/?] (NEW) y 2 | Choice ? 3 | > 1. Choice B (CHOICE_B) 4 | 2. Choice C (CHOICE_C) (NEW) 5 | choice[1-2?]: 6 | Choice2 ? 7 | 1. Choice D (CHOICE_D) 8 | > 2. Choice E (CHOICE_E) 9 | 3. Choice F (CHOICE_F) (NEW) 10 | choice[1-3?]: 11 | -------------------------------------------------------------------------------- /kconfig/tests/no_write_if_dep_unmet/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | config A 4 | bool "A" 5 | 6 | choice 7 | prompt "Choice ?" 8 | depends on A 9 | 10 | config CHOICE_B 11 | bool "Choice B" 12 | 13 | config CHOICE_C 14 | bool "Choice C" 15 | 16 | endchoice 17 | -------------------------------------------------------------------------------- /kconfig/tests/no_write_if_dep_unmet/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Do not write choice values to .config if the dependency is unmet. 4 | 5 | "# CONFIG_... is not set" should not be written into the .config file 6 | for symbols with unmet dependency. 7 | 8 | This was not working correctly for choice values because choice needs 9 | a bit different symbol computation. 10 | 11 | This checks that no unneeded "# COFIG_... is not set" is contained in 12 | the .config file. 13 | 14 | Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59 15 | """ 16 | 17 | 18 | def test(conf): 19 | assert conf.oldaskconfig('config', 'n') == 0 20 | assert conf.config_matches('expected_config') 21 | -------------------------------------------------------------------------------- /kconfig/tests/no_write_if_dep_unmet/config: -------------------------------------------------------------------------------- 1 | CONFIG_A=y 2 | -------------------------------------------------------------------------------- /kconfig/tests/no_write_if_dep_unmet/expected_config: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Main menu 4 | # 5 | # CONFIG_A is not set 6 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/builtin_func/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | # 'info' prints the argument to stdout. 4 | $(info,hello world 0) 5 | 6 | # 'warning-if', if the first argument is y, sends the second argument to stderr, 7 | # and the message is prefixed with the current file name and line number. 8 | $(warning-if,y,hello world 1) 9 | 10 | # 'error-if' is similar, but it terminates the parsing immediately. 11 | # The following is just no-op since the first argument is not y. 12 | $(error-if,n,this should not be printed) 13 | 14 | # Shorthand 15 | warning = $(warning-if,y,$(1)) 16 | 17 | # 'shell' executes a command, and returns its stdout. 18 | $(warning,$(shell,echo hello world 3)) 19 | 20 | # Every newline in the output is replaced with a space, 21 | # but any trailing newlines are deleted. 22 | $(warning,$(shell,printf 'hello\nworld\n\n4\n\n\n')) 23 | 24 | # 'filename' is expanded to the currently parsed file name, 25 | # 'lineno' to the line number. 26 | $(warning,filename=$(filename)) 27 | $(warning,lineno=$(lineno)) 28 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/builtin_func/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Built-in function tests. 4 | """ 5 | 6 | def test(conf): 7 | assert conf.oldaskconfig() == 0 8 | assert conf.stdout_contains('expected_stdout') 9 | assert conf.stderr_matches('expected_stderr') 10 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/builtin_func/expected_stderr: -------------------------------------------------------------------------------- 1 | Kconfig:8: hello world 1 2 | Kconfig:18: hello world 3 3 | Kconfig:22: hello world 4 4 | Kconfig:26: filename=Kconfig 5 | Kconfig:27: lineno=27 6 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/builtin_func/expected_stdout: -------------------------------------------------------------------------------- 1 | hello world 0 2 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/circular_expansion/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | X = $(Y) 4 | Y = $(X) 5 | $(info $(X)) 6 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/circular_expansion/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Detect circular variable expansion. 4 | 5 | If a recursively expanded variable references itself (eventually), 6 | it should fail with an error message. 7 | """ 8 | 9 | def test(conf): 10 | assert conf.oldaskconfig() != 0 11 | assert conf.stderr_matches('expected_stderr') 12 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/circular_expansion/expected_stderr: -------------------------------------------------------------------------------- 1 | Kconfig:5: Recursive variable 'X' references itself (eventually) 2 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/escape/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | # Shorthand 4 | warning = $(warning-if,y,$(1)) 5 | 6 | # You can not pass commas directly to a function since they are treated as 7 | # delimiters. You can use the following trick to do so. 8 | comma := , 9 | $(warning,hello$(comma) world) 10 | 11 | # Like Make, single quotes, double quotes, spaces are treated verbatim. 12 | # The following prints the text as-is. 13 | $(warning, ' " '" ' ''' "'") 14 | 15 | # Unlike Make, '$' has special meaning only when it is followed by '('. 16 | # No need to escape '$' itself. 17 | $(warning,$) 18 | $(warning,$$) 19 | $ := 1 20 | $(warning,$($)) 21 | 22 | # You need a trick to escape '$' followed by '(' 23 | # The following should print "$(X)". It should not be expanded further. 24 | dollar := $ 25 | $(warning,$(dollar)(X)) 26 | 27 | # You need a trick to treat unbalanced parentheses. 28 | # The following should print "(". 29 | left_paren := ( 30 | $(warning,$(left_paren)) 31 | 32 | # A simple expanded should not be expanded multiple times. 33 | # The following should print "$(X)". It should not be expanded further. 34 | Y := $(dollar)(X) 35 | $(warning,$(Y)) 36 | 37 | # The following should print "$(X)" as well. 38 | Y = $(dollar)(X) 39 | $(warning,$(Y)) 40 | 41 | # The following should print "$(". 42 | # It should not be emit "unterminated reference" error. 43 | unterminated := $(dollar)( 44 | $(warning,$(unterminated)) 45 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/escape/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Escape sequence tests. 4 | """ 5 | 6 | def test(conf): 7 | assert conf.oldaskconfig() == 0 8 | assert conf.stderr_matches('expected_stderr') 9 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/escape/expected_stderr: -------------------------------------------------------------------------------- 1 | Kconfig:9: hello, world 2 | Kconfig:13: ' " '" ' ''' "'" 3 | Kconfig:17: $ 4 | Kconfig:18: $$ 5 | Kconfig:20: 1 6 | Kconfig:25: $(X) 7 | Kconfig:30: ( 8 | Kconfig:35: $(X) 9 | Kconfig:39: $(X) 10 | Kconfig:44: $( 11 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/variable/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | # Shorthand 4 | warning = $(warning-if,y,$(1)) 5 | 6 | # Simply expanded variable. 7 | X := 1 8 | SIMPLE := $(X) 9 | X := 2 10 | $(warning,SIMPLE = $(SIMPLE)) 11 | 12 | # Recursively expanded variable. 13 | X := 1 14 | RECURSIVE = $(X) 15 | X := 2 16 | $(warning,RECURSIVE = $(RECURSIVE)) 17 | 18 | # Append something to a simply expanded variable. 19 | Y := 3 20 | SIMPLE += $(Y) 21 | Y := 4 22 | $(warning,SIMPLE = $(SIMPLE)) 23 | 24 | # Append something to a recursively expanded variable. 25 | Y := 3 26 | RECURSIVE += $(Y) 27 | Y := 4 28 | $(warning,RECURSIVE = $(RECURSIVE)) 29 | 30 | # Use += operator to an undefined variable. 31 | # This works as a recursively expanded variable. 32 | Y := 3 33 | UNDEFINED_VARIABLE += $(Y) 34 | Y := 4 35 | $(warning,UNDEFINED_VARIABLE = $(UNDEFINED_VARIABLE)) 36 | 37 | # You can use variable references for the lefthand side of assignment statement. 38 | X := A 39 | Y := B 40 | $(X)$(Y) := 5 41 | $(warning,AB = $(AB)) 42 | 43 | # User-defined function. 44 | greeting = $(1), my name is $(2). 45 | $(warning,$(greeting,Hello,John)) 46 | 47 | # The number of arguments is not checked for user-defined functions. 48 | # If some arguments are optional, it is useful to pass fewer parameters. 49 | # $(2) will be blank in this case. 50 | $(warning,$(greeting,Hello)) 51 | 52 | # Unreferenced parameters are just ignored. 53 | $(warning,$(greeting,Hello,John,ignored,ignored)) 54 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/variable/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | """ 3 | Variable and user-defined function tests. 4 | """ 5 | 6 | def test(conf): 7 | assert conf.oldaskconfig() == 0 8 | assert conf.stderr_matches('expected_stderr') 9 | -------------------------------------------------------------------------------- /kconfig/tests/preprocess/variable/expected_stderr: -------------------------------------------------------------------------------- 1 | Kconfig:10: SIMPLE = 1 2 | Kconfig:16: RECURSIVE = 2 3 | Kconfig:22: SIMPLE = 1 3 4 | Kconfig:28: RECURSIVE = 2 4 5 | Kconfig:35: UNDEFINED_VARIABLE = 4 6 | Kconfig:41: AB = 5 7 | Kconfig:45: Hello, my name is John. 8 | Kconfig:50: Hello, my name is . 9 | Kconfig:53: Hello, my name is John. 10 | -------------------------------------------------------------------------------- /kconfig/tests/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = --verbose 3 | 4 | # Pytest requires that test files have unique names, because pytest imports 5 | # them as top-level modules. It is silly to prefix or suffix a test file with 6 | # the directory name that contains it. Use __init__.py for all test files. 7 | python_files = __init__.py 8 | -------------------------------------------------------------------------------- /kconfig/util.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2002-2005 Roman Zippel 4 | * Copyright (C) 2002-2005 Sam Ravnborg 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "hashtable.h" 12 | #include "lkc.h" 13 | 14 | unsigned int strhash(const char *s) 15 | { 16 | /* fnv32 hash */ 17 | unsigned int hash = 2166136261U; 18 | 19 | for (; *s; s++) 20 | hash = (hash ^ *s) * 0x01000193; 21 | return hash; 22 | } 23 | 24 | /* hash table of all parsed Kconfig files */ 25 | static HASHTABLE_DEFINE(file_hashtable, 1U << 11); 26 | 27 | struct file { 28 | struct hlist_node node; 29 | char name[]; 30 | }; 31 | 32 | /* file already present in list? If not add it */ 33 | const char *file_lookup(const char *name) 34 | { 35 | struct file *file; 36 | size_t len; 37 | int hash = strhash(name); 38 | 39 | hash_for_each_possible(file_hashtable, file, node, hash) 40 | if (!strcmp(name, file->name)) 41 | return file->name; 42 | 43 | len = strlen(name); 44 | file = xmalloc(sizeof(*file) + len + 1); 45 | memset(file, 0, sizeof(*file)); 46 | memcpy(file->name, name, len); 47 | file->name[len] = '\0'; 48 | 49 | hash_add(file_hashtable, &file->node, hash); 50 | 51 | str_printf(&autoconf_cmd, "\t%s \\\n", name); 52 | 53 | return file->name; 54 | } 55 | 56 | /* Allocate initial growable string */ 57 | struct gstr str_new(void) 58 | { 59 | struct gstr gs; 60 | gs.s = xmalloc(sizeof(char) * 64); 61 | gs.len = 64; 62 | gs.max_width = 0; 63 | strcpy(gs.s, "\0"); 64 | return gs; 65 | } 66 | 67 | /* Free storage for growable string */ 68 | void str_free(struct gstr *gs) 69 | { 70 | free(gs->s); 71 | gs->s = NULL; 72 | gs->len = 0; 73 | } 74 | 75 | /* Append to growable string */ 76 | void str_append(struct gstr *gs, const char *s) 77 | { 78 | size_t l; 79 | if (s) { 80 | l = strlen(gs->s) + strlen(s) + 1; 81 | if (l > gs->len) { 82 | gs->s = xrealloc(gs->s, l); 83 | gs->len = l; 84 | } 85 | strcat(gs->s, s); 86 | } 87 | } 88 | 89 | /* Append printf formatted string to growable string */ 90 | void str_printf(struct gstr *gs, const char *fmt, ...) 91 | { 92 | va_list ap; 93 | char s[10000]; /* big enough... */ 94 | va_start(ap, fmt); 95 | vsnprintf(s, sizeof(s), fmt, ap); 96 | str_append(gs, s); 97 | va_end(ap); 98 | } 99 | 100 | /* Retrieve value of growable string */ 101 | char *str_get(struct gstr *gs) 102 | { 103 | return gs->s; 104 | } 105 | 106 | void *xmalloc(size_t size) 107 | { 108 | void *p = malloc(size); 109 | if (p) 110 | return p; 111 | fprintf(stderr, "Out of memory.\n"); 112 | exit(1); 113 | } 114 | 115 | void *xcalloc(size_t nmemb, size_t size) 116 | { 117 | void *p = calloc(nmemb, size); 118 | if (p) 119 | return p; 120 | fprintf(stderr, "Out of memory.\n"); 121 | exit(1); 122 | } 123 | 124 | void *xrealloc(void *p, size_t size) 125 | { 126 | p = realloc(p, size); 127 | if (p) 128 | return p; 129 | fprintf(stderr, "Out of memory.\n"); 130 | exit(1); 131 | } 132 | 133 | char *xstrdup(const char *s) 134 | { 135 | char *p; 136 | 137 | p = strdup(s); 138 | if (p) 139 | return p; 140 | fprintf(stderr, "Out of memory.\n"); 141 | exit(1); 142 | } 143 | 144 | char *xstrndup(const char *s, size_t n) 145 | { 146 | char *p; 147 | 148 | p = strndup(s, n); 149 | if (p) 150 | return p; 151 | fprintf(stderr, "Out of memory.\n"); 152 | exit(1); 153 | } 154 | -------------------------------------------------------------------------------- /sync_with_linux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | function usage() 3 | { 4 | echo "Usage:" 5 | echo "$0 " 6 | exit 1 7 | } 8 | 9 | LINUX_SRC="$1" 10 | 11 | if [ ! -d "$LINUX_SRC" ]; 12 | then 13 | LINUX_SRC="/usr/src/linux-headers-$(uname -r)" 14 | fi 15 | 16 | if [ ! -d "$LINUX_SRC" ]; 17 | then 18 | usage $0 19 | else 20 | echo "sync with $LINUX_SRC" 21 | fi 22 | 23 | DST="." 24 | 25 | rm -rf ${DST}/fixdep 26 | cp -rv ${LINUX_SRC}/scripts/basic ${DST}/fixdep 27 | 28 | for f in Kbuild.include Makefile.build Makefile.clean Makefile.host Makefile.lib Makefile.userprogs Makefile.compiler; do 29 | cp -v ${LINUX_SRC}/scripts/$f ${DST}/kbuild/scripts/$f 30 | done 31 | 32 | rm -rf ${DST}/kconfig 33 | cp -rv ${LINUX_SRC}/scripts/kconfig ${DST}/kconfig 34 | cp -v ${LINUX_SRC}/scripts/unifdef.c ${DST}/unifdef/ 35 | -------------------------------------------------------------------------------- /unifdef/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | 3 | hostprogs := unifdef 4 | always-y := $(hostprogs) 5 | --------------------------------------------------------------------------------