Compare commits

...

12 Commits

129 changed files with 24148 additions and 59 deletions

View File

@ -7,6 +7,10 @@ root = true
indent_style = tab
indent_size = 8
[Makefile]
indent_style = tab
indent_size = 8
[*]
end_of_line = lf
charset = utf-8

11
.gitignore vendored
View File

@ -11,7 +11,16 @@
.modules.order.cmd
.Module.symvers.cmd
*.dmp
.config
.config.old
Module.symvers
modules.order
compile_commands.json
output/
/.cache/
/include/
/output/

View File

@ -0,0 +1,97 @@
#*******************************************************************************
# HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
# Author :
# Version : V1.0.0 2020.10.21
# Description :
# Note : yegaoyang@hikvision.com.cn Modified 2020.10.21
#*******************************************************************************
#*******************************************************************************
# Path information
#*******************************************************************************
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
DRIVER_DIR := $(realpath $(LOCAL_DIR)/../../..)
KERNEL_DIR ?= /home/gaoyang3513/Source/06-SG20x/02-Projects/SDK_SG200x_V2/linux_5.10/build/sg2000_milkv_duos_glibc_arm64_sd
#KERNEL_DIR ?= $(HOME)/Source/06-SG20x/02-Projects/SDK_SG200x_V2/linux_5.10/build/sg2000_milkv_duos_glibc_arm64_sd/
# ParDirectory
LIBS_DIR :=
INCLUDE_DIR :=
# Subdirectory
# Output
OUTPUT_DIR := $(LOCAL_DIR)/output
INSTALL_DIR ?= $(LOCAL_DIR)/__install
#*******************************************************************************
# Variables
#*******************************************************************************
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
MOD_NAME := osal
#*******************************************************************************
# Compile configure
#*******************************************************************************
ARCH ?= arm64
CROSS_COMPILE ?= ${HOME}/Source/06-SG20x/02-Projects/SDK_SG200x_V2/host-tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
OBJDUMP := $(CROSS_COMPILE)objdump
export ARCH CROSS_COMPILE
#*******************************************************************************
# Targets
#*******************************************************************************
# Read auto.conf if it exists, otherwise ignore
-include $(DRIVER_DIR)/include/config/auto.conf
.PHONY: all install clean
ifeq ($(CONFIG_DRIVER_BUS_PLATFORM_OSDEV),)
all:
$(Q)echo -n ""
install:
$(Q)echo "[SKIP] OSAL_osdev"
else ifeq ($(KERNELRELEASE),)
all: init
@$(MAKE) modules -C $(KERNEL_DIR) M=$(LOCAL_DIR) -j$(MULTI_CORES)
# @$(MAKE) modules_install -C $(KERNEL_DIR) M=$(LOCAL_DIR) INSTALL_MOD_PATH=$(KERNEL_DIR)/_install_modules INSTALL_MOD_DIR=private
@$(OBJDUMP) -hdS $(MOD_NAME).o > $(MOD_NAME).dmp
clean:
# File
@for n in *.o *.ko *.mod.c *.mod *.cmd *.symvers *.order; do \
find $(LOCAL_DIR) -type f -name $$n -exec rm {} \;;\
done
# Directory
@if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
@if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
@if [ -d $(LOCAL_DIR)/.tmp_versions ]; then rm -rf $(LOCAL_DIR)/.tmp_versions; fi;
install:
@mkdir -p $(INSTALL_DIR)/lib/modules/private
@install -m 644 -D $(MOD_NAME).ko $(INSTALL_DIR)/lib/modules/private;
init:
@mkdir -p $(OUTPUT_DIR)
else
obj-m := $(MOD_NAME).o
$(MOD_NAME)-objs := OSAL_osdev.o
INC_DIRS :=
ccflags-y +=
EXTRA_CFLAGS += -Wno-error=date-time # Fix compile error on gcc 4.9 and later
EXTRA_CFLAGS += -Wno-date-time -g
endif # ifeq ($(KERNELRELEASE),)

View File

@ -0,0 +1,186 @@
/*******************************************************************************
* HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
* Author :
* Version : V1.0.0 2024.11.15
* Description :
* Note : anonymity@hikvision.com.cn Modified 2024.11.15
******************************************************************************/
#include <stdarg.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/kdev_t.h> // MKDEV
#include "OSAL_osdev.h"
struct device osal_bus = {
.init_name = "osal",
};
struct bus_type osal_bus_type = {
.name = "osal",
};
struct osdev_device { // Object
struct osdev osdev; // Proxy
struct device dev;
char name[];
};
struct osdev_driver {
struct device_driver drv;
};
static void osadev_device_release(struct device *dev)
{
struct osdev_device *osdev_obj = container_of(dev, struct osdev_device, dev);
kfree(osdev_obj);
}
OSAL_osdev *OSAL_osdevAlloc(const char *name, int id)
{
struct device *dev = NULL;
struct osdev *osdev = NULL;
struct osdev_device *osdev_obj = NULL;
osdev_obj = kzalloc(sizeof(struct osdev_device) + strlen(name) + 1, GFP_KERNEL);
if (!osdev_obj) {
pr_err("ErrNo(%ld), alloc memory for OSAL_sysDevice failed.", PTR_ERR(dev));
return ERR_PTR(-ENOMEM);
}
osdev = &(osdev_obj->osdev);
dev = &(osdev_obj->dev);
strcpy(osdev_obj->name, name);
osdev->name = osdev_obj->name;
osdev->id = id;
device_initialize(dev);
dev->release = osadev_device_release;
osdev->obj = osdev;
return (OSAL_osdev *)osdev;
}
EXPORT_SYMBOL(OSAL_osdevAlloc);
int OSAL_osdevRegister(OSAL_osdev *osdev)
{
int ret = 0;
struct device *dev = NULL;
struct osdev *osdev_tmp = NULL;
struct osdev_device *osdev_obj = NULL;
struct osdev_device *osdev_parent = NULL;
if (osdev == NULL) {
pr_err("Error, null pointer exception.");
return -EINVAL;
}
if (!osdev->obj) {
osdev_tmp = OSAL_osdevAlloc(osdev->name, osdev->id);
osdev->obj = osdev_tmp;
}
else {
osdev_tmp = osdev->obj;
osdev_parent = container_of(osdev_tmp, struct osdev_device, osdev);
}
osdev_obj = container_of(osdev_tmp->obj, struct osdev_device, osdev);
dev = &(osdev_obj->dev);
dev_set_name(dev, "%s.%d", osdev->name, osdev->id);
dev_set_drvdata(dev, osdev_obj);
dev->bus = &osal_bus_type;
dev->devt = MKDEV(0, 0);
dev->parent = osdev_parent ? &osdev_parent->dev : &osal_bus;
ret = device_add(dev);
if (ret) {
pr_err("ErrNo(%d), add device failed.", ret);
put_device(dev);
return ret;
}
return ret;
}
EXPORT_SYMBOL(OSAL_osdevRegister);
void OSAL_osdevUnregister(OSAL_osdev *osdev)
{
struct osdev_device *osdev_obj = NULL;
if (osdev == NULL || osdev->obj == NULL) {
pr_err("Error, null pointer exception.");
return;
}
osdev_obj = container_of(osdev->obj, struct osdev_device, osdev);
device_del(&osdev_obj->dev);
put_device(&osdev_obj->dev);
}
EXPORT_SYMBOL(OSAL_osdevUnregister);
inline void *OSAL_osdevGetDrvdata(const OSAL_osdev *osdev)
{
struct osdev_device *osdev_obj = NULL;
if (osdev == NULL || osdev->obj == NULL) {
pr_err("Error, null pointer exception.");
return ERR_PTR(-EINVAL);
}
osdev_obj = container_of(osdev->obj, struct osdev_device, osdev);
return dev_get_drvdata(&osdev_obj->dev);
}
EXPORT_SYMBOL(OSAL_osdevGetDrvdata);
inline void OSAL_osdevSetDrvdata(OSAL_osdev *osdev, void *data)
{
struct osdev_device *osdev_obj = NULL;
if (osdev == NULL || osdev->obj == NULL) {
pr_err("Error, null pointer exception.");
return;
}
osdev_obj = container_of(osdev->obj, struct osdev_device, osdev);
dev_set_drvdata(&osdev_obj->dev, data);
}
EXPORT_SYMBOL(OSAL_osdevSetDrvdata);
int __init OSAL_osdevInit(void)
{
int ret = 0;
ret = device_register(&osal_bus);
if (ret) {
pr_err("ErrNo(%d), register bus Device[osal] failed.", ret);
put_device(&osal_bus);
goto out;
}
ret = bus_register(&osal_bus_type);
if (ret) {
pr_err("ErrNo(%d), register bus Type[osal] failed.", ret);
goto out_unregister_bus;
}
pr_info("OSAL_osdev initialize completed.");
return ret;
out_unregister_bus:
device_unregister(&osal_bus);
out:
return ret;
}
void __exit OSAL_osdevExit(void)
{
bus_unregister(&osal_bus_type);
device_unregister(&osal_bus);
}

View File

@ -0,0 +1,185 @@
/*******************************************************************************
* HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
* Author :
* Version : V1.0.0 2024.11.15
* Description :
* Note : anonymity@hikvision.com.cn Modified 2024.11.15
******************************************************************************/
#include <stdarg.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/kdev_t.h> // MKDEV
#include "OSAL_osdev.h"
struct device osal_bus = {
.init_name = "osal",
};
struct bus_type osal_bus_type = {
.name = "osal",
};
struct osdev_device { // Object
struct device dev;
char name[];
};
struct osdev_driver {
struct device_driver drv;
};
static void osadev_device_release(struct device *dev)
{
struct osdev_device *osdev_obj = container_of(dev, struct osdev_device, dev);
kfree(osdev_obj);
}
OSAL_osdev *OSAL_osdevAlloc(const char *name, int id)
{
struct device *dev = NULL;
struct osdev *osdev = NULL;
struct osdev_device *osdev_obj = NULL;
osdev_obj = kzalloc(sizeof(struct osdev_device) + strlen(name) + 1, GFP_KERNEL);
if (!osdev_obj) {
pr_err("ErrNo(%ld), alloc memory for OSAL_sysDevice failed.", PTR_ERR(dev));
return ERR_PTR(-ENOMEM);
}
osdev = &(osdev_obj->osdev);
dev = &(osdev_obj->dev);
strcpy(osdev_obj->name, name);
osdev->name = osdev_obj->name;
osdev->id = id;
device_initialize(dev);
dev->release = osadev_device_release;
osdev->obj = osdev;
return (OSAL_osdev *)osdev;
}
EXPORT_SYMBOL(OSAL_osdevAlloc);
int OSAL_osdevRegister(OSAL_osdev *osdev)
{
int ret = 0;
struct device *dev = NULL;
struct osdev *osdev_tmp = NULL;
struct osdev_device *osdev_obj = NULL;
struct osdev_device *osdev_parent = NULL;
if (osdev == NULL) {
pr_err("Error, null pointer exception.");
return -EINVAL;
}
if (!osdev->obj) {
osdev_tmp = OSAL_osdevAlloc(osdev->name, osdev->id);
osdev->obj = osdev_tmp;
}
else {
osdev_tmp = osdev->obj;
osdev_parent = container_of(osdev_tmp, struct osdev_device, osdev);
}
osdev_obj = container_of(osdev_tmp->obj, struct osdev_device, osdev);
dev = &(osdev_obj->dev);
dev_set_name(dev, "%s.%d", osdev->name, osdev->id);
dev_set_drvdata(dev, osdev_obj);
dev->bus = &osal_bus_type;
dev->devt = MKDEV(0, 0);
dev->parent = osdev_parent ? &osdev_parent->dev : &osal_bus;
ret = device_add(dev);
if (ret) {
pr_err("ErrNo(%d), add device failed.", ret);
put_device(dev);
return ret;
}
return ret;
}
EXPORT_SYMBOL(OSAL_osdevRegister);
void OSAL_osdevUnregister(OSAL_osdev *osdev)
{
struct osdev_device *osdev_obj = NULL;
if (osdev == NULL || osdev->obj == NULL) {
pr_err("Error, null pointer exception.");
return;
}
osdev_obj = container_of(osdev->obj, struct osdev_device, osdev);
device_del(&osdev_obj->dev);
put_device(&osdev_obj->dev);
}
EXPORT_SYMBOL(OSAL_osdevUnregister);
inline void *OSAL_osdevGetDrvdata(const OSAL_osdev *osdev)
{
struct osdev_device *osdev_obj = NULL;
if (osdev == NULL || osdev->obj == NULL) {
pr_err("Error, null pointer exception.");
return ERR_PTR(-EINVAL);
}
osdev_obj = container_of(osdev->obj, struct osdev_device, osdev);
return dev_get_drvdata(&osdev_obj->dev);
}
EXPORT_SYMBOL(OSAL_osdevGetDrvdata);
inline void OSAL_osdevSetDrvdata(OSAL_osdev *osdev, void *data)
{
struct osdev_device *osdev_obj = NULL;
if (osdev == NULL || osdev->obj == NULL) {
pr_err("Error, null pointer exception.");
return;
}
osdev_obj = container_of(osdev->obj, struct osdev_device, osdev);
dev_set_drvdata(&osdev_obj->dev, data);
}
EXPORT_SYMBOL(OSAL_osdevSetDrvdata);
int __init OSAL_osdevInit(void)
{
int ret = 0;
ret = device_register(&osal_bus);
if (ret) {
pr_err("ErrNo(%d), register bus Device[osal] failed.", ret);
put_device(&osal_bus);
goto out;
}
ret = bus_register(&osal_bus_type);
if (ret) {
pr_err("ErrNo(%d), register bus Type[osal] failed.", ret);
goto out_unregister_bus;
}
pr_info("OSAL_osdev initialize completed.");
return ret;
out_unregister_bus:
device_unregister(&osal_bus);
out:
return ret;
}
void __exit OSAL_osdevExit(void)
{
bus_unregister(&osal_bus_type);
device_unregister(&osal_bus);
}

View File

@ -0,0 +1,29 @@
/*******************************************************************************
* HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
* Author :
* Version : V1.0.0 2024.11.15
* Description :
* Note : anonymity@hikvision.com.cn Modified 2024.11.15
******************************************************************************/
#ifndef INCLUDE_WIDGET_OSAL_OSDEV_H_
#define INCLUDE_WIDGET_OSAL_OSDEV_H_
typedef struct osdev {
int id;
const char *name;
void *obj;
} OSAL_osdev;
typedef struct osdrv {
int (*probe)(struct osdev *);
int (*remove)(struct osdev *);
void *obj;
} OSAL_osdrv;
OSAL_osdev *OSAL_osdevAlloc(const char *name, int id);
int OSAL_osdevRegister(OSAL_osdev *osdev);
void OSAL_osdevUnregister(OSAL_osdev *osdev);
void *OSAL_osdevGetDrvdata(const OSAL_osdev *osdev);
void OSAL_osdevSetDrvdata(OSAL_osdev *osdev, void *data);
#endif /* INCLUDE_WIDGET_OSAL_OSDEV_H_ */

View File

@ -0,0 +1,28 @@
/*******************************************************************************
* HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
* Author :
* Version : V1.0.0 2024.11.15
* Description :
* Note : anonymity@hikvision.com.cn Modified 2024.11.15
******************************************************************************/
#ifndef INCLUDE_WIDGET_OSAL_OSDEV_H_
#define INCLUDE_WIDGET_OSAL_OSDEV_H_
typedef struct osdev {
int id;
const char *name;
void *obj;
} OSAL_osdev;
typedef struct osdrv {
int (*probe)(struct osdev *);
int (*remove)(struct osdev *);
void *obj;
} OSAL_osdrv;
int OSAL_osdevRegister(OSAL_osdev *osdev);
void OSAL_osdevUnregister(OSAL_osdev *osdev);
void *OSAL_osdevGetDrvdata(const OSAL_osdev *osdev);
void OSAL_osdevSetDrvdata(OSAL_osdev *osdev, void *data);
#endif /* INCLUDE_WIDGET_OSAL_OSDEV_H_ */

View File

@ -0,0 +1,3 @@
config DRIVER_BUS_PLATFORM_OSDEV
bool "OSAL osdev driver"

View File

@ -0,0 +1,70 @@
#------------------------------------------------------------------------------#
# All Right Reserved.
# Author :
# Version : V1.0.0 202x.01.01
# Description :
# Note : gaoyang3513@163.com Modified 202x.01.01
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#
# Path information
#------------------------------------------------------------------------------#
# Top directories
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
KERNEL_DIR ?= $(realpath $(LOCAL_DIR)/../../../../../linux_5.10/build/kernel_output)
# Subdirectories
# Output directories
OUTPUT_DIR := $(LOCAL_DIR)/output
INSTALL_DIR ?= $(LOCAL_DIR)/__install
#$(info Output directoty : $(OUTPUT_DIR))
#$(info Install directoty: $(INSTALL_DIR))
#------------------------------------------------------------------------------#
# Variables
#------------------------------------------------------------------------------#
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
#------------------------------------------------------------------------------#
# Compile configure
#------------------------------------------------------------------------------#
export ARCH ?= riscv
export CROSS_COMPILE ?= riscv64-unknown-linux-musl-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
#------------------------------------------------------------------------------#
# Targets
#------------------------------------------------------------------------------#
ifneq ($(KERNELRELEASE),)
# called from kernel build system: just declare what our modules are
obj-m += pn5180.o
else
.PHONY: init all clean distclean install menuconfig
all: init
@$(MAKE) modules -C $(KERNEL_DIR) M=$(LOCAL_DIR) -j$(MULTI_CORES)
# @$(MAKE) modules_install -C $(KERNEL_DIR) M=$(LOCAL_DIR) INSTALL_MOD_PATH=$(KERNEL_DIR)/_install_modules INSTALL_MOD_DIR=private
clean:
# File
@for n in *.o *.ko *.mod.c *.mod *.cmd *.symvers *.order; do \
find $(LOCAL_DIR) -type f -name $$n -exec rm {} \;;\
done
# Directory
@if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
@if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
@if [ -d $(LOCAL_DIR)/.tmp_versions ]; then rm -rf $(LOCAL_DIR)/.tmp_versions; fi;
install:
@mkdir -p $(INSTALL_DIR)
@cp -arf $(OUTPUT_DIR)/. $(INSTALL_DIR)
init:
@mkdir -p $(OUTPUT_DIR);
endif # ifeq ($(KERNELRELEASE),)

View File

@ -0,0 +1,70 @@
#------------------------------------------------------------------------------#
# All Right Reserved.
# Author :
# Version : V1.0.0 202x.01.01
# Description :
# Note : gaoyang3513@163.com Modified 202x.01.01
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#
# Path information
#------------------------------------------------------------------------------#
# Top directories
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
KERNEL_DIR ?= $(realpath $(LOCAL_DIR)/../../../../../linux_5.10/build/kernel_output)
# Subdirectories
# Output directories
OUTPUT_DIR := $(LOCAL_DIR)/output
INSTALL_DIR ?= $(LOCAL_DIR)/__install
#$(info Output directoty : $(OUTPUT_DIR))
#$(info Install directoty: $(INSTALL_DIR))
#------------------------------------------------------------------------------#
# Variables
#------------------------------------------------------------------------------#
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
#------------------------------------------------------------------------------#
# Compile configure
#------------------------------------------------------------------------------#
export ARCH ?= riscv
export CROSS_COMPILE ?= riscv64-unknown-linux-musl-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
#------------------------------------------------------------------------------#
# Targets
#------------------------------------------------------------------------------#
ifneq ($(KERNELRELEASE),)
# called from kernel build system: just declare what our modules are
obj-m += cmt2301.o
else
.PHONY: init all clean distclean install menuconfig
all: init
@$(MAKE) modules -C $(KERNEL_DIR) M=$(LOCAL_DIR) -j$(MULTI_CORES)
# @$(MAKE) modules_install -C $(KERNEL_DIR) M=$(LOCAL_DIR) INSTALL_MOD_PATH=$(KERNEL_DIR)/_install_modules INSTALL_MOD_DIR=private
clean:
# File
@for n in *.o *.ko *.mod.c *.mod *.cmd *.symvers *.order; do \
find $(LOCAL_DIR) -type f -name $$n -exec rm {} \;;\
done
# Directory
@if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
@if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
@if [ -d $(LOCAL_DIR)/.tmp_versions ]; then rm -rf $(LOCAL_DIR)/.tmp_versions; fi;
install:
@mkdir -p $(INSTALL_DIR)
@cp -arf $(OUTPUT_DIR)/. $(INSTALL_DIR)
init:
@mkdir -p $(OUTPUT_DIR);
endif # ifeq ($(KERNELRELEASE),)

View File

@ -0,0 +1,75 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#define IS_USE_STATIC_PLATFORM_DATA 0
struct CHIP {
struct spi_device *spi;
};
#if IS_USE_STATIC_PLATFORM_DATA
struct CHIP_platform_data {
int spi_ch;
};
#endif // IS_USE_STATIC_PLATFORM_DATA
static int CHIP_probe(struct spi_device *spi)
{
struct CHIP *chip;
#if IS_USE_STATIC_PLATFORM_DATA
struct CHIP_platform_data *pdata;
/* assuming the driver requires board-specific data: */
pdata = (struct CHIP_platform_data *)&spi->dev.platform_data;
if (!pdata)
return -ENODEV;
#endif // IS_USE_STATIC_PLATFORM_DATA
/* get memory for driver's per-chip state */
chip = kzalloc(sizeof *chip, GFP_KERNEL);
if (!chip)
return -ENOMEM;
spi_set_drvdata(spi, chip);
return 0;
}
int CHIP_remove(struct spi_device *spi)
{
struct CHIP *chip = NULL;
chip = (struct CHIP *)spi_get_drvdata(spi);
kfree(chip);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id CHIP_of_match[] = {
{ .compatible = "nxp,pn5180", },
{ }
};
MODULE_DEVICE_TABLE(of, CHIP_of_match); // Used by file2alias, which indicated what devices are support with this drive.
#endif // CONFIG_OF
static struct spi_driver CHIP_driver = {
.driver = {
.name = "CHIP",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = CHIP_of_match,
#endif // CONFIG_OF
},
.probe = CHIP_probe,
.remove = CHIP_remove,
};
module_spi_driver(CHIP_driver);
MODULE_AUTHOR("Gao yang <gaoyang3513@163.com>");
MODULE_DESCRIPTION("NXP PN5180 NFC driver");
MODULE_LICENSE("GPL");

76
03-Bus/03-SPI/Makefile Normal file
View File

@ -0,0 +1,76 @@
#------------------------------------------------------------------------------#
# All Right Reserved.
# Author :
# Version : V1.0.0 202x.01.01
# Description :
# Note : gaoyang3513@163.com Modified 202x.01.01
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#
# Path information
#------------------------------------------------------------------------------#
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
# Subdirectory
PN5180_DIR := $(LOCAL_DIR)/01-NFC_PN5180
CMT2301_DIR := $(LOCAL_DIR)/02-Sub1G_CMT2301
OUTPUT_DIR := $(LOCAL_DIR)/output
INSTALL_DIR ?= $(LOCAL_DIR)/__install
#$(info Output directoty : $(OUTPUT_DIR))
#$(info Install directoty: $(INSTALL_DIR))
#------------------------------------------------------------------------------#
# Variables
#------------------------------------------------------------------------------#
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
SUB_DIRS := $(CMT2301_DIR) $(PN5180_DIR)
#------------------------------------------------------------------------------#
# Compile configure
#------------------------------------------------------------------------------#
ARCH ?= riscv
CROSS_COMPILE ?= riscv64-unknown-linux-musl-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
export ARCH CROSS_COMPILE
#------------------------------------------------------------------------------#
# Targets
#------------------------------------------------------------------------------#
ifneq ($(KERNELRELEASE),)
# called from kernel build system: just declare what our modules are
obj-y += $(SUB_DIRS)
#INC_DIRS := $(INCLUDE_DIR)/generated
#subdir-ccflags-y += $(addprefix -I, $(INC_DIRS))
else # !KERNELRELEASE
.PHONY: init all clean distclean install menuconfig
all: init
@for sub in $(SUB_DIRS); do \
$(MAKE) -C $$sub; \
$(MAKE) install INSTALL_DIR=$(OUTPUT_DIR) -C $$sub || exit "$$?"; \
done;
clean:
@for sub in $(SUB_DIRS); do \
$(MAKE) clean -C $$sub || exit "$$?"; \
done;
# Directory
@if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
@if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
install:
@mkdir -p $(INSTALL_DIR)
@cp -arf $(OUTPUT_DIR)/. $(INSTALL_DIR)
init:
@mkdir -p $(OUTPUT_DIR);
endif # !KERNELRELEASE

13
03-Bus/Kconfig Normal file
View File

@ -0,0 +1,13 @@
config DRIVER_BUS_PLATFORM
bool "Platform device driver"
if DRIVER_BUS_PLATFORM
source "03-Bus/01-Platform/Kconfig"
endif # DRIVER_BUS_PLATFORM
config DRIVER_BUS_I2C
bool "I2C device driver"
config DRIVER_BUS_SPI
bool "SPI device driver"

View File

@ -0,0 +1,87 @@
#*******************************************************************************
# HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
# Author :
# Version : V1.0.0 2020.10.21
# Description :
# Note : yegaoyang@hikvision.com.cn Modified 2020.10.21
#*******************************************************************************
#*******************************************************************************
# Path information
#*******************************************************************************
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
KERNEL_DIR ?= /home/gaoyang3513/Source/06-SG20x/02-Projects/SDK_SG200x_V2/linux_5.10/build/sg2000_milkv_duos_glibc_arm64_sd
#KERNEL_DIR ?= $(HOME)/Source/06-SG20x/02-Projects/SDK_SG200x_V2/linux_5.10/build/sg2000_milkv_duos_glibc_arm64_sd/
# ParDirectory
LIBS_DIR :=
INCLUDE_DIR :=
# Subdirectory
# Output
OUTPUT_DIR := $(LOCAL_DIR)/output
INSTALL_DIR ?= $(LOCAL_DIR)/__install
#*******************************************************************************
# Variables
#*******************************************************************************
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
MOD_NAME := test_panic
#*******************************************************************************
# Compile configure
#*******************************************************************************
ARCH ?= arm64
CROSS_COMPILE ?= ${HOME}/Source/06-SG20x/02-Projects/SDK_SG200x_V2/host-tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
OBJDUMP := $(CROSS_COMPILE)objdump
export ARCH CROSS_COMPILE
#*******************************************************************************
# Targets
#*******************************************************************************
.PHONY: all install clean
ifeq ($(KERNELRELEASE),)
all: init
@$(MAKE) modules -C $(KERNEL_DIR) M=$(LOCAL_DIR) -j$(MULTI_CORES)
# @$(MAKE) modules_install -C $(KERNEL_DIR) M=$(LOCAL_DIR) INSTALL_MOD_PATH=$(KERNEL_DIR)/_install_modules INSTALL_MOD_DIR=private
@$(OBJDUMP) -hdS test_ps.o > test_ps.dmp
clean:
# File
@for n in *.o *.ko *.mod.c *.mod *.cmd *.symvers *.order; do \
find $(LOCAL_DIR) -type f -name $$n -exec rm {} \;;\
done
# Directory
@if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
@if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
@if [ -d $(LOCAL_DIR)/.tmp_versions ]; then rm -rf $(LOCAL_DIR)/.tmp_versions; fi;
install:
@mkdir -p $(INSTALL_DIR)/lib/modules/private
@install -m 644 -D $(MOD_NAME).ko $(INSTALL_DIR)/lib/modules/private;
init:
@mkdir -p $(OUTPUT_DIR)
else
obj-m := $(MOD_NAME).o
$(MOD_NAME)-objs := test_ps.o
INC_DIRS :=
ccflags-y +=
EXTRA_CFLAGS += -Wno-error=date-time # Fix compile error on gcc 4.9 and later
EXTRA_CFLAGS += -Wno-date-time -g
endif # ifeq ($(KERNELRELEASE),)

167
04-Debug/01-Panic/test_ps.c Normal file
View File

@ -0,0 +1,167 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/rcupdate.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
static unsigned int test_type;
module_param(test_type, uint, 0400);
MODULE_PARM_DESC(test_type, "set to 1 to try to OOM (default 0)");
static int trigger_oops(void)
{
int *ptr = (int *)0; // 强制类型转换0地址为指针并尝试读取
printk(KERN_ALERT "Dereferenced NULL pointer value: %d\n", *ptr);
return 0;
}
static int trigger_oob(void) {
char *buffer;
int *out_of_bounds;
printk(KERN_INFO "Out-of-bounds memory access test module loaded\n");
// Allocate a small buffer
// buffer = kmalloc(256, GFP_KERNEL);
buffer = vmalloc(PAGE_SIZE * 2);
if (!buffer) {
printk(KERN_ERR "Failed to allocate memory\n");
return -ENOMEM;
}
// Attempt to access memory out of bounds
out_of_bounds = (int *)(buffer + PAGE_SIZE * 3); // Move pointer to the end of the buffer
*out_of_bounds = 0; // This should cause an out-of-bounds write
printk(KERN_INFO "Out-of-bounds Ofst[%lu] memory access performed\n", 256 + PAGE_SIZE);
kfree(buffer);
return 0;
}
static int trigger_oom(void)
{
void *memory = NULL;
size_t memory_size = 0;
printk(KERN_INFO "oom_trigger: Initializing the oom_trigger LKM\n");
memory_size = 100*1024*1024;
while (1) { // 尝试分配大块内存
memory = vmalloc(memory_size);
if (!memory) {
printk(KERN_ALERT "oom_trigger: Memory allocation failed\n");
break;
}
// 仅为防止编译器优化,实际不访问分配的内存
memset(memory, 0, memory_size);
}
return 0;
}
static int test_data = 0;
static struct rcu_head test_rcu_head;
static void bad_rcu_callback(struct rcu_head *head)
{
// 违规操作在RCU回调函数中睡眠这可能导致RCU grace period过长
msleep(1000);
// 违规操作修改被RCU保护的数据结构
test_data++; // 不应在RCU回调中修改全局变量
pr_info("Bad RCU callback executed\n");
}
static void trigger_rcu(void)
{
pr_info("RCU error module loaded\n");
call_rcu(&test_rcu_head, bad_rcu_callback);
}
static int is_ready_thread1, is_ready_thread2;
static struct task_struct *thread1;
static struct task_struct *thread2;
static DEFINE_MUTEX(mutex_a);
static DEFINE_MUTEX(mutex_b);
static int thread_func(void *data)
{
char *name = (char *) data;
if (!strcmp(name, "Thread1")) {
printk(KERN_INFO "%s: Acquiring mutex A...\n", name);
mutex_lock(&mutex_a);
is_ready_thread1 = 1;
while (!is_ready_thread2);
printk(KERN_INFO "%s: Got mutex A. Now trying to acquire mutex B...\n", name);
mutex_lock(&mutex_b); // This will block, causing deadlock
printk(KERN_INFO "%s: Got mutex B.\n", name);
} else {
printk(KERN_INFO "%s: Acquiring mutex B...\n", name);
mutex_lock(&mutex_b);
is_ready_thread2 = 1;
while (!is_ready_thread1);
printk(KERN_INFO "%s: Got mutex B. Now trying to acquire mutex A...\n", name);
mutex_lock(&mutex_a); // This will block, causing deadlock
printk(KERN_INFO "%s: Got mutex A.\n", name);
}
return 0;
}
static int trigger_deadlock(void)
{
thread1 = kthread_run(thread_func, (void *) "Thread1", "thread1");
if (IS_ERR(thread1)) {
printk(KERN_ERR "Failed to create thread1\n");
return PTR_ERR(thread1);
}
thread2 = kthread_run(thread_func, (void *) "Thread2", "thread2");
if (IS_ERR(thread2)) {
printk(KERN_ERR "Failed to create thread2\n");
kthread_stop(thread1);
return PTR_ERR(thread2);
}
return 0;
}
static int trigger_init(void) {
if (test_type == 0)
trigger_oops();
else if (test_type == 1)
trigger_oom();
else if (test_type == 2)
trigger_rcu();
else if (test_type == 3)
trigger_deadlock();
else if (test_type == 4)
trigger_oob();
return 0; // 加载模块不应该有返回值但这里返回0避免编译警告。
}
static void __exit trigger_exit(void) {
if (test_type == 3) {
kthread_stop(thread1);
kthread_stop(thread2);
printk(KERN_INFO "Deadlock trigger exit.\n");
}
}
module_init(trigger_init);
module_exit(trigger_exit);
MODULE_LICENSE("GPL");

View File

@ -1,33 +1,41 @@
#*******************************************************************************
# HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
# Author :
# Version : V1.0.0 202x.01.01
# Version : V1.0.0 2020.10.21
# Description :
# Note : gaoyang3513@163.com Modified 2020.10.21
# Note : yegaoyang@hikvision.com.cn Modified 2020.10.21
#*******************************************************************************
#*******************************************************************************
# Path information
#*******************************************************************************
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
KERNEL_DIR ?= $(realpath $(LOCAL_DIR)/../../../../linux_5.10)
KERNEL_DIR ?= /home/gaoyang3513/Source/06-SG20x/02-Projects/SDK_SG200x_V2/linux_5.10/build/sg2000_milkv_duos_glibc_arm64_sd
#KERNEL_DIR ?= $(HOME)/Source/06-SG20x/02-Projects/SDK_SG200x_V2/linux_5.10/build/sg2000_milkv_duos_glibc_arm64_sd/
# ParDirectory
LIBS_DIR :=
INCLUDE_DIR :=
# Subdirectory
SUB_DIRS := $(LOCAL_DIR)/01-Panic
# Output
OUTPUT_DIR := $(LOCAL_DIR)/output
INSTALL_DIR ?= $(LOCAL_DIR)/__install
#$(info Output directoty : $(OUTPUT_DIR))
#$(info Install directoty: $(INSTALL_DIR))
#*******************************************************************************
# Variables
#*******************************************************************************
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
MOD_NAME := test_panic
#*******************************************************************************
# Compile configure
#*******************************************************************************
ARCH ?= riscv
CROSS_COMPILE ?= riscv64-unknown-linux-musl-
ARCH ?= arm64
CROSS_COMPILE ?= ${HOME}/Source/06-SG20x/02-Projects/SDK_SG200x_V2/host-tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
@ -35,25 +43,26 @@ AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
export ARCH CROSS_COMPILE
#*******************************************************************************
# Targets
#*******************************************************************************
.PHONY: init all clean distclean install menuconfig
.PHONY: init all clean install menuconfig
ifeq ($(KERNELRELEASE),)
all: init
@$(MAKE) modules -C $(KERNEL_DIR) M=$(LOCAL_DIR) -j$(MULTI_CORES)
@$(MAKE) modules_install -C $(KERNEL_DIR) M=$(LOCAL_DIR) INSTALL_MOD_PATH=$(KERNEL_DIR)/_install_modules INSTALL_MOD_DIR=private
@for sub in $(SUB_DIRS); do \
$(MAKE) -C $$sub || exit "$$?"; \
$(MAKE) install INSTALL_DIR=$(OUTPUT_DIR) -C $$sub || exit "$$?"; \
done;
clean:
@for sub in $(SUB_DIRS); do \
$(MAKE) clean -C $$sub || exit "$$?"; \
done;
# Directory
@if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
@if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
@if [ -d $(LOCAL_DIR)/.tmp_versions ]; then rm -rf $(LOCAL_DIR)/.tmp_versions; fi;
# File
@for f in {Module.symvers,modules.order}; do \
if [ -e $$f ]; then rm -rf $$f; fi; \
done
install:
@mkdir -p $(INSTALL_DIR)
@ -61,9 +70,12 @@ install:
init:
@mkdir -p $(OUTPUT_DIR);
else
# called from kernel build system: just declare what our modules are
obj-m += pn5180.o
obj-y += $(SUB_DIRS)
INC_DIRS :=
subdir-ccflags-y += $(addprefix -I, $(INC_DIRS))
endif # ifeq ($(KERNELRELEASE),)

114
Kconfig Normal file
View File

@ -0,0 +1,114 @@
mainmenu "Example Kconfig configuration"
menu "Modules with the type of bus support"
config MODULE_BUS
bool "Bus device driver"
default n
if MODULE_BUS
source "03-Bus/Kconfig"
endif # Module_BUS
endmenu
#config MODULES
# bool "Enable loadable module support"
# option modules
# default n
menu "Bool and tristate symbols"
config BOOL
bool "Bool symbol"
default y
config BOOL_DEP
bool "Dependent bool symbol"
depends on BOOL
# Mix it up a bit with an 'if' instead of a 'depends on'
if BOOL
config TRI_DEP
tristate "Dependent tristate symbol"
select SELECTED_BY_TRI_DEP
imply IMPLIED_BY_TRI_DEP
endif
config TWO_MENU_NODES
bool "First prompt"
depends on BOOL
config TRI
tristate "Tristate symbol"
config TWO_MENU_NODES
bool "Second prompt"
comment "These are selected by TRI_DEP"
config SELECTED_BY_TRI_DEP
tristate "Tristate selected by TRI_DEP"
config IMPLIED_BY_TRI_DEP
tristate "Tristate implied by TRI_DEP"
endmenu
menu "String, int, and hex symbols"
config STRING
string "String symbol"
default "foo"
config INT
int "Int symbol"
default 747
config HEX
hex "Hex symbol"
default 0xABC
endmenu
menu "Various choices"
choice BOOL_CHOICE
bool "Bool choice"
config BOOL_CHOICE_SYM_1
bool "Bool choice sym 1"
config BOOL_CHOICE_SYM_2
bool "Bool choice sym 2"
endchoice
choice TRI_CHOICE
tristate "Tristate choice"
config TRI_CHOICE_SYM_1
tristate "Tristate choice sym 1"
config TRI_CHOICE_SYM_2
tristate "Tristate choice sym 2"
endchoice
choice OPT_BOOL_CHOICE
bool "Optional bool choice"
optional
config OPT_BOOL_CHOICE_SYM_1
bool "Optional bool choice sym 1"
config OPT_BOOL_CHOICE_SYM_2
bool "Optional bool choice sym 2"
endchoice
endmenu

134
Makefile
View File

@ -1,75 +1,135 @@
#*******************************************************************************
# HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
# ---------------------------------------------------------------------------- #
# All Right Reserved.
# Author :
# Version : V1.0.0 202x.01.01
# Description :
# Note : gaoyang@.com.cn Modified 2020.10.21
#*******************************************************************************
# Note : gaoyang3513@163.com.cn Modified 202x.01.01
# ---------------------------------------------------------------------------- #
# That's our default target when none is given on the command line
PHONY := all
all:
#*******************************************************************************
# ---------------------------------------------------------------------------- #
# Path information
#*******************************************************************************
# ---------------------------------------------------------------------------- #
LOCAL_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
KERNEL_DIR ?= $(realpath $(LOCAL_DIR)/../../../linux_5.10)
# SDK directories
SDK_TOP ?= $(HOME)/Source/15-SG200x/01-MilkDuo/02-Project/SDK_SG200x_V2.0.0
KERNEL_DIR ?= $(SDK_TOP)/linux_5.10/build/sg2000_milkv_duos_glibc_arm64_sd
TOOLCHAIN_DIR ?= $(SDK_TOP)/host-tools/gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin
# Subdirectory
OUTPUT_DIR := $(LOCAL_DIR)/output
INSTALL_DIR ?= $(LOCAL_DIR)/__install
#$(info Output directoty : $(OUTPUT_DIR))
#$(info Install directoty: $(INSTALL_DIR))
#*******************************************************************************
export KERNEL_DIR
# ---------------------------------------------------------------------------- #
# Functions
# ---------------------------------------------------------------------------- #
define filechk_version.h
echo \#define LINUX_VERSION_CODE $(shell \
expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))'
endef
# ---------------------------------------------------------------------------- #
# Variables
#*******************************************************************************
# ---------------------------------------------------------------------------- #
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 0
EXTRAVERSION =
NAME = Kleptomaniac Octopus
version_h := include/generated/version.h
MAKEFLAGS += --no-print-directory
MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
SUB_DIRS := spi/
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
#*******************************************************************************
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet = quiet_
Q = @
endif
export Q quiet
# ---------------------------------------------------------------------------- #
# Compile configure
#*******************************************************************************
ARCH ?= riscv
CROSS_COMPILE ?= riscv64-unknown-linux-musl-
# ---------------------------------------------------------------------------- #
#CROSS_COMPILE ?= riscv64-unknown-linux-musl-
ARCH ?= arm64
CROSS_COMPILE ?= aarch64-linux-gnu-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
export ARCH CROSS_COMPILE
#*******************************************************************************
# Targets
#*******************************************************************************
.PHONY: init all clean distclean install menuconfig
PATH := $(TOOLCHAIN_DIR):$(PATH)
export ARCH CROSS_COMPILE PATH
# ---------------------------------------------------------------------------- #
# Objects
# ---------------------------------------------------------------------------- #
SUB_DIRS := 03-Bus/01-Platform/01-osdev
#$(warning "SUB_DIRS: $(SUB_DIRS)")
# ---------------------------------------------------------------------------- #
# Targets
# ---------------------------------------------------------------------------- #
.PHONY += init all clean distclean install menuconfig oldconfig $(version_h)
include scripts/Kbuild.include
ifeq ($(KERNELRELEASE),)
all: init
@for sub in $(SUB_DIRS); do \
$(Q)for sub in $(SUB_DIRS); do \
$(MAKE) -C $$sub; \
$(MAKE) install INSTALL_DIR=$(OUTPUT_DIR) -C $$sub || exit "$$?"; \
done;
clean:
@for sub in $(SUB_DIRS); do \
$(Q)for sub in $(SUB_DIRS); do \
$(MAKE) clean -C $$sub || exit "$$?"; \
done;
# Directory
@if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
@if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
$(Q)if [ -d $(LOCAL_DIR)/include/config ]; then rm -rf $(LOCAL_DIR)/include/config; fi;
$(Q)if [ -d $(LOCAL_DIR)/include/generated ]; then rm -rf $(LOCAL_DIR)/include/generated; fi;
$(Q)if [ -d $(LOCAL_DIR)/output ]; then rm -rf $(LOCAL_DIR)/output; fi;
$(Q)if [ -d $(LOCAL_DIR)/__install ]; then rm -rf $(LOCAL_DIR)/__install; fi;
install:
@mkdir -p $(INSTALL_DIR)
@cp -arf $(OUTPUT_DIR)/. $(INSTALL_DIR)
$(Q)mkdir -p $(INSTALL_DIR)
$(Q)cp -arf $(OUTPUT_DIR)/. $(INSTALL_DIR)
init:
@mkdir -p $(OUTPUT_DIR);
init: $(version_h)
$(Q)mkdir -p $(OUTPUT_DIR);
$(Q)mkdir -p include/config include/generated
$(Q)$(LOCAL_DIR)/scripts/kconfig/Kconfiglib/genconfig.py --sync-dep include/config --header-path include/generated/autoconf.h
else
# called from kernel build system: just declare what our modules are
obj-y += $(SUB_DIRS)
oldconfig:
$(Q)$(LOCAL_DIR)/scripts/kconfig/Kconfiglib/oldconfig.py
#INC_DIRS := $(INCLUDE_DIR)/generated
#subdir-ccflags-y += $(addprefix -I, $(INC_DIRS))
%_defconfig:
$(Q)$(LOCAL_DIR)/scripts/kconfig/Kconfiglib/defconfig.py --kconfig Kconfig configs/$@
endif # ifeq ($(KERNELRELEASE),)
menuconfig:
$(Q)mkdir -p include/config include/generated
$(Q)$(LOCAL_DIR)/scripts/kconfig/Kconfiglib/menuconfig.py Kconfig
savedefconfig:
$(Q)$(LOCAL_DIR)/scripts/kconfig/Kconfiglib/savedefconfig.py --kconfig Kconfig --out defconfig
$(version_h):
$(Q)$(call filechk,version.h)

9
config.h Normal file
View File

@ -0,0 +1,9 @@
#define CONFIG_MODULE_BUS 1
#define CONFIG_DRIVER_BUS_PLATFORM 1
#define CONFIG_DRIVER_BUS_PLATFORM_OSDEV 1
#define CONFIG_BOOL 1
#define CONFIG_STRING "foo"
#define CONFIG_INT 747
#define CONFIG_HEX 0xABC
#define CONFIG_BOOL_CHOICE_SYM_1 1
#define CONFIG_TRI_CHOICE_SYM_1 1

3
configs/foo_defconfig Normal file
View File

@ -0,0 +1,3 @@
# CONFIG_MODULES is not set
# CONFIG_BOOL is not set
CONFIG_TRI_CHOICE_SYM_1=y

323
scripts/Kbuild.include Normal file
View File

@ -0,0 +1,323 @@
# SPDX-License-Identifier: GPL-2.0
####
# kbuild: Generic definitions
# Convenient variables
comma := ,
quote := "
squote := '
empty :=
space := $(empty) $(empty)
space_escape := _-_SPACE_-_
pound := \#
###
# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
dot-target = $(dir $@).$(notdir $@)
###
# The temporary file to save gcc -MMD generated dependencies must not
# contain a comma
depfile = $(subst $(comma),_,$(dot-target).d)
###
# filename of target with directory and extension stripped
basetarget = $(basename $(notdir $@))
###
# real prerequisites without phony targets
real-prereqs = $(filter-out $(PHONY), $^)
###
# Escape single quote for use in echo statements
escsq = $(subst $(squote),'\$(squote)',$1)
###
# Quote a string to pass it to C files. foo => '"foo"'
stringify = $(squote)$(quote)$1$(quote)$(squote)
###
# Easy method for doing a status message
kecho := :
quiet_kecho := echo
silent_kecho := :
kecho := $($(quiet)kecho)
###
# filechk is used to check if the content of a generated file is updated.
# Sample usage:
#
# filechk_sample = echo $(KERNELRELEASE)
# version.h: FORCE
# $(call filechk,sample)
#
# The rule defined shall write to stdout the content of the new file.
# The existing file will be compared with the new one.
# - If no file exist it is created
# - If the content differ the new file is used
# - If they are equal no change, and no timestamp update
define filechk
$(Q)set -e; \
mkdir -p $(dir $@); \
trap "rm -f $(dot-target).tmp" EXIT; \
{ $(filechk_$(1)); } > $(dot-target).tmp; \
if [ ! -r $@ ] || ! cmp -s $@ $(dot-target).tmp; then \
$(kecho) ' UPD $@'; \
mv -f $(dot-target).tmp $@; \
fi
endef
######
# gcc support functions
# See documentation in Documentation/kbuild/makefiles.rst
# cc-cross-prefix
# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-)
# Return first <prefix> where a <prefix>gcc is found in PATH.
# If no gcc found in PATH with listed prefixes return nothing
#
# Note: '2>/dev/null' is here to force Make to invoke a shell. Otherwise, it
# would try to directly execute the shell builtin 'command'. This workaround
# should be kept for a long time since this issue was fixed only after the
# GNU Make 4.2.1 release.
cc-cross-prefix = $(firstword $(foreach c, $(1), \
$(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c))))
# output directory for tests below
TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$
# try-run
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
# Exit code chooses option. "$$TMP" serves as a temporary file and is
# automatically cleaned up.
try-run = $(shell set -e; \
TMP=$(TMPOUT)/tmp; \
TMPO=$(TMPOUT)/tmp.o; \
mkdir -p $(TMPOUT); \
trap "rm -rf $(TMPOUT)" EXIT; \
if ($(1)) >/dev/null 2>&1; \
then echo "$(2)"; \
else echo "$(3)"; \
fi)
# as-option
# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
as-option = $(call try-run,\
$(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2))
# as-instr
# Usage: cflags-y += $(call as-instr,instr,option1,option2)
as-instr = $(call try-run,\
printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
# __cc-option
# Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
__cc-option = $(call try-run,\
$(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4))
# cc-option
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
cc-option = $(call __cc-option, $(CC),\
$(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS),$(1),$(2))
# cc-option-yn
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
cc-option-yn = $(call try-run,\
$(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
# cc-disable-warning
# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
cc-disable-warning = $(call try-run,\
$(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
# cc-ifversion
# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
cc-ifversion = $(shell [ $(CONFIG_GCC_VERSION)0 $(1) $(2)000 ] && echo $(3) || echo $(4))
# ld-option
# Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y)
ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3))
# ld-version
# Note this is mainly for HJ Lu's 3 number binutil versions
ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh)
# ld-ifversion
# Usage: $(call ld-ifversion, -ge, 22252, y)
ld-ifversion = $(shell [ $(ld-version) $(1) $(2) ] && echo $(3) || echo $(4))
######
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj=
# Usage:
# $(Q)$(MAKE) $(dtbinst)=dir
dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=
# Usage:
# $(Q)$(MAKE) $(clean)=dir
clean := -f $(srctree)/scripts/Makefile.clean obj
# echo command.
# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
# printing commands
cmd = @set -e; $(echo-cmd) $(cmd_$(1))
###
# if_changed - execute command if any prerequisite is newer than
# target, or command line has changed
# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
# including used config symbols
# if_changed_rule - as if_changed but execute rule instead
# See Documentation/kbuild/makefiles.rst for more info
ifneq ($(KBUILD_NOCMDDEP),1)
# Check if both commands are the same including their order. Result is empty
# string if equal. User may override this check using make KBUILD_NOCMDDEP=1
cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
$(subst $(space),$(space_escape),$(strip $(cmd_$1))))
else
cmd-check = $(if $(strip $(cmd_$@)),,1)
endif
# Replace >$< with >$$< to preserve $ when reloading the .cmd file
# (needed for make)
# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file
# (needed for make)
# Replace >'< with >'\''< to be able to enclose the whole string in '...'
# (needed for the shell)
make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
# Find any prerequisites that are newer than target or that do not exist.
# (This is not true for now; $? should contain any non-existent prerequisites,
# but it does not work as expected when .SECONDARY is present. This seems a bug
# of GNU Make.)
# PHONY targets skipped in both cases.
newer-prereqs = $(filter-out $(PHONY),$?)
# Execute command if command has changed or prerequisite(s) are updated.
if_changed = $(if $(newer-prereqs)$(cmd-check), \
$(cmd); \
printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
# Execute the command and also postprocess generated .d dependencies file.
if_changed_dep = $(if $(newer-prereqs)$(cmd-check),$(cmd_and_fixdep),@:)
cmd_and_fixdep = \
$(cmd); \
scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\
rm -f $(depfile)
# Usage: $(call if_changed_rule,foo)
# Will check if $(cmd_foo) or any of the prerequisites changed,
# and if so will execute $(rule_foo).
if_changed_rule = $(if $(newer-prereqs)$(cmd-check),$(rule_$(1)),@:)
###
# why - tell why a target got built
# enabled by make V=2
# Output (listed in the order they are checked):
# (1) - due to target is PHONY
# (2) - due to target missing
# (3) - due to: file1.h file2.h
# (4) - due to command line change
# (5) - due to missing .cmd file
# (6) - due to target not in $(targets)
# (1) PHONY targets are always build
# (2) No target, so we better build it
# (3) Prerequisite is newer than target
# (4) The command line stored in the file named dir/.target.cmd
# differed from actual command line. This happens when compiler
# options changes
# (5) No dir/.target.cmd file (used to store command line)
# (6) No dir/.target.cmd file and target not listed in $(targets)
# This is a good hint that there is a bug in the kbuild file
ifeq ($(KBUILD_VERBOSE),2)
why = \
$(if $(filter $@, $(PHONY)),- due to target is PHONY, \
$(if $(wildcard $@), \
$(if $(newer-prereqs),- due to: $(newer-prereqs), \
$(if $(cmd-check), \
$(if $(cmd_$@),- due to command line change, \
$(if $(filter $@, $(targets)), \
- due to missing .cmd file, \
- due to $(notdir $@) not in $$(targets) \
) \
) \
) \
), \
- due to target missing \
) \
)
echo-why = $(call escsq, $(strip $(why)))
endif
###############################################################################
#
# When a Kconfig string contains a filename, it is suitable for
# passing to shell commands. It is surrounded by double-quotes, and
# any double-quotes or backslashes within it are escaped by
# backslashes.
#
# This is no use for dependencies or $(wildcard). We need to strip the
# surrounding quotes and the escaping from quotes and backslashes, and
# we *do* need to escape any spaces in the string. So, for example:
#
# Usage: $(eval $(call config_filename,FOO))
#
# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option,
# transformed as described above to be suitable for use within the
# makefile.
#
# Also, if the filename is a relative filename and exists in the source
# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to
# be prefixed to *both* command invocation and dependencies.
#
# Note: We also print the filenames in the quiet_cmd_foo text, and
# perhaps ought to have a version specially escaped for that purpose.
# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good
# enough. It'll strip the quotes in the common case where there's no
# space and it's a simple filename, and it'll retain the quotes when
# there's a space. There are some esoteric cases in which it'll print
# the wrong thing, but we don't really care. The actual dependencies
# and commands *do* get it right, with various combinations of single
# and double quotes, backslashes and spaces in the filenames.
#
###############################################################################
#
define config_filename
ifneq ($$(CONFIG_$(1)),"")
$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1)))))))
ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME)))
else
ifeq ($$(wildcard $$($(1)_FILENAME)),)
ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),)
$(1)_SRCPREFIX := $(srctree)/
endif
endif
endif
endif
endef
#
###############################################################################
# delete partially updated (i.e. corrupted) files on error
.DELETE_ON_ERROR:
# do not delete intermediate files automatically
.SECONDARY:

526
scripts/Makefile.build Normal file
View File

@ -0,0 +1,526 @@
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
# Building
# ==========================================================================
src := $(obj)
PHONY := __build
__build:
# Init all relevant variables used in kbuild files so
# 1) they have correct type
# 2) they do not inherit any value from the environment
obj-y :=
obj-m :=
lib-y :=
lib-m :=
always :=
always-y :=
always-m :=
targets :=
subdir-y :=
subdir-m :=
EXTRA_AFLAGS :=
EXTRA_CFLAGS :=
EXTRA_CPPFLAGS :=
EXTRA_LDFLAGS :=
asflags-y :=
ccflags-y :=
cppflags-y :=
ldflags-y :=
subdir-asflags-y :=
subdir-ccflags-y :=
# Read auto.conf if it exists, otherwise ignore
-include include/config/auto.conf
include scripts/Kbuild.include
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
include scripts/Makefile.lib
# Do not include hostprogs rules unless needed.
# $(sort ...) is used here to remove duplicated words and excessive spaces.
hostprogs := $(sort $(hostprogs))
ifneq ($(hostprogs),)
include scripts/Makefile.host
endif
# Do not include userprogs rules unless needed.
# $(sort ...) is used here to remove duplicated words and excessive spaces.
userprogs := $(sort $(userprogs))
ifneq ($(userprogs),)
include scripts/Makefile.userprogs
endif
ifndef obj
$(warning kbuild: Makefile.build is included improperly)
endif
ifeq ($(need-modorder),)
ifneq ($(obj-m),)
$(warning $(patsubst %.o,'%.ko',$(obj-m)) will not be built even though obj-m is specified.)
$(warning You cannot use subdir-y/m to visit a module Makefile. Use obj-y/m instead.)
endif
endif
# ===========================================================================
# subdir-builtin and subdir-modorder may contain duplications. Use $(sort ...)
subdir-builtin := $(sort $(filter %/built-in.a, $(real-obj-y)))
subdir-modorder := $(sort $(filter %/modules.order, $(obj-m)))
targets-for-builtin := $(extra-y)
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
targets-for-builtin += $(obj)/lib.a
endif
ifdef need-builtin
targets-for-builtin += $(obj)/built-in.a
endif
targets-for-modules := $(patsubst %.o, %.mod, $(filter %.o, $(obj-m)))
ifdef need-modorder
targets-for-modules += $(obj)/modules.order
endif
targets += $(targets-for-builtin) $(targets-for-modules)
# Linus' kernel sanity checking tool
ifeq ($(KBUILD_CHECKSRC),1)
quiet_cmd_checksrc = CHECK $<
cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $<
else ifeq ($(KBUILD_CHECKSRC),2)
quiet_cmd_force_checksrc = CHECK $<
cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $<
endif
ifneq ($(KBUILD_EXTRA_WARN),)
cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $<
endif
# Compile C sources (.c)
# ---------------------------------------------------------------------------
quiet_cmd_cc_s_c = CC $(quiet_modtag) $@
cmd_cc_s_c = $(CC) $(filter-out $(DEBUG_CFLAGS), $(c_flags)) -fverbose-asm -S -o $@ $<
$(obj)/%.s: $(src)/%.c FORCE
$(call if_changed_dep,cc_s_c)
quiet_cmd_cpp_i_c = CPP $(quiet_modtag) $@
cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $<
$(obj)/%.i: $(src)/%.c FORCE
$(call if_changed_dep,cpp_i_c)
# These mirror gensymtypes_S and co below, keep them in synch.
cmd_gensymtypes_c = \
$(CPP) -D__GENKSYMS__ $(c_flags) $< | \
scripts/genksyms/genksyms $(if $(1), -T $(2)) \
$(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
$(if $(KBUILD_PRESERVE),-p) \
-r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
cmd_cc_symtypes_c = \
$(call cmd_gensymtypes_c,true,$@) >/dev/null; \
test -s $@ || rm -f $@
$(obj)/%.symtypes : $(src)/%.c FORCE
$(call cmd,cc_symtypes_c)
# LLVM assembly
# Generate .ll files from .c
quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@
cmd_cc_ll_c = $(CC) $(c_flags) -emit-llvm -S -o $@ $<
$(obj)/%.ll: $(src)/%.c FORCE
$(call if_changed_dep,cc_ll_c)
# C (.c) files
# The C file is compiled and updated dependency information is generated.
# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
ifdef CONFIG_MODVERSIONS
# When module versioning is enabled the following steps are executed:
# o compile a <file>.o from <file>.c
# o if <file>.o doesn't contain a __ksymtab version, i.e. does
# not export symbols, it's done.
# o otherwise, we calculate symbol versions using the good old
# genksyms on the preprocessed source and postprocess them in a way
# that they are usable as a linker script
# o generate .tmp_<file>.o from <file>.o using the linker to
# replace the unresolved symbols __crc_exported_symbol with
# the actual value of the checksum generated by genksyms
# o remove .tmp_<file>.o to <file>.o
cmd_modversions_c = \
if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \
$(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
> $(@D)/.tmp_$(@F:.o=.ver); \
\
$(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \
-T $(@D)/.tmp_$(@F:.o=.ver); \
mv -f $(@D)/.tmp_$(@F) $@; \
rm -f $(@D)/.tmp_$(@F:.o=.ver); \
fi
endif
ifdef CONFIG_FTRACE_MCOUNT_RECORD
ifndef CC_USING_RECORD_MCOUNT
# compiler will not generate __mcount_loc use recordmcount or recordmcount.pl
ifdef BUILD_C_RECORDMCOUNT
ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
RECORDMCOUNT_FLAGS = -w
endif
# Due to recursion, we must skip empty.o.
# The empty.o file is created in the make process in order to determine
# the target endianness and word size. It is made before all other C
# files, including recordmcount.
sub_cmd_record_mcount = \
if [ $(@) != "scripts/mod/empty.o" ]; then \
$(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \
fi;
recordmcount_source := $(srctree)/scripts/recordmcount.c \
$(srctree)/scripts/recordmcount.h
else
sub_cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
"$(if $(CONFIG_64BIT),64,32)" \
"$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)" \
"$(LD) $(KBUILD_LDFLAGS)" "$(NM)" "$(RM)" "$(MV)" \
"$(if $(part-of-module),1,0)" "$(@)";
recordmcount_source := $(srctree)/scripts/recordmcount.pl
endif # BUILD_C_RECORDMCOUNT
cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), \
$(sub_cmd_record_mcount))
endif # CC_USING_RECORD_MCOUNT
endif # CONFIG_FTRACE_MCOUNT_RECORD
ifdef CONFIG_STACK_VALIDATION
ifneq ($(SKIP_STACK_VALIDATION),1)
__objtool_obj := $(objtree)/tools/objtool/objtool
objtool_args = $(if $(CONFIG_UNWINDER_ORC),orc generate,check)
objtool_args += $(if $(part-of-module), --module,)
ifndef CONFIG_FRAME_POINTER
objtool_args += --no-fp
endif
ifdef CONFIG_GCOV_KERNEL
objtool_args += --no-unreachable
endif
ifdef CONFIG_RETPOLINE
objtool_args += --retpoline
endif
ifdef CONFIG_X86_SMAP
objtool_args += --uaccess
endif
# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file
cmd_objtool = $(if $(patsubst y%,, \
$(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \
$(__objtool_obj) $(objtool_args) $@)
objtool_obj = $(if $(patsubst y%,, \
$(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \
$(__objtool_obj))
endif # SKIP_STACK_VALIDATION
endif # CONFIG_STACK_VALIDATION
# Rebuild all objects when objtool changes, or is enabled/disabled.
objtool_dep = $(objtool_obj) \
$(wildcard include/config/orc/unwinder.h \
include/config/stack/validation.h)
ifdef CONFIG_TRIM_UNUSED_KSYMS
cmd_gen_ksymdeps = \
$(CONFIG_SHELL) $(srctree)/scripts/gen_ksymdeps.sh $@ >> $(dot-target).cmd
# List module undefined symbols
undefined_syms = $(NM) $< | $(AWK) '$$1 == "U" { printf("%s%s", x++ ? " " : "", $$2) }';
endif
define rule_cc_o_c
$(call cmd_and_fixdep,cc_o_c)
$(call cmd,gen_ksymdeps)
$(call cmd,checksrc)
$(call cmd,checkdoc)
$(call cmd,objtool)
$(call cmd,modversions_c)
$(call cmd,record_mcount)
endef
define rule_as_o_S
$(call cmd_and_fixdep,as_o_S)
$(call cmd,gen_ksymdeps)
$(call cmd,objtool)
$(call cmd,modversions_S)
endef
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
$(call if_changed_rule,cc_o_c)
$(call cmd,force_checksrc)
cmd_mod = { \
echo $(if $($*-objs)$($*-y)$($*-m), $(addprefix $(obj)/, $($*-objs) $($*-y) $($*-m)), $(@:.mod=.o)); \
$(undefined_syms) echo; \
} > $@
$(obj)/%.mod: $(obj)/%.o FORCE
$(call if_changed,mod)
quiet_cmd_cc_lst_c = MKLST $@
cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
$(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
System.map $(OBJDUMP) > $@
$(obj)/%.lst: $(src)/%.c FORCE
$(call if_changed_dep,cc_lst_c)
# Compile assembler sources (.S)
# ---------------------------------------------------------------------------
# .S file exports must have their C prototypes defined in asm/asm-prototypes.h
# or a file that it includes, in order to get versioned symbols. We build a
# dummy C file that includes asm-prototypes and the EXPORT_SYMBOL lines from
# the .S file (with trailing ';'), and run genksyms on that, to extract vers.
#
# This is convoluted. The .S file must first be preprocessed to run guards and
# expand names, then the resulting exports must be constructed into plain
# EXPORT_SYMBOL(symbol); to build our dummy C file, and that gets preprocessed
# to make the genksyms input.
#
# These mirror gensymtypes_c and co above, keep them in synch.
cmd_gensymtypes_S = \
{ echo "\#include <linux/kernel.h>" ; \
echo "\#include <asm/asm-prototypes.h>" ; \
$(CPP) $(a_flags) $< | \
grep "\<___EXPORT_SYMBOL\>" | \
sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ; } | \
$(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \
scripts/genksyms/genksyms $(if $(1), -T $(2)) \
$(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
$(if $(KBUILD_PRESERVE),-p) \
-r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@
cmd_cc_symtypes_S = \
$(call cmd_gensymtypes_S,true,$@) >/dev/null; \
test -s $@ || rm -f $@
$(obj)/%.symtypes : $(src)/%.S FORCE
$(call cmd,cc_symtypes_S)
quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@
cmd_cpp_s_S = $(CPP) $(a_flags) -o $@ $<
$(obj)/%.s: $(src)/%.S FORCE
$(call if_changed_dep,cpp_s_S)
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
ifdef CONFIG_ASM_MODVERSIONS
# versioning matches the C process described above, with difference that
# we parse asm-prototypes.h C header to get function definitions.
cmd_modversions_S = \
if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \
$(call cmd_gensymtypes_S,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
> $(@D)/.tmp_$(@F:.o=.ver); \
\
$(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \
-T $(@D)/.tmp_$(@F:.o=.ver); \
mv -f $(@D)/.tmp_$(@F) $@; \
rm -f $(@D)/.tmp_$(@F:.o=.ver); \
fi
endif
$(obj)/%.o: $(src)/%.S $(objtool_dep) FORCE
$(call if_changed_rule,as_o_S)
targets += $(filter-out $(subdir-builtin), $(real-obj-y))
targets += $(filter-out $(subdir-modorder), $(real-obj-m))
targets += $(lib-y) $(always-y) $(MAKECMDGOALS)
# Linker scripts preprocessor (.lds.S -> .lds)
# ---------------------------------------------------------------------------
quiet_cmd_cpp_lds_S = LDS $@
cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -U$(ARCH) \
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
$(obj)/%.lds: $(src)/%.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
# ASN.1 grammar
# ---------------------------------------------------------------------------
quiet_cmd_asn1_compiler = ASN.1 $(basename $@).[ch]
cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
$(basename $@).c $(basename $@).h
$(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
$(call cmd,asn1_compiler)
# Build the compiled-in targets
# ---------------------------------------------------------------------------
# To build objects in subdirs, we need to descend into the directories
$(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ;
$(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;
#
# Rule to compile a set of .o files into one .a file (without symbol table)
#
quiet_cmd_ar_builtin = AR $@
cmd_ar_builtin = rm -f $@; $(AR) cDPrST $@ $(real-prereqs)
$(obj)/built-in.a: $(real-obj-y) FORCE
$(call if_changed,ar_builtin)
#
# Rule to create modules.order file
#
# Create commands to either record .ko file or cat modules.order from
# a subdirectory
# Add $(obj-m) as the prerequisite to avoid updating the timestamp of
# modules.order unless contained modules are updated.
cmd_modules_order = { $(foreach m, $(real-prereqs), \
$(if $(filter %/modules.order, $m), cat $m, echo $(patsubst %.o,%.ko,$m));) :; } \
| $(AWK) '!x[$$0]++' - > $@
$(obj)/modules.order: $(obj-m) FORCE
$(call if_changed,modules_order)
#
# Rule to compile a set of .o files into one .a file (with symbol table)
#
$(obj)/lib.a: $(lib-y) FORCE
$(call if_changed,ar)
# NOTE:
# Do not replace $(filter %.o,^) with $(real-prereqs). When a single object
# module is turned into a multi object module, $^ will contain header file
# dependencies recorded in the .*.cmd file.
quiet_cmd_link_multi-m = LD [M] $@
cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^)
$(multi-used-m): FORCE
$(call if_changed,link_multi-m)
$(call multi_depend, $(multi-used-m), .o, -objs -y -m)
targets += $(multi-used-m)
targets := $(filter-out $(PHONY), $(targets))
# Add intermediate targets:
# When building objects with specific suffix patterns, add intermediate
# targets that the final targets are derived from.
intermediate_targets = $(foreach sfx, $(2), \
$(patsubst %$(strip $(1)),%$(sfx), \
$(filter %$(strip $(1)), $(targets))))
# %.asn1.o <- %.asn1.[ch] <- %.asn1
# %.dtb.o <- %.dtb.S <- %.dtb <- %.dts
# %.lex.o <- %.lex.c <- %.l
# %.tab.o <- %.tab.[ch] <- %.y
targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \
$(call intermediate_targets, .dtb.o, .dtb.S .dtb) \
$(call intermediate_targets, .lex.o, .lex.c) \
$(call intermediate_targets, .tab.o, .tab.c .tab.h)
# Build
# ---------------------------------------------------------------------------
ifdef single-build
KBUILD_SINGLE_TARGETS := $(filter $(obj)/%, $(KBUILD_SINGLE_TARGETS))
curdir-single := $(sort $(foreach x, $(KBUILD_SINGLE_TARGETS), \
$(if $(filter $(x) $(basename $(x)).o, $(targets)), $(x))))
# Handle single targets without any rule: show "Nothing to be done for ..." or
# "No rule to make target ..." depending on whether the target exists.
unknown-single := $(filter-out $(addsuffix /%, $(subdir-ym)), \
$(filter-out $(curdir-single), $(KBUILD_SINGLE_TARGETS)))
single-subdirs := $(foreach d, $(subdir-ym), \
$(if $(filter $(d)/%, $(KBUILD_SINGLE_TARGETS)), $(d)))
__build: $(curdir-single) $(single-subdirs)
ifneq ($(unknown-single),)
$(Q)$(MAKE) -f /dev/null $(unknown-single)
endif
@:
ifeq ($(curdir-single),)
# Nothing to do in this directory. Do not include any .*.cmd file for speed-up
targets :=
else
targets += $(curdir-single)
endif
else
__build: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \
$(if $(KBUILD_MODULES), $(targets-for-modules)) \
$(subdir-ym) $(always-y)
@:
endif
# Descending
# ---------------------------------------------------------------------------
PHONY += $(subdir-ym)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@ \
$(if $(filter $@/, $(KBUILD_SINGLE_TARGETS)),single-build=) \
need-builtin=$(if $(filter $@/built-in.a, $(subdir-builtin)),1) \
need-modorder=$(if $(filter $@/modules.order, $(subdir-modorder)),1)
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
PHONY += FORCE
FORCE:
# Read all saved command lines and dependencies for the $(targets) we
# may be building above, using $(if_changed{,_dep}). As an
# optimization, we don't need to read them if the target does not
# exist, we will rebuild anyway in that case.
existing-targets := $(wildcard $(sort $(targets)))
-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
# Create directories for object files if they do not exist
obj-dirs := $(sort $(patsubst %/,%, $(dir $(targets))))
# If targets exist, their directories apparently exist. Skip mkdir.
existing-dirs := $(sort $(patsubst %/,%, $(dir $(existing-targets))))
obj-dirs := $(strip $(filter-out $(existing-dirs), $(obj-dirs)))
ifneq ($(obj-dirs),)
$(shell mkdir -p $(obj-dirs))
endif
.PHONY: $(PHONY)

73
scripts/Makefile.clean Normal file
View File

@ -0,0 +1,73 @@
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
# Cleaning up
# ==========================================================================
src := $(obj)
PHONY := __clean
__clean:
include scripts/Kbuild.include
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
# Figure out what we need to build from the various variables
# ==========================================================================
subdir-ymn := $(sort $(subdir-y) $(subdir-m) $(subdir-) \
$(patsubst %/,%, $(filter %/, $(obj-y) $(obj-m) $(obj-))))
# Add subdir path
subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
# build a list of files to remove, usually relative to the current
# directory
__clean-files := \
$(clean-files) $(targets) $(hostprogs) $(userprogs) \
$(extra-y) $(extra-m) $(extra-) \
$(always-y) $(always-m) $(always-) \
$(hostprogs-always-y) $(hostprogs-always-m) $(hostprogs-always-) \
$(userprogs-always-y) $(userprogs-always-m) $(userprogs-always-)
# deprecated
__clean-files += $(always) $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
__clean-files := $(filter-out $(no-clean-files), $(__clean-files))
# clean-files is given relative to the current directory, unless it
# starts with $(objtree)/ (which means "./", so do not add "./" unless
# you want to delete a file from the toplevel object directory).
__clean-files := $(wildcard \
$(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \
$(filter $(objtree)/%, $(__clean-files)))
# ==========================================================================
quiet_cmd_clean = CLEAN $(obj)
cmd_clean = rm -rf $(__clean-files)
__clean: $(subdir-ymn)
ifneq ($(strip $(__clean-files)),)
$(call cmd,clean)
endif
@:
# ===========================================================================
# Generic stuff
# ===========================================================================
# Descending
# ---------------------------------------------------------------------------
PHONY += $(subdir-ymn)
$(subdir-ymn):
$(Q)$(MAKE) $(clean)=$@
.PHONY: $(PHONY)

4
scripts/kconfig/Kconfiglib/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.py[co]
build/
*.egg-info/
dist/

View File

@ -0,0 +1,5 @@
Copyright (c) 2011-2019, Ulf Magnusson <ulfalizer@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,2 @@
# Include the license file in source distributions
include LICENSE.txt

View File

@ -0,0 +1,841 @@
.. contents:: Table of contents
:backlinks: none
News
----
Dependency loop with recent linux-next kernels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To fix issues with dependency loops on recent linux-next kernels, apply `this
patch <https://www.spinics.net/lists/linux-kbuild/msg23455.html>`_. Hopefully,
it will be in ``linux-next`` soon.
``windows-curses`` is no longer automatically installed on Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Starting with Kconfiglib 13.0.0, the `windows-curses
<https://github.com/zephyrproject-rtos/windows-curses>`__ package is no longer
automatically installed on Windows, and needs to be installed manually for the
terminal ``menuconfig`` to work.
This fixes installation of Kconfiglib on MSYS2, which is not compatible with
``windows-curses``. See `this issue
<https://github.com/ulfalizer/Kconfiglib/issues/77>`__.
The ``menuconfig`` now shows a hint re. installing ``windows-curses`` when the
``curses`` module can't be imported on Windows.
Sorry if this change caused problems!
Overview
--------
Kconfiglib is a `Kconfig
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-language.rst>`__
implementation in Python 2/3. It started out as a helper library, but now has a
enough functionality to also work well as a standalone Kconfig implementation
(including `terminal and GUI menuconfig interfaces <Menuconfig interfaces_>`_
and `Kconfig extensions`_).
The entire library is contained in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_. The
bundled scripts are implemented on top of it. Implementing your own scripts
should be relatively easy, if needed.
Kconfiglib is used exclusively by e.g. the `Zephyr
<https://www.zephyrproject.org/>`__, `esp-idf
<https://github.com/espressif/esp-idf>`__, and `ACRN
<https://projectacrn.org/>`__ projects. It is also used for many small helper
scripts in various projects.
Since Kconfiglib is based around a library, it can be used e.g. to generate a
`Kconfig cross-reference
<https://docs.zephyrproject.org/latest/reference/kconfig/index.html>`_, using
the same robust Kconfig parser used for other Kconfig tools, instead of brittle
ad-hoc parsing. The documentation generation script can be found `here
<https://github.com/zephyrproject-rtos/zephyr/blob/master/doc/scripts/genrest.py>`__.
Kconfiglib implements the recently added `Kconfig preprocessor
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-macro-language.rst>`__.
For backwards compatibility, environment variables can be referenced both as
``$(FOO)`` (the new syntax) and as ``$FOO`` (the old syntax). The old syntax is
deprecated, but will probably be supported for a long time, as it's needed to
stay compatible with older Linux kernels. The major version will be increased
if support is ever dropped. Using the old syntax with an undefined environment
variable keeps the string as is.
Note: See `this issue <https://github.com/ulfalizer/Kconfiglib/issues/47>`__ if
you run into a "macro expanded to blank string" error with kernel 4.18+.
See `this page
<https://docs.zephyrproject.org/latest/guides/kconfig/tips.html>`__ for some
Kconfig tips and best practices.
Installation
------------
Installation with pip
~~~~~~~~~~~~~~~~~~~~~
Kconfiglib is available on `PyPI <https://pypi.python.org/pypi/kconfiglib/>`_ and can be
installed with e.g.
.. code::
$ pip(3) install kconfiglib
Microsoft Windows is supported.
The ``pip`` installation will give you both the base library and the following
executables. All but two (``genconfig`` and ``setconfig``) mirror functionality
available in the C tools.
- `menuconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_
- `guiconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_
- `oldconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/oldconfig.py>`_
- `olddefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/olddefconfig.py>`_
- `savedefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/savedefconfig.py>`_
- `defconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/defconfig.py>`_
- `alldefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/alldefconfig.py>`_
- `allnoconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allnoconfig.py>`_
- `allmodconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allmodconfig.py>`_
- `allyesconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_
- `listnewconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/listnewconfig.py>`_
- `genconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/genconfig.py>`_
- `setconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/setconfig.py>`_
``genconfig`` is intended to be run at build time. It generates a C header from
the configuration and (optionally) information that can be used to rebuild only
files that reference Kconfig symbols that have changed value.
Starting with Kconfiglib version 12.2.0, all utilities are compatible with both
Python 2 and Python 3. Previously, ``menuconfig.py`` only ran under Python 3
(i.e., it's now more backwards compatible than before).
**Note:** If you install Kconfiglib with ``pip``'s ``--user`` flag, make sure
that your ``PATH`` includes the directory where the executables end up. You can
list the installed files with ``pip(3) show -f kconfiglib``.
All releases have a corresponding tag in the git repository, e.g. ``v14.1.0``
(the latest version).
`Semantic versioning <http://semver.org/>`_ is used. There's been ten small
changes to the behavior of the API, a Windows packaging change, and a hashbang
change to use ``python3``
(`1 <https://github.com/ulfalizer/Kconfiglib/commit/e8b4ecb6ff6ccc1c7be0818314fbccda2ef2b2ee>`_,
`2 <https://github.com/ulfalizer/Kconfiglib/commit/db633015a4d7b0ba1e882f665e191f350932b2af>`_,
`3 <https://github.com/ulfalizer/Kconfiglib/commit/8983f7eb297dd614faf0beee3129559bc8ba338e>`_,
`4 <https://github.com/ulfalizer/Kconfiglib/commit/cbf32e29a130d22bc734b7778e6304ac9df2a3e8>`_,
`5 <https://github.com/ulfalizer/Kconfiglib/commit/eb6c21a9b33a2d6e2bed9882d4f930d0cab2f03b>`_,
`6 <https://github.com/ulfalizer/Kconfiglib/commit/c19fc11355b13d75d97286402c7a933fb23d3b70>`_,
`7 <https://github.com/ulfalizer/Kconfiglib/commit/7a428aa415606820a44291f475248b08e3952c4b>`_,
`8 <https://github.com/ulfalizer/Kconfiglib/commit/f247ddf618ad29718e5efd3e69f8baf75d4d347b>`_,
`9 <https://github.com/ulfalizer/Kconfiglib/commit/4fed39d9271ceb68be4157ab3f96a45b94f77dc0>`_,
`10 <https://github.com/ulfalizer/Kconfiglib/commit/55bc8c380869ea663092212e8fe388ad7abae596>`_,
`Windows packaging change <https://github.com/ulfalizer/Kconfiglib/commit/21b4c1e3b6e2867b9a0788d21a358f6b1f581d86>`_,
`Python 3 hashbang change <https://github.com/ulfalizer/Kconfiglib/commit/9e0a8d29fa76adcb3f27bb2e20f16fefc2a8591e>`_),
which is why the major version is at 14 rather than 2. I do major version bumps
for all behavior changes, even tiny ones, and most of these were fixes for baby
issues in the early days of the Kconfiglib 2 API.
Manual installation
~~~~~~~~~~~~~~~~~~~
Just drop ``kconfiglib.py`` and the scripts you want somewhere. There are no
third-party dependencies, but the terminal ``menuconfig`` won't work on Windows
unless a package like `windows-curses
<https://github.com/zephyrproject-rtos/windows-curses>`__ is installed.
Installation for the Linux kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See the module docstring at the top of `kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
Python version compatibility (2.7/3.2+)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kconfiglib and all utilities run under both Python 2.7 and Python 3.2 and
later. The code mostly uses basic Python features and has no third-party
dependencies, so keeping it backwards-compatible is pretty low effort.
The 3.2 requirement comes from ``argparse``. ``format()`` with unnumbered
``{}`` is used as well.
A recent Python 3 version is recommended if you have a choice, as it'll give
you better Unicode handling.
Getting started
---------------
1. `Install <Installation_>`_ the library and the utilities.
2. Write `Kconfig
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-language.rst>`__
files that describe the available configuration options. See `this page
<https://docs.zephyrproject.org/latest/guides/kconfig/tips.html>`__ for some
general Kconfig advice.
3. Generate an initial configuration with e.g. ``menuconfig``/``guiconfig`` or
``alldefconfig``. The configuration is saved as ``.config`` by default.
For more advanced projects, the ``defconfig`` utility can be used to
generate the initial configuration from an existing configuration file.
Usually, this existing configuration file would be a minimal configuration
file, as generated by e.g. ``savedefconfig``.
4. Run ``genconfig`` to generate a header file. By default, it is saved as
``config.h``.
Normally, ``genconfig`` would be run automatically as part of the build.
Before writing a header file or other configuration output, Kconfiglib
compares the old contents of the file against the new contents. If there's
no change, the write is skipped. This avoids updating file metadata like the
modification time, and might save work depending on your build setup.
Adding new configuration output formats should be relatively straightforward.
See the implementation of ``write_config()`` in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
The documentation for the ``Symbol.config_string`` property has some tips as
well.
5. To update an old ``.config`` file after the Kconfig files have changed (e.g.
to add new options), run ``oldconfig`` (prompts for values for new options)
or ``olddefconfig`` (gives new options their default value). Entering the
``menuconfig`` or ``guiconfig`` interface and saving the configuration will
also update it (the configuration interfaces always prompt for saving
on exit if it would modify the contents of the ``.config`` file).
Due to Kconfig semantics, simply loading an old ``.config`` file performs an
implicit ``olddefconfig``, so building will normally not be affected by
having an outdated configuration.
Whenever ``.config`` is overwritten, the previous version of the file is saved
to ``.config.old`` (or, more generally, to ``$KCONFIG_CONFIG.old``).
Using ``.config`` files as Make input
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``.config`` files use Make syntax and can be included directly in Makefiles to
read configuration values from there. This is why ``n``-valued
``bool``/``tristate`` values are written out as ``# CONFIG_FOO is not set`` (a
Make comment) in ``.config``, allowing them to be tested with ``ifdef`` in
Make.
If you make use of this, you might want to pass ``--config-out <filename>`` to
``genconfig`` and include the configuration file it generates instead of
including ``.config`` directly. This has the advantage that the generated
configuration file will always be a "full" configuration file, even if
``.config`` is outdated. Otherwise, it might be necessary to run
``old(def)config`` or ``menuconfig``/``guiconfig`` before rebuilding with an
outdated ``.config``.
If you use ``--sync-deps`` to generate incremental build information, you can
include ``deps/auto.conf`` instead, which is also a full configuration file.
Useful helper macros
~~~~~~~~~~~~~~~~~~~~
The `include/linux/kconfig.h
<https://github.com/torvalds/linux/blob/master/include/linux/kconfig.h>`_
header in the Linux kernel defines some useful helper macros for testing
Kconfig configuration values.
``IS_ENABLED()`` is generally useful, allowing configuration values to be
tested in ``if`` statements with no runtime overhead.
Incremental building
~~~~~~~~~~~~~~~~~~~~
See the docstring for ``Kconfig.sync_deps()`` in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_ for hints
on implementing incremental builds (rebuilding just source files that reference
changed configuration values).
Running the ``scripts/basic/fixdep.c`` tool from the kernel on the output of
``gcc -MD <source file>`` might give you an idea of how it all fits together.
Library documentation
---------------------
Kconfiglib comes with extensive documentation in the form of docstrings. To view it, run e.g.
the following command:
.. code:: sh
$ pydoc(3) kconfiglib
For HTML output, add ``-w``:
.. code:: sh
$ pydoc(3) -w kconfiglib
This will also work after installing Kconfiglib with ``pip(3)``.
Documentation for other modules can be viewed in the same way (though a plain
``--help`` will work when they're run as executables):
.. code:: sh
$ pydoc(3) menuconfig/guiconfig/...
A good starting point for learning the library is to read the module docstring
(which you could also just read directly at the beginning of `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_). It
gives an introduction to symbol values, the menu tree, and expressions.
After reading the module docstring, a good next step is to read the ``Kconfig``
class documentation, and then the documentation for the ``Symbol``, ``Choice``,
and ``MenuNode`` classes.
Please tell me if something is unclear or can be explained better.
Library features
----------------
Kconfiglib can do the following, among other things:
- **Programmatically get and set symbol values**
See `allnoconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allnoconfig.py>`_ and
`allyesconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_,
which are automatically verified to produce identical output to the standard
``make allnoconfig`` and ``make allyesconfig``.
- **Read and write .config and defconfig files**
The generated ``.config`` and ``defconfig`` (minimal configuration) files are
character-for-character identical to what the C implementation would generate
(except for the header comment). The test suite relies on this, as it
compares the generated files.
- **Write C headers**
The generated headers use the same format as ``include/generated/autoconf.h``
from the Linux kernel. Output for symbols appears in the order that they're
defined, unlike in the C tools (where the order depends on the hash table
implementation).
- **Implement incremental builds**
This uses the same scheme as the ``include/config`` directory in the kernel:
Symbols are translated into files that are touched when the symbol's value
changes between builds, which can be used to avoid having to do a full
rebuild whenever the configuration is changed.
See the ``sync_deps()`` function for more information.
- **Inspect symbols**
Printing a symbol or other item (which calls ``__str__()``) returns its
definition in Kconfig format. This also works for symbols defined in multiple
locations.
A helpful ``__repr__()`` is on all objects too.
All ``__str__()`` and ``__repr__()`` methods are deliberately implemented
with just public APIs, so all symbol information can be fetched separately as
well.
- **Inspect expressions**
Expressions use a simple tuple-based format that can be processed manually
if needed. Expression printing and evaluation functions are provided,
implemented with public APIs.
- **Inspect the menu tree**
The underlying menu tree is exposed, including submenus created implicitly
from symbols depending on preceding symbols. This can be used e.g. to
implement menuconfig-like functionality.
See `menuconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_/`guiconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_ and the
minimalistic `menuconfig_example.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/examples/menuconfig_example.py>`_
example.
Kconfig extensions
~~~~~~~~~~~~~~~~~~
The following Kconfig extensions are available:
- ``source`` supports glob patterns and includes each matching file. A pattern
is required to match at least one file.
A separate ``osource`` statement is available for cases where it's okay for
the pattern to match no files (in which case ``osource`` turns into a no-op).
- A relative ``source`` statement (``rsource``) is available, where file paths
are specified relative to the directory of the current Kconfig file. An
``orsource`` statement is available as well, analogous to ``osource``.
- Preprocessor user functions can be defined in Python, which makes it simple
to integrate information from existing Python tools into Kconfig (e.g. to
have Kconfig symbols depend on hardware information stored in some other
format).
See the *Kconfig extensions* section in the
`kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_
module docstring for more information.
- ``def_int``, ``def_hex``, and ``def_string`` are available in addition to
``def_bool`` and ``def_tristate``, allowing ``int``, ``hex``, and ``string``
symbols to be given a type and a default at the same time.
These can be useful in projects that make use of symbols defined in multiple
locations, and remove some Kconfig inconsistency.
- Environment variables are expanded directly in e.g. ``source`` and
``mainmenu`` statements, meaning ``option env`` symbols are redundant.
This is the standard behavior with the new `Kconfig preprocessor
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-macro-language.rst>`__,
which Kconfiglib implements.
``option env`` symbols are accepted but ignored, which leads the caveat that
they must have the same name as the environment variables they reference
(Kconfiglib warns if the names differ). This keeps Kconfiglib compatible with
older Linux kernels, where the name of the ``option env`` symbol always
matched the environment variable. Compatibility with older Linux kernels is
the main reason ``option env`` is still supported.
The C tools have dropped support for ``option env``.
- Two extra optional warnings can be enabled by setting environment variables,
covering cases that are easily missed when making changes to Kconfig files:
* ``KCONFIG_WARN_UNDEF``: If set to ``y``, warnings will be generated for all
references to undefined symbols within Kconfig files. The only gotcha is
that all hex literals must be prefixed with ``0x`` or ``0X``, to make it
possible to distinguish them from symbol references.
Some projects (e.g. the Linux kernel) use multiple Kconfig trees with many
shared Kconfig files, leading to some safe undefined symbol references.
``KCONFIG_WARN_UNDEF`` is useful in projects that only have a single
Kconfig tree though.
``KCONFIG_STRICT`` is an older alias for this environment variable,
supported for backwards compatibility.
* ``KCONFIG_WARN_UNDEF_ASSIGN``: If set to ``y``, warnings will be generated
for all assignments to undefined symbols within ``.config`` files. By
default, no such warnings are generated.
This warning can also be enabled/disabled by setting
``Kconfig.warn_assign_undef`` to ``True``/``False``.
Other features
--------------
- **Single-file implementation**
The entire library is contained in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
The tools implemented on top of it are one file each.
- **Robust and highly compatible with the C Kconfig tools**
 The `test suite <https://github.com/ulfalizer/Kconfiglib/blob/master/testsuite.py>`_
automatically compares output from Kconfiglib and the C tools
by diffing the generated ``.config`` files for the real kernel Kconfig and
defconfig files, for all ARCHes.
This currently involves comparing the output for 36 ARCHes and 498 defconfig
files (or over 18000 ARCH/defconfig combinations in "obsessive" test suite
mode). All tests are expected to pass.
A comprehensive suite of selftests is included as well.
- **Not horribly slow despite being a pure Python implementation**
The `allyesconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_
script currently runs in about 1.3 seconds on the Linux kernel on a Core i7
2600K (with a warm file cache), including the ``make`` overhead from ``make
scriptconfig``. Note that the Linux kernel Kconfigs are absolutely massive
(over 14k symbols for x86) compared to most projects, and also have overhead
from running shell commands via the Kconfig preprocessor.
Kconfiglib is especially speedy in cases where multiple ``.config`` files
need to be processed, because the ``Kconfig`` files will only need to be parsed
once.
For long-running jobs, `PyPy <https://pypy.org/>`_ gives a big performance
boost. CPython is faster for short-running jobs as PyPy needs some time to
warm up.
Kconfiglib also works well with the
`multiprocessing <https://docs.python.org/3/library/multiprocessing.html>`_
module. No global state is kept.
- **Generates more warnings than the C implementation**
Generates the same warnings as the C implementation, plus additional ones.
Also detects dependency and ``source`` loops.
All warnings point out the location(s) in the ``Kconfig`` files where a
symbol is defined, where applicable.
- **Unicode support**
Unicode characters in string literals in ``Kconfig`` and ``.config`` files are
correctly handled. This support mostly comes for free from Python.
- **Windows support**
Nothing Linux-specific is used. Universal newlines mode is used for both
Python 2 and Python 3.
The `Zephyr <https://www.zephyrproject.org/>`_ project uses Kconfiglib to
generate ``.config`` files and C headers on Linux as well as Windows.
- **Internals that (mostly) mirror the C implementation**
While being simpler to understand and tweak.
Menuconfig interfaces
---------------------
Three configuration interfaces are currently available:
- `menuconfig.py <https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_
is a terminal-based configuration interface implemented using the standard
Python ``curses`` module. ``xconfig`` features like showing invisible symbols and
showing symbol names are included, and it's possible to jump directly to a symbol
in the menu tree (even if it's currently invisible).
.. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/menuconfig.gif
*There is now also a show-help mode that shows the help text of the currently
selected symbol in the help window at the bottom.*
Starting with Kconfiglib 12.2.0, ``menuconfig.py`` runs under both Python 2
and Python 3 (previously, it only ran under Python 3, so this was a
backport). Running it under Python 3 provides better support for Unicode text
entry (``get_wch()`` is not available in the ``curses`` module on Python 2).
There are no third-party dependencies on \*nix. On Windows,
the ``curses`` modules is not available by default, but support
can be added by installing the ``windows-curses`` package:
.. code-block:: shell
$ pip install windows-curses
This uses wheels built from `this repository
<https://github.com/zephyrproject-rtos/windows-curses>`_, which is in turn
based on Christoph Gohlke's `Python Extension Packages for Windows
<https://www.lfd.uci.edu/~gohlke/pythonlibs/#curses>`_.
See the docstring at the top of `menuconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_ for
more information about the terminal menuconfig implementation.
- `guiconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_ is a
graphical configuration interface written in `Tkinter
<https://docs.python.org/3/library/tkinter.html>`_. Like ``menuconfig.py``,
it supports showing all symbols (with invisible symbols in red) and jumping
directly to symbols. Symbol values can also be changed directly from the
jump-to dialog.
When single-menu mode is enabled, a single menu is shown at a time, like in
the terminal menuconfig. Only this mode distinguishes between symbols defined
with ``config`` and symbols defined with ``menuconfig``.
``guiconfig.py`` has been tested on X11, Windows, and macOS, and is
compatible with both Python 2 and Python 3.
Despite being part of the Python standard library, ``tkinter`` often isn't
included by default in Python installations on Linux. These commands will
install it on a few different distributions:
- Ubuntu: ``sudo apt install python-tk``/``sudo apt install python3-tk``
- Fedora: ``dnf install python2-tkinter``/``dnf install python3-tkinter``
- Arch: ``sudo pacman -S tk``
- Clear Linux: ``sudo swupd bundle-add python3-tcl``
Screenshot below, with show-all mode enabled and the jump-to dialog open:
.. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/guiconfig.png
To avoid having to carry around a bunch of GIFs, the image data is embedded
in ``guiconfig.py``. To use separate GIF files instead, change
``_USE_EMBEDDED_IMAGES`` to ``False`` in ``guiconfig.py``. The image files
can be found in the `screenshots
<https://github.com/ulfalizer/Kconfiglib/tree/screenshots/guiconfig>`_
branch.
I did my best with the images, but some are definitely only art adjacent.
Touch-ups are welcome. :)
- `pymenuconfig <https://github.com/RomaVis/pymenuconfig>`_, built by `RomaVis
<https://github.com/RomaVis>`_, is an older portable Python 2/3 TkInter
menuconfig implementation.
Screenshot below:
.. image:: https://raw.githubusercontent.com/RomaVis/pymenuconfig/master/screenshot.PNG
While working on the terminal menuconfig implementation, I added a few APIs
to Kconfiglib that turned out to be handy. ``pymenuconfig`` predates
``menuconfig.py`` and ``guiconfig.py``, and so didn't have them available.
Blame me for any workarounds.
Examples
--------
Example scripts
~~~~~~~~~~~~~~~
The `examples/ <https://github.com/ulfalizer/Kconfiglib/blob/master/examples>`_ directory contains some simple example scripts. Among these are the following ones. Make sure you run them with the latest version of Kconfiglib, as they might make use of newly added features.
- `eval_expr.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/eval_expr.py>`_ evaluates an expression in the context of a configuration.
- `find_symbol.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/find_symbol.py>`_ searches through expressions to find references to a symbol, also printing a "backtrace" with parents for each reference found.
- `help_grep.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/help_grep.py>`_ searches for a string in all help texts.
- `print_tree.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/print_tree.py>`_ prints a tree of all configuration items.
- `print_config_tree.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/print_config_tree.py>`_ is similar to ``print_tree.py``, but dumps the tree as it would appear in ``menuconfig``, including values. This can be handy for visually diffing between ``.config`` files and different versions of ``Kconfig`` files.
- `list_undefined.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/list_undefined.py>`_ finds references to symbols that are not defined by any architecture in the Linux kernel.
- `merge_config.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/merge_config.py>`_ merges configuration fragments to produce a complete .config, similarly to ``scripts/kconfig/merge_config.sh`` from the kernel.
- `menuconfig_example.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/menuconfig_example.py>`_ implements a configuration interface that uses notation similar to ``make menuconfig``. It's deliberately kept as simple as possible to demonstrate just the core concepts.
Real-world examples
~~~~~~~~~~~~~~~~~~~
- `kconfig.py
<https://github.com/zephyrproject-rtos/zephyr/blob/master/scripts/kconfig/kconfig.py>`_
from the `Zephyr <https://www.zephyrproject.org/>`_ project handles
``.config`` and header file generation, also doing configuration fragment
merging
- `genrest.py
<https://github.com/zephyrproject-rtos/zephyr/blob/master/doc/scripts/genrest.py>`_
generates a Kconfig symbol cross-reference, which can be viewed `here
<http://docs.zephyrproject.org/reference/kconfig/index.html>`__
- `CMake and IDE integration
<https://github.com/espressif/esp-idf/tree/master/tools/kconfig_new>`_ from
the ESP-IDF project, via a configuration server program.
- `A script for turning on USB-related options
<https://github.com/google/syzkaller/blob/master/dashboard/config/kconfiglib-merge-usb-configs.py>`_,
from the `syzkaller <https://github.com/google/syzkaller>`_ project.
- `Various automated checks
<https://github.com/zephyrproject-rtos/ci-tools/blob/master/scripts/check_compliance.py>`_,
including a check for references to undefined Kconfig symbols in source code.
See the ``KconfigCheck`` class.
- `Various utilities
<https://github.com/projectacrn/acrn-hypervisor/tree/master/scripts/kconfig>`_
from the `ACRN <https://projectacrn.org/>`_ project
These use the older Kconfiglib 1 API, which was clunkier and not as general
(functions instead of properties, no direct access to the menu structure or
properties, uglier ``__str__()`` output):
- `genboardscfg.py <http://git.denx.de/?p=u-boot.git;a=blob;f=tools/genboardscfg.py;hb=HEAD>`_ from `Das U-Boot <http://www.denx.de/wiki/U-Boot>`_ generates some sort of legacy board database by pulling information from a newly added Kconfig-based configuration system (as far as I understand it :).
- `gen-manual-lists.py <https://git.busybox.net/buildroot/tree/support/scripts/gen-manual-lists.py?id=5676a2deea896f38123b99781da0a612865adeb0>`_ generated listings for an appendix in the `Buildroot <https://buildroot.org>`_ manual. (The listing has since been removed.)
- `gen_kconfig_doc.py <https://github.com/espressif/esp-idf/blob/master/docs/gen-kconfig-doc.py>`_ from the `esp-idf <https://github.com/espressif/esp-idf>`_ project generates documentation from Kconfig files.
- `SConf <https://github.com/CoryXie/SConf>`_ builds an interactive configuration interface (like ``menuconfig``) on top of Kconfiglib, for use e.g. with `SCons <scons.org>`_.
- `kconfig-diff.py <https://gist.github.com/dubiousjim/5638961>`_ -- a script by `dubiousjim <https://github.com/dubiousjim>`_ that compares kernel configurations.
- Originally, Kconfiglib was used in chapter 4 of my `master's thesis <http://liu.diva-portal.org/smash/get/diva2:473038/FULLTEXT01.pdf>`_ to automatically generate a "minimal" kernel for a given system. Parts of it bother me a bit now, but that's how it goes with old work.
Sample ``make iscriptconfig`` session
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following log should give some idea of the functionality available in the API:
.. code-block::
$ make iscriptconfig
A Kconfig instance 'kconf' for the architecture x86 has been created.
>>> kconf # Calls Kconfig.__repr__()
<configuration with 13711 symbols, main menu prompt "Linux/x86 4.14.0-rc7 Kernel Configuration", srctree ".", config symbol prefix "CONFIG_", warnings enabled, undef. symbol assignment warnings disabled>
>>> kconf.mainmenu_text # Expanded main menu text
'Linux/x86 4.14.0-rc7 Kernel Configuration'
>>> kconf.top_node # The implicit top-level menu
<menu node for menu, prompt "Linux/x86 4.14.0-rc7 Kernel Configuration" (visibility y), deps y, 'visible if' deps y, has child, Kconfig:5>
>>> kconf.top_node.list # First child menu node
<menu node for symbol SRCARCH, deps y, has next, Kconfig:7>
>>> print(kconf.top_node.list) # Calls MenuNode.__str__()
config SRCARCH
string
option env="SRCARCH"
default "x86"
>>> sym = kconf.top_node.list.next.item # Item contained in next menu node
>>> print(sym) # Calls Symbol.__str__()
config 64BIT
bool "64-bit kernel" if ARCH = "x86"
default ARCH != "i386"
help
Say yes to build a 64-bit kernel - formerly known as x86_64
Say no to build a 32-bit kernel - formerly known as i386
>>> sym # Calls Symbol.__repr__()
<symbol 64BIT, bool, "64-bit kernel", value y, visibility y, direct deps y, arch/x86/Kconfig:2>
>>> sym.assignable # Currently assignable values (0, 1, 2 = n, m, y)
(0, 2)
>>> sym.set_value(0) # Set it to n
True
>>> sym.tri_value # Check the new value
0
>>> sym = kconf.syms["X86_MPPARSE"] # Look up symbol by name
>>> print(sym)
config X86_MPPARSE
bool "Enable MPS table" if (ACPI || SFI) && X86_LOCAL_APIC
default y if X86_LOCAL_APIC
help
For old smp systems that do not have proper acpi support. Newer systems
(esp with 64bit cpus) with acpi support, MADT and DSDT will override it
>>> default = sym.defaults[0] # Fetch its first default
>>> sym = default[1] # Fetch the default's condition (just a Symbol here)
>>> print(sym)
config X86_LOCAL_APIC
bool
default y
select IRQ_DOMAIN_HIERARCHY
select PCI_MSI_IRQ_DOMAIN if PCI_MSI
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
>>> sym.nodes # Show the MenuNode(s) associated with it
[<menu node for symbol X86_LOCAL_APIC, deps n, has next, arch/x86/Kconfig:1015>]
>>> kconfiglib.expr_str(sym.defaults[0][1]) # Print the default's condition
'X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI'
>>> kconfiglib.expr_value(sym.defaults[0][1]) # Evaluate it (0 = n)
0
>>> kconf.syms["64BIT"].set_value(2)
True
>>> kconfiglib.expr_value(sym.defaults[0][1]) # Evaluate it again (2 = y)
2
>>> kconf.write_config("myconfig") # Save a .config
>>> ^D
$ cat myconfig
# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)
CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
...
Test suite
----------
The test suite is run with
.. code::
$ python(3) Kconfiglib/testsuite.py
`pypy <https://pypy.org/>`_ works too, and is much speedier for everything except ``allnoconfig.py``/``allnoconfig_simpler.py``/``allyesconfig.py``, where it doesn't have time to warm up since
the scripts are run via ``make scriptconfig``.
The test suite must be run from the top-level kernel directory. It requires that the
Kconfiglib git repository has been cloned into it and that the makefile patch has been applied.
To get rid of warnings generated for the kernel ``Kconfig`` files, add ``2>/dev/null`` to the command to
discard ``stderr``.
**NOTE: Forgetting to apply the Makefile patch will cause some tests that compare generated configurations to fail**
**NOTE: The test suite overwrites .config in the kernel root, so make sure to back it up.**
The test suite consists of a set of selftests and a set of compatibility tests that
compare configurations generated by Kconfiglib with
configurations generated by the C tools, for a number of cases. See
`testsuite.py <https://github.com/ulfalizer/Kconfiglib/blob/master/testsuite.py>`_
for the available options.
The `tests/reltest <https://github.com/ulfalizer/Kconfiglib/blob/master/tests/reltest>`_ script runs the test suite
and all the example scripts for both Python 2 and Python 3, verifying that everything works.
Rarely, the output from the C tools is changed slightly (most recently due to a
`change <https://www.spinics.net/lists/linux-kbuild/msg17074.html>`_ I added).
If you get test suite failures, try running the test suite again against the
`linux-next tree <https://www.kernel.org/doc/man-pages/linux-next.html>`_,
which has all the latest changes. I will make it clear if any
non-backwards-compatible changes appear.
A lot of time is spent waiting around for ``make`` and the C utilities (which need to reparse all the
Kconfig files for each defconfig test). Adding some multiprocessing to the test suite would make sense
too.
Notes
-----
* This is version 2 of Kconfiglib, which is not backwards-compatible with
Kconfiglib 1. A summary of changes between Kconfiglib 1 and Kconfiglib
2 can be found `here
<https://github.com/ulfalizer/Kconfiglib/blob/screenshots/kconfiglib-2-changes.txt>`__.
* I sometimes see people add custom output formats, which is pretty
straightforward to do (see the implementations of ``write_autoconf()`` and
``write_config()`` for a template, and also the documentation of the
``Symbol.config_string`` property). If you come up with something you think
might be useful to other people, I'm happy to take it in upstream. Batteries
included and all that.
* Kconfiglib assumes the modules symbol is ``MODULES``, which is backwards-compatible.
A warning is printed by default if ``option modules`` is set on some other symbol.
Let me know if you need proper ``option modules`` support. It wouldn't be that
hard to add.
Thanks
------
- To `RomaVis <https://github.com/RomaVis>`_, for making
`pymenuconfig <https://github.com/RomaVis/pymenuconfig>`_ and suggesting
the ``rsource`` keyword.
- To `Mitja Horvat <https://github.com/pinkfluid>`_, for adding support
for user-defined styles to the terminal menuconfig.
- To `Philip Craig <https://github.com/philipc>`_ for adding
support for the ``allnoconfig_y`` option and fixing an obscure issue
with ``comment``\s inside ``choice``\s (that didn't affect correctness but
made outputs differ). ``allnoconfig_y`` is used to force certain symbols
to ``y`` during ``make allnoconfig`` to improve coverage.
License
-------
See `LICENSE.txt <https://github.com/ulfalizer/Kconfiglib/blob/master/LICENSE.txt>`_. SPDX license identifiers are used in the
source code.

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where all symbols are set to their their default
values.
The default output filename is '.config'. A different filename can be passed in
the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/alldefconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
kconf.load_allconfig("alldef.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,46 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'm'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allmodconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# See allnoconfig.py
kconf.warn = False
for sym in kconf.unique_defined_syms:
if sym.orig_type == kconfiglib.BOOL:
# 'bool' choice symbols get their default value, as determined by
# e.g. 'default's on the choice
if not sym.choice:
# All other bool symbols get set to 'y', like for allyesconfig
sym.set_value(2)
elif sym.orig_type == kconfiglib.TRISTATE:
sym.set_value(1)
for choice in kconf.unique_choices:
choice.set_value(2 if choice.orig_type == kconfiglib.BOOL else 1)
kconf.warn = True
kconf.load_allconfig("allmod.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,45 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'n'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allnoconfig.py
"""
# See examples/allnoconfig_walk.py for another way to implement this script
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# Avoid warnings that would otherwise get printed by Kconfiglib for the
# following:
#
# 1. Assigning a value to a symbol without a prompt, which never has any
# effect
#
# 2. Assigning values invalid for the type (only bool/tristate symbols
# accept 0/1/2, for n/m/y). The assignments will be ignored for other
# symbol types, which is what we want.
kconf.warn = False
for sym in kconf.unique_defined_syms:
sym.set_value(2 if sym.is_allnoconfig_y else 0)
kconf.warn = True
kconf.load_allconfig("allno.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'y'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allyesconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# See allnoconfig.py
kconf.warn = False
# Try to set all symbols to 'y'. Dependencies might truncate the value down
# later, but this will at least give the highest possible value.
#
# Assigning 0/1/2 to non-bool/tristate symbols has no effect (int/hex
# symbols still take a string, because they preserve formatting).
for sym in kconf.unique_defined_syms:
# Set choice symbols to 'm'. This value will be ignored for choices in
# 'y' mode (the "normal" mode), which will instead just get their
# default selection, but will set all symbols in m-mode choices to 'm',
# which is as high as they can go.
#
# Here's a convoluted example of how you might get an m-mode choice
# even during allyesconfig:
#
# choice
# tristate "weird choice"
# depends on m
sym.set_value(1 if sym.choice else 2)
# Set all choices to the highest possible mode
for choice in kconf.unique_choices:
choice.set_value(2)
kconf.warn = True
kconf.load_allconfig("allyes.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Reads a specified configuration file, then writes a new configuration file.
This can be used to initialize the configuration from e.g. an arch-specific
configuration file. This input configuration file would usually be a minimal
configuration file, as generated by e.g. savedefconfig.
The default output filename is '.config'. A different filename can be passed in
the KCONFIG_CONFIG environment variable.
"""
import argparse
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"config",
metavar="CONFIGURATION",
help="Input configuration file")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config(args.config))
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,102 @@
mainmenu "Example Kconfig configuration"
config MODULES
bool "Enable loadable module support"
option modules
default y
menu "Bool and tristate symbols"
config BOOL
bool "Bool symbol"
default y
config BOOL_DEP
bool "Dependent bool symbol"
depends on BOOL
# Mix it up a bit with an 'if' instead of a 'depends on'
if BOOL
config TRI_DEP
tristate "Dependent tristate symbol"
select SELECTED_BY_TRI_DEP
imply IMPLIED_BY_TRI_DEP
endif
config TWO_MENU_NODES
bool "First prompt"
depends on BOOL
config TRI
tristate "Tristate symbol"
config TWO_MENU_NODES
bool "Second prompt"
comment "These are selected by TRI_DEP"
config SELECTED_BY_TRI_DEP
tristate "Tristate selected by TRI_DEP"
config IMPLIED_BY_TRI_DEP
tristate "Tristate implied by TRI_DEP"
endmenu
menu "String, int, and hex symbols"
config STRING
string "String symbol"
default "foo"
config INT
int "Int symbol"
default 747
config HEX
hex "Hex symbol"
default 0xABC
endmenu
menu "Various choices"
choice BOOL_CHOICE
bool "Bool choice"
config BOOL_CHOICE_SYM_1
bool "Bool choice sym 1"
config BOOL_CHOICE_SYM_2
bool "Bool choice sym 2"
endchoice
choice TRI_CHOICE
tristate "Tristate choice"
config TRI_CHOICE_SYM_1
tristate "Tristate choice sym 1"
config TRI_CHOICE_SYM_2
tristate "Tristate choice sym 2"
endchoice
choice OPT_BOOL_CHOICE
bool "Optional bool choice"
optional
config OPT_BOOL_CHOICE_SYM_1
bool "Optional bool choice sym 1"
config OPT_BOOL_CHOICE_SYM_2
bool "Optional bool choice sym 2"
endchoice
endmenu

View File

@ -0,0 +1,66 @@
# This is tree-walking version of allnoconfig.py, for demonstration purposes.
# Verified by the test suite to generate identical output to 'make allnoconfig'
# for all ARCHes.
#
# Note: A more practical version would use Kconfig.node_iter(). The manual tree
# walking is for demonstration purposes.
#
# Usage for the Linux kernel:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/allnoconfig_walk.py
import sys
from kconfiglib import Kconfig, Symbol
def do_allnoconfig(node):
global changed
# Walk the tree of menu nodes. You can imagine this as going down/into menu
# entries in the menuconfig interface, setting each to n (or the lowest
# assignable value).
while node:
if isinstance(node.item, Symbol):
sym = node.item
# Is the symbol a non-allnoconfig_y symbol that can be set to a
# lower value than its current value?
if (not sym.is_allnoconfig_y and
sym.assignable and
sym.assignable[0] < sym.tri_value):
# Yup, lower it
sym.set_value(sym.assignable[0])
changed = True
# Recursively lower children
if node.list:
do_allnoconfig(node.list)
node = node.next
# Parse the Kconfig files
kconf = Kconfig(sys.argv[1])
# Do an initial pass to set 'option allnoconfig_y' symbols to y
for sym in kconf.unique_defined_syms:
if sym.is_allnoconfig_y:
sym.set_value(2)
while True:
# Changing later symbols in the configuration can sometimes allow earlier
# symbols to be lowered, e.g. if a later symbol 'select's an earlier
# symbol. To handle such situations, we do additional passes over the tree
# until we're no longer able to change the value of any symbol in a pass.
changed = False
do_allnoconfig(kconf.top_node)
# Did the pass change any symbols?
if not changed:
break
print(kconf.write_config())

View File

@ -0,0 +1,39 @@
# Produces exactly the same output as the following script:
#
# make defconfig
# echo CONFIG_ETHERNET=n >> .config
# make oldconfig
# echo CONFIG_ETHERNET=y >> .config
# yes n | make oldconfig
#
# This came up in https://github.com/ulfalizer/Kconfiglib/issues/15.
#
# Usage:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/defconfig_oldconfig.py
import sys
import kconfiglib
kconf = kconfiglib.Kconfig(sys.argv[1])
# Mirrors defconfig
kconf.load_config("arch/x86/configs/x86_64_defconfig")
kconf.write_config()
# Mirrors the first oldconfig
kconf.load_config()
kconf.syms["ETHERNET"].set_value(0)
kconf.write_config()
# Mirrors the second oldconfig
kconf.load_config()
kconf.syms["ETHERNET"].set_value(2)
for s in kconf.unique_defined_syms:
if s.user_value is None and 0 in s.assignable:
s.set_value(0)
# Write the final configuration
print(kconf.write_config())

View File

@ -0,0 +1,15 @@
# Prints all (set) environment variables referenced in the Kconfig files
# together with their values, as a list of assignments.
#
# Note: This only works for environment variables referenced via the $(FOO)
# preprocessor syntax. The older $FOO syntax is maintained for backwards
# compatibility.
import os
import sys
import kconfiglib
print(" ".join("{}='{}'".format(var, os.environ[var])
for var in kconfiglib.Kconfig(sys.argv[1]).env_vars))

View File

@ -0,0 +1,24 @@
# Evaluates an expression (e.g. "X86_64 || (X86_32 && X86_LOCAL_APIC)") in the
# context of a configuration. Note that this always yields a tristate value (n,
# m, or y).
#
# Usage:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/eval_expr.py SCRIPT_ARG=<expr>
import sys
import kconfiglib
if len(sys.argv) < 3:
sys.exit("Pass the expression to evaluate with SCRIPT_ARG=<expression>")
kconf = kconfiglib.Kconfig(sys.argv[1])
expr = sys.argv[2]
# Enable modules so that m doesn't get demoted to n
kconf.modules.set_value(2)
print("the expression '{}' evaluates to {}"
.format(expr, kconf.eval_string(expr)))

View File

@ -0,0 +1,112 @@
# Prints all menu nodes that reference a given symbol any of their properties
# or property conditions, along with their parent menu nodes.
#
# Usage:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/find_symbol.py SCRIPT_ARG=<name>
#
# Example output for SCRIPT_ARG=X86:
#
# Found 470 locations that reference X86:
#
# ========== Location 1 (init/Kconfig:1108) ==========
#
# config SGETMASK_SYSCALL
# bool
# prompt "sgetmask/ssetmask syscalls support" if EXPERT
# default PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH
# help
# sys_sgetmask and sys_ssetmask are obsolete system calls
# no longer supported in libc but still enabled by default in some
# architectures.
#
# If unsure, leave the default option here.
#
# ---------- Parent 1 (init/Kconfig:1077) ----------
#
# menuconfig EXPERT
# bool
# prompt "Configure standard kernel features (expert users)"
# select DEBUG_KERNEL
# help
# This option allows certain base kernel options and settings
# to be disabled or tweaked. This is for specialized
# environments which can tolerate a "non-standard" kernel.
# Only use this if you really know what you are doing.
#
# ---------- Parent 2 (init/Kconfig:39) ----------
#
# menu "General setup"
#
# ========== Location 2 (arch/Kconfig:29) ==========
#
# config OPROFILE_EVENT_MULTIPLEX
# bool
# prompt "OProfile multiplexing support (EXPERIMENTAL)"
# default "n"
# depends on OPROFILE && X86
# help
# The number of hardware counters is limited. The multiplexing
# feature enables OProfile to gather more events than counters
# are provided by the hardware. This is realized by switching
# between events at a user specified time interval.
#
# If unsure, say N.
#
# ---------- Parent 1 (arch/Kconfig:16) ----------
#
# config OPROFILE
# tristate
# prompt "OProfile system profiling"
# select RING_BUFFER
# select RING_BUFFER_ALLOW_SWAP
# depends on PROFILING && HAVE_OPROFILE
# help
# OProfile is a profiling system capable of profiling the
# whole system, include the kernel, kernel modules, libraries,
# and applications.
#
# If unsure, say N.
#
# ---------- Parent 2 (init/Kconfig:39) ----------
#
# menu "General setup"
#
# ... (tons more)
import sys
import kconfiglib
if len(sys.argv) < 3:
sys.exit('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=<name>')
kconf = kconfiglib.Kconfig(sys.argv[1])
sym_name = sys.argv[2]
if sym_name not in kconf.syms:
print("No symbol {} exists in the configuration".format(sym_name))
sys.exit(0)
referencing = [node for node in kconf.node_iter()
if kconf.syms[sym_name] in node.referenced]
if not referencing:
print("No references to {} found".format(sym_name))
sys.exit(0)
print("Found {} locations that reference {}:\n"
.format(len(referencing), sym_name))
for i, node in enumerate(referencing, 1):
print("========== Location {} ({}:{}) ==========\n\n{}"
.format(i, node.filename, node.linenr, node))
# Print the parents of the menu node too
node = node.parent
parent_i = 1
while node is not kconf.top_node:
print("---------- Parent {} ({}:{}) ----------\n\n{}"
.format(parent_i, node.filename, node.linenr, node))
node = node.parent
parent_i += 1

View File

@ -0,0 +1,64 @@
# Does a case-insensitive search for a regular expression in the help texts of
# symbols and choices and the prompts of menus and comments. Prints the
# matching items together with their locations and the matching text.
#
# Usage:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/help_grep.py SCRIPT_ARG=<regex>
#
# Shortened example output for SCRIPT_ARG=general:
#
# menu "General setup"
# location: init/Kconfig:39
#
# config SYSVIPC
# bool
# prompt "System V IPC"
# help
# ...
# exchange information. It is generally considered to be a good thing,
# ...
#
# location: init/Kconfig:233
#
# config BSD_PROCESS_ACCT
# bool
# prompt "BSD Process Accounting" if MULTIUSER
# help
# ...
# information. This is generally a good idea, so say Y.
#
# location: init/Kconfig:403
#
# ...
import re
import sys
from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT
if len(sys.argv) < 3:
sys.exit("Pass the regex with SCRIPT_ARG=<regex>")
search = re.compile(sys.argv[2], re.IGNORECASE).search
for node in Kconfig(sys.argv[1]).node_iter():
match = False
if isinstance(node.item, (Symbol, Choice)) and \
node.help is not None and search(node.help):
print(node.item)
match = True
elif node.item == MENU and search(node.prompt[0]):
print('menu "{}"'.format(node.prompt[0]))
match = True
elif node.item == COMMENT and search(node.prompt[0]):
print('comment "{}"'.format(node.prompt[0]))
match = True
if match:
print("location: {}:{}\n".format(node.filename, node.linenr))

View File

@ -0,0 +1 @@
../kconfiglib.py

View File

@ -0,0 +1,156 @@
# Prints a list of symbols that are referenced in the Kconfig files of some
# architecture but not defined by the Kconfig files of any architecture.
#
# A Kconfig file might be shared between many architectures and legitimately
# reference undefined symbols for some of them, but if no architecture defines
# the symbol, it usually indicates a problem or potential cleanup.
#
# This script could be sped up a lot if needed. See the comment near the
# referencing_nodes() call.
#
# Run with the following command in the kernel root:
#
# $ python(3) Kconfiglib/examples/list_undefined.py
#
# Example output:
#
# Registering defined and undefined symbols for all arches
# Processing mips
# Processing ia64
# Processing metag
# ...
#
# Finding references to each undefined symbol
# Processing mips
# Processing ia64
# Processing metag
# ...
#
# The following globally undefined symbols were found, listed here
# together with the locations of the items that reference them.
# References might come from enclosing menus and ifs.
#
# ARM_ERRATA_753970: arch/arm/mach-mvebu/Kconfig:56, arch/arm/mach-mvebu/Kconfig:39
# SUNXI_CCU_MP: drivers/clk/sunxi-ng/Kconfig:14
# SUNXI_CCU_DIV: drivers/clk/sunxi-ng/Kconfig:14
# AC97: sound/ac97/Kconfig:6
# ...
import os
import subprocess
from kconfiglib import Kconfig
# Referenced inside the Kconfig files
os.environ["KERNELVERSION"] = str(
subprocess.check_output(("make", "kernelversion")).decode("utf-8").rstrip()
)
def all_arch_srcarch_pairs():
"""
Generates all valid (ARCH, SRCARCH) tuples for the kernel, corresponding to
different architectures. SRCARCH holds the arch/ subdirectory.
"""
for srcarch in os.listdir("arch"):
# Each subdirectory of arch/ containing a Kconfig file corresponds to
# an architecture
if os.path.exists(os.path.join("arch", srcarch, "Kconfig")):
yield (srcarch, srcarch)
# Some architectures define additional ARCH settings with ARCH != SRCARCH
# (search for "Additional ARCH settings for" in the top-level Makefile)
yield ("i386", "x86")
yield ("x86_64", "x86")
yield ("sparc32", "sparc")
yield ("sparc64", "sparc")
yield ("sh64", "sh")
yield ("um", "um")
def all_arch_srcarch_kconfigs():
"""
Generates Kconfig instances for all the architectures in the kernel
"""
os.environ["srctree"] = "."
os.environ["HOSTCC"] = "gcc"
os.environ["HOSTCXX"] = "g++"
os.environ["CC"] = "gcc"
os.environ["LD"] = "ld"
for arch, srcarch in all_arch_srcarch_pairs():
print(" Processing " + arch)
os.environ["ARCH"] = arch
os.environ["SRCARCH"] = srcarch
# um (User Mode Linux) uses a different base Kconfig file
yield Kconfig("Kconfig" if arch != "um" else "arch/x86/um/Kconfig",
warn=False)
print("Registering defined and undefined symbols for all arches")
# Sets holding the names of all defined and undefined symbols, for all
# architectures
defined = set()
undefined = set()
for kconf in all_arch_srcarch_kconfigs():
for name, sym in kconf.syms.items():
if sym.nodes:
# If the symbol has a menu node, it is defined
defined.add(name)
else:
# Undefined symbol. We skip some of the uninteresting ones.
# Due to how Kconfig works, integer literals show up as symbols
# (from e.g. 'default 1'). Skip those.
try:
int(name, 0)
continue
except ValueError:
# Interesting undefined symbol
undefined.add(name)
print("\nFinding references to each undefined symbol")
def referencing_nodes(kconf, name):
# Returns a list of all menu nodes that reference a symbol named 'name' in
# any of their properties or property conditions
res = []
for node in kconf.node_iter():
for ref in node.referenced:
if ref.name == name:
res.append(node)
return res
# Maps each globally undefined symbol to the menu nodes that reference it
undef_sym_refs = [(name, set()) for name in undefined - defined]
for kconf in all_arch_srcarch_kconfigs():
for name, refs in undef_sym_refs:
# This means that we search the entire configuration tree for each
# undefined symbol, which is terribly inefficient. We could speed
# things up by tweaking referencing_nodes() to compare each symbol to
# multiple symbols while walking the configuration tree.
for node in referencing_nodes(kconf, name):
refs.add("{}:{}".format(node.filename, node.linenr))
print("\nThe following globally undefined symbols were found, listed here\n"
"together with the locations of the items that reference them.\n"
"References might come from enclosing menus and ifs.\n")
for name, refs in undef_sym_refs:
print(" {}: {}".format(name, ", ".join(refs)))

View File

@ -0,0 +1,341 @@
#!/usr/bin/env python3
# Implements a simple configuration interface on top of Kconfiglib to
# demonstrate concepts for building a menuconfig-like. Emulates how the
# standard menuconfig prints menu entries.
#
# Always displays the entire Kconfig tree to keep things as simple as possible
# (all symbols, choices, menus, and comments).
#
# Usage:
#
# $ python(3) Kconfiglib/examples/menuconfig.py <Kconfig file>
#
# A sample Kconfig is available in Kconfiglib/examples/Kmenuconfig.
#
# Here's a notation guide. The notation matches the one used by menuconfig
# (scripts/kconfig/mconf):
#
# [ ] prompt - Bool
# < > prompt - Tristate
# {M} prompt - Tristate selected to m. Can only be set to m or y.
# -*- prompt - Bool/tristate selected to y, pinning it
# -M- prompt - Tristate selected to m that also has m visibility,
# pinning it to m
# (foo) prompt - String/int/hex symbol with value "foo"
# --> prompt - The selected symbol in a choice in y mode. This
# syntax is unique to this example.
#
# When modules are disabled, the .type attribute of TRISTATE symbols and
# choices automatically changes to BOOL. This trick is used by the C
# implementation as well, and gives the expected behavior without having to do
# anything extra here. The original type is available in .orig_type if needed.
#
# The Kconfiglib/examples/Kmenuconfig example uses named choices to be able to
# refer to choices by name. Named choices are supported in the C tools too, but
# I don't think I've ever seen them used in the wild.
#
# Sample session:
#
# $ python Kconfiglib/examples/menuconfig.py Kconfiglib/examples/Kmenuconfig
#
# ======== Example Kconfig configuration ========
#
# [*] Enable loadable module support (MODULES)
# Bool and tristate symbols
# [*] Bool symbol (BOOL)
# [ ] Dependent bool symbol (BOOL_DEP)
# < > Dependent tristate symbol (TRI_DEP)
# [ ] First prompt (TWO_MENU_NODES)
# < > Tristate symbol (TRI)
# [ ] Second prompt (TWO_MENU_NODES)
# *** These are selected by TRI_DEP ***
# < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP)
# < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP)
# String, int, and hex symbols
# (foo) String symbol (STRING)
# (747) Int symbol (INT)
# (0xABC) Hex symbol (HEX)
# Various choices
# -*- Bool choice (BOOL_CHOICE)
# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1)
# Bool choice sym 2 (BOOL_CHOICE_SYM_2)
# {M} Tristate choice (TRI_CHOICE)
# < > Tristate choice sym 1 (TRI_CHOICE_SYM_1)
# < > Tristate choice sym 2 (TRI_CHOICE_SYM_2)
# [ ] Optional bool choice (OPT_BOOL_CHOICE)
#
# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): BOOL
# Value for BOOL (available: n, y): n
#
# ======== Example Kconfig configuration ========
#
# [*] Enable loadable module support (MODULES)
# Bool and tristate symbols
# [ ] Bool symbol (BOOL)
# < > Tristate symbol (TRI)
# [ ] Second prompt (TWO_MENU_NODES)
# *** These are selected by TRI_DEP ***
# < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP)
# < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP)
# String, int, and hex symbols
# (foo) String symbol (STRING)
# (747) Int symbol (INT)
# (0xABC) Hex symbol (HEX)
# Various choices
# -*- Bool choice (BOOL_CHOICE)
# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1)
# Bool choice sym 2 (BOOL_CHOICE_SYM_2)
# {M} Tristate choice (TRI_CHOICE)
# < > Tristate choice sym 1 (TRI_CHOICE_SYM_1)
# < > Tristate choice sym 2 (TRI_CHOICE_SYM_2)
# [ ] Optional bool choice (OPT_BOOL_CHOICE)
#
# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): MODULES
# Value for MODULES (available: n, y): n
#
# ======== Example Kconfig configuration ========
#
# [ ] Enable loadable module support (MODULES)
# Bool and tristate symbols
# [ ] Bool symbol (BOOL)
# [ ] Tristate symbol (TRI)
# [ ] Second prompt (TWO_MENU_NODES)
# *** These are selected by TRI_DEP ***
# [ ] Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP)
# [ ] Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP)
# String, int, and hex symbols
# (foo) String symbol (STRING)
# (747) Int symbol (INT)
# (0xABC) Hex symbol (HEX)
# Various choices
# -*- Bool choice (BOOL_CHOICE)
# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1)
# Bool choice sym 2 (BOOL_CHOICE_SYM_2)
# -*- Tristate choice (TRI_CHOICE)
# --> Tristate choice sym 1 (TRI_CHOICE_SYM_1)
# Tristate choice sym 2 (TRI_CHOICE_SYM_2)
# [ ] Optional bool choice (OPT_BOOL_CHOICE)
#
# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): ^D
from __future__ import print_function
import readline
import sys
from kconfiglib import Kconfig, \
Symbol, MENU, COMMENT, \
BOOL, TRISTATE, STRING, INT, HEX, UNKNOWN, \
expr_value, \
TRI_TO_STR
# Python 2/3 compatibility hack
if sys.version_info[0] < 3:
input = raw_input
def indent_print(s, indent):
print(indent*" " + s)
def value_str(sc):
"""
Returns the value part ("[*]", "<M>", "(foo)" etc.) of a menu entry.
sc: Symbol or Choice.
"""
if sc.type in (STRING, INT, HEX):
return "({})".format(sc.str_value)
# BOOL or TRISTATE
# The choice mode is an upper bound on the visibility of choice symbols, so
# we can check the choice symbols' own visibility to see if the choice is
# in y mode
if isinstance(sc, Symbol) and sc.choice and sc.visibility == 2:
# For choices in y mode, print '-->' next to the selected symbol
return "-->" if sc.choice.selection is sc else " "
tri_val_str = (" ", "M", "*")[sc.tri_value]
if len(sc.assignable) == 1:
# Pinned to a single value
return "-{}-".format(tri_val_str)
if sc.type == BOOL:
return "[{}]".format(tri_val_str)
if sc.type == TRISTATE:
if sc.assignable == (1, 2):
# m and y available
return "{" + tri_val_str + "}" # Gets a bit confusing with .format()
return "<{}>".format(tri_val_str)
def node_str(node):
"""
Returns the complete menu entry text for a menu node, or "" for invisible
menu nodes. Invisible menu nodes are those that lack a prompt or that do
not have a satisfied prompt condition.
Example return value: "[*] Bool symbol (BOOL)"
The symbol name is printed in parentheses to the right of the prompt. This
is so that symbols can easily be referred to in the configuration
interface.
"""
if not node.prompt:
return ""
# Even for menu nodes for symbols and choices, it's wrong to check
# Symbol.visibility / Choice.visibility here. The reason is that a symbol
# (and a choice, in theory) can be defined in multiple locations, giving it
# multiple menu nodes, which do not necessarily all have the same prompt
# visibility. Symbol.visibility / Choice.visibility is calculated as the OR
# of the visibility of all the prompts.
prompt, prompt_cond = node.prompt
if not expr_value(prompt_cond):
return ""
if node.item == MENU:
return " " + prompt
if node.item == COMMENT:
return " *** {} ***".format(prompt)
# Symbol or Choice
sc = node.item
if sc.type == UNKNOWN:
# Skip symbols defined without a type (these are obscure and generate
# a warning)
return ""
# {:3} sets the field width to three. Gives nice alignment for empty string
# values.
res = "{:3} {}".format(value_str(sc), prompt)
# Don't print the name for unnamed choices (the normal kind)
if sc.name is not None:
res += " ({})".format(sc.name)
return res
def print_menuconfig_nodes(node, indent):
"""
Prints a tree with all the menu entries rooted at 'node'. Child menu
entries are indented.
"""
while node:
string = node_str(node)
if string:
indent_print(string, indent)
if node.list:
print_menuconfig_nodes(node.list, indent + 8)
node = node.next
def print_menuconfig(kconf):
"""
Prints all menu entries for the configuration.
"""
# Print the expanded mainmenu text at the top. This is the same as
# kconf.top_node.prompt[0], but with variable references expanded.
print("\n======== {} ========\n".format(kconf.mainmenu_text))
print_menuconfig_nodes(kconf.top_node.list, 0)
print("")
def get_value_from_user(sc):
"""
Prompts the user for a value for the symbol or choice 'sc'. For
bool/tristate symbols and choices, provides a list of all the assignable
values.
"""
if not sc.visibility:
print(sc.name + " is not currently visible")
return False
prompt = "Value for {}".format(sc.name)
if sc.type in (BOOL, TRISTATE):
prompt += " (available: {})" \
.format(", ".join(TRI_TO_STR[val] for val in sc.assignable))
prompt += ": "
val = input(prompt)
# Automatically add a "0x" prefix for hex symbols, like the menuconfig
# interface does. This isn't done when loading .config files, hence why
# set_value() doesn't do it automatically.
if sc.type == HEX and not val.startswith(("0x", "0X")):
val = "0x" + val
# Let Kconfiglib itself print a warning here if the value is invalid. We
# could also disable warnings temporarily with 'kconf.warn = False' and
# print our own warning.
return sc.set_value(val)
if __name__ == "__main__":
if len(sys.argv) != 2:
sys.exit("usage: menuconfig.py <Kconfig file>")
# Load Kconfig configuration files
kconf = Kconfig(sys.argv[1])
# Print the initial configuration tree
print_menuconfig(kconf)
while True:
try:
cmd = input('Enter a symbol/choice name, "load_config", or '
'"write_config" (or press CTRL+D to exit): ').strip()
except EOFError:
print("")
break
if cmd == "load_config":
config_filename = input(".config file to load: ")
try:
# Returns a message telling which file got loaded
print(kconf.load_config(config_filename))
except EnvironmentError as e:
print(e, file=sys.stderr)
print_menuconfig(kconf)
continue
if cmd == "write_config":
config_filename = input("To this file: ")
try:
# Returns a message telling which file got saved
print(kconf.write_config(config_filename))
except EnvironmentError as e:
print(e, file=sys.stderr)
continue
# Assume 'cmd' is the name of a symbol or choice if it isn't one of the
# commands above, prompt the user for a value for it, and print the new
# configuration tree
if cmd in kconf.syms:
if get_value_from_user(kconf.syms[cmd]):
print_menuconfig(kconf)
continue
if cmd in kconf.named_choices:
if get_value_from_user(kconf.named_choices[cmd]):
print_menuconfig(kconf)
continue
print("No symbol/choice named '{}' in the configuration".format(cmd),
file=sys.stderr)

View File

@ -0,0 +1,121 @@
#!/usr/bin/env python3
# This script functions similarly to scripts/kconfig/merge_config.sh from the
# kernel tree, merging multiple configurations fragments to produce a complete
# .config, with unspecified values filled in as for alldefconfig.
#
# The generated .config respects symbol dependencies, and a warning is printed
# if any symbol gets a different value from the assigned value.
#
# For a real-world merging example based on this script, see
# https://github.com/zephyrproject-rtos/zephyr/blob/master/scripts/kconfig/kconfig.py.
#
# Here's a demo:
#
# Kconfig contents:
#
# config FOO
# bool "FOO"
#
# config BAR
# bool "BAR"
#
# config BAZ
# string "BAZ"
#
# config QAZ
# bool "QAZ" if n
#
#
# conf1 contents:
#
# CONFIG_FOO=y
#
#
# conf2 contents:
#
# CONFIG_BAR=y
#
#
# conf3 contents:
#
# # Assigned twice (would generate warning if 'warn_assign_override' was
# # True)
# # CONFIG_FOO is not set
#
# # Ops... this symbol doesn't exist
# CONFIG_OPS=y
#
# CONFIG_BAZ="baz string"
#
#
# conf4 contents:
#
# CONFIG_QAZ=y
#
#
# Running:
#
# $ python(3) merge_config.py Kconfig merged conf1 conf2 conf3 conf4
# Merged configuration 'conf1'
# Merged configuration 'conf2'
# conf3:5: warning: attempt to assign the value 'y' to the undefined symbol OPS
# Merged configuration 'conf3'
# Merged configuration 'conf4'
# Configuration saved to 'merged'
# warning: QAZ (defined at Kconfig:10) was assigned the value 'y' but got the value 'n' -- check dependencies
# $ cat merged
# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)
# # CONFIG_FOO is not set
# CONFIG_BAR=y
# CONFIG_BAZ="baz string"
from __future__ import print_function
import sys
from kconfiglib import Kconfig, BOOL, TRISTATE, TRI_TO_STR
if len(sys.argv) < 4:
sys.exit("usage: merge_config.py Kconfig merged_config config1 [config2 ...]")
kconf = Kconfig(sys.argv[1], suppress_traceback=True)
# Enable warnings for assignments to undefined symbols
kconf.warn_assign_undef = True
# (This script uses alldefconfig as the base. Other starting states could be
# set up here as well. The approach in examples/allnoconfig_simpler.py could
# provide an allnoconfig starting state for example.)
# Disable warnings generated for multiple assignments to the same symbol within
# a (set of) configuration files. Assigning a symbol multiple times might be
# done intentionally when merging configuration files.
kconf.warn_assign_override = False
kconf.warn_assign_redun = False
# Create a merged configuration by loading the fragments with replace=False.
# load_config() and write_config() returns a message to print.
for config in sys.argv[3:]:
print(kconf.load_config(config, replace=False))
# Write the merged configuration
print(kconf.write_config(sys.argv[2]))
# Print warnings for symbols whose actual value doesn't match the assigned
# value
for sym in kconf.defined_syms:
# Was the symbol assigned to?
if sym.user_value is not None:
# Tristate values are represented as 0, 1, 2. Having them as
# "n", "m", "y" is more convenient here, so convert.
if sym.type in (BOOL, TRISTATE):
user_value = TRI_TO_STR[sym.user_value]
else:
user_value = sym.user_value
if user_value != sym.str_value:
print("warning: {} was assigned the value '{}' but got the "
"value '{}' -- check dependencies".format(
sym.name_and_loc, user_value, sym.str_value),
file=sys.stderr)

View File

@ -0,0 +1,199 @@
# Prints menu entries as a tree with its value in the .config file. This can be
# handy e.g. for diffing between different .config files or versions of Kconfig files.
#
# Usage:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=print_config_tree.py [SCRIPT_ARG=<.config>]
#
# If the variable WITH_HELP_DESC is modified to 'True', the help is added
# to the symbols.
#
# Here's a notation guide. The notation matches the one used by menuconfig
# (scripts/kconfig/mconf):
#
# [ ] prompt - Bool
# < > prompt - Tristate
# {M} prompt - Tristate selected to m. Can only be set to m or y.
# -*- prompt - Bool/tristate selected to y, pinning it
# -M- prompt - Tristate selected to m that also has m visibility,
# pinning it to m
# (foo) prompt - String/int/hex symbol with value "foo"
# --> prompt - The selected symbol in a choice in y mode. This
# syntax is unique to this example.
#
# When modules are disabled, the .type attribute of TRISTATE symbols and
# choices automatically changes to BOOL. This trick is used by the C
# implementation as well, and gives the expected behavior without having to do
# anything extra here. The original type is available in .orig_type if needed.
#
# Example output:
#
# $ make scriptconfig SCRIPT=Kconfiglib/examples/print_config_tree.py [SCRIPT_ARG=<.config file>]
#
# ======== Linux/x86 4.9.82 Kernel Configuration ========
#
# [*] 64-bit kernel (64BIT)
# General setup
# () Cross-compiler tool prefix (CROSS_COMPILE)
# [ ] Compile also drivers which will not load (COMPILE_TEST)
# () Local version - append to kernel release (LOCALVERSION)
# [*] Automatically append version information to the version string (LOCALVERSION_AUTO)
# -*- Kernel compression mode
# ...
#
# With the variable WITH_HELP_DESC modified to 'True':
#
# ======== Linux/x86 4.9.82 Kernel Configuration ========
#
# [*] 64-bit kernel - Say yes to build a 64-bit kernel - formerly known as x86_64 Say no to build a 32-bit kernel - formerly known as i386 (64BIT)
# General setup
# () Cross-compiler tool prefix - Same as running 'make CROSS_COMPILE=prefix-' but stored for default make runs in this kernel build directory. You don't need to set this unless you want the configured kernel build directory to select the cross-compiler automatically. (CROSS_COMPILE)
# [ ] Compile also drivers which will not load - Some drivers can be compiled on a different platform than they are intended to be run on. Despite they cannot be loaded there (or even when they load they cannot be used due to missing HW support), developers still, opposing to distributors, might want to build such drivers to compile-test them. If you are a developer and want to build everything available, say Y here. If you are a user/distributor, say N here to exclude useless drivers to be distributed. (COMPILE_TEST)
# ...
import sys
from kconfiglib import Kconfig, \
Symbol, MENU, COMMENT, \
BOOL, TRISTATE, STRING, INT, HEX, UNKNOWN, \
expr_value
# Add help description to output
WITH_HELP_DESC = False
def indent_print(s, indent):
print(indent*" " + s)
def value_str(sc):
"""
Returns the value part ("[*]", "<M>", "(foo)" etc.) of a menu entry.
sc: Symbol or Choice.
"""
if sc.type in (STRING, INT, HEX):
return "({})".format(sc.str_value)
# BOOL or TRISTATE
# The choice mode is an upper bound on the visibility of choice symbols, so
# we can check the choice symbols' own visibility to see if the choice is
# in y mode
if isinstance(sc, Symbol) and sc.choice and sc.visibility == 2:
# For choices in y mode, print '-->' next to the selected symbol
return "-->" if sc.choice.selection is sc else " "
tri_val_str = (" ", "M", "*")[sc.tri_value]
if len(sc.assignable) == 1:
# Pinned to a single value
return "-{}-".format(tri_val_str)
if sc.type == BOOL:
return "[{}]".format(tri_val_str)
if sc.type == TRISTATE:
if sc.assignable == (1, 2):
# m and y available
return "{" + tri_val_str + "}" # Gets a bit confusing with .format()
return "<{}>".format(tri_val_str)
def node_str(node):
"""
Returns the complete menu entry text for a menu node, or "" for invisible
menu nodes. Invisible menu nodes are those that lack a prompt or that do
not have a satisfied prompt condition.
Example return value: "[*] Bool symbol (BOOL)"
The symbol name is printed in parentheses to the right of the prompt.
"""
if not node.prompt:
return ""
# Even for menu nodes for symbols and choices, it's wrong to check
# Symbol.visibility / Choice.visibility here. The reason is that a symbol
# (and a choice, in theory) can be defined in multiple locations, giving it
# multiple menu nodes, which do not necessarily all have the same prompt
# visibility. Symbol.visibility / Choice.visibility is calculated as the OR
# of the visibility of all the prompts.
prompt, prompt_cond = node.prompt
if not expr_value(prompt_cond):
return ""
if node.item == MENU:
return " " + prompt
if node.item == COMMENT:
return " *** {} ***".format(prompt)
# Symbol or Choice
sc = node.item
if sc.type == UNKNOWN:
# Skip symbols defined without a type (these are obscure and generate
# a warning)
return ""
# Add help text
if WITH_HELP_DESC:
prompt += ' - ' + str(node.help).replace('\n', ' ').replace('\r', '')
# {:3} sets the field width to three. Gives nice alignment for empty string
# values.
res = "{:3} {}".format(value_str(sc), prompt)
# Don't print the name for unnamed choices (the normal kind)
if sc.name is not None:
res += " ({})".format(sc.name)
return res
def print_menuconfig_nodes(node, indent):
"""
Prints a tree with all the menu entries rooted at 'node'. Child menu
entries are indented.
"""
while node:
string = node_str(node)
if string:
indent_print(string, indent)
if node.list:
print_menuconfig_nodes(node.list, indent + 8)
node = node.next
def print_menuconfig(kconf):
"""
Prints all menu entries for the configuration.
"""
# Print the expanded mainmenu text at the top. This is the same as
# kconf.top_node.prompt[0], but with variable references expanded.
print("\n======== {} ========\n".format(kconf.mainmenu_text))
print_menuconfig_nodes(kconf.top_node.list, 0)
print("")
if __name__ == "__main__":
# Load Kconfig configuration files
kconf = Kconfig(sys.argv[1])
# Set default .config file or load it from argv
if len(sys.argv) == 2:
config_filename = '.config'
else:
config_filename = sys.argv[2]
kconf.load_config(config_filename)
# Print the configuration tree
print_menuconfig(kconf)

View File

@ -0,0 +1,54 @@
# Loads a Kconfig and a .config and prints a symbol.
#
# Usage:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/print_sym_info.py SCRIPT_ARG=<name>
#
# Example output for SCRIPT_ARG=MODULES:
#
# menuconfig MODULES
# bool
# prompt "Enable loadable module support"
# option modules
# help
# Kernel modules are small pieces of compiled code which can
# be inserted in the running kernel, rather than being
# permanently built into the kernel. You use the "modprobe"
# tool to add (and sometimes remove) them. If you say Y here,
# many parts of the kernel can be built as modules (by
# answering M instead of Y where indicated): this is most
# useful for infrequently used options which are not required
# for booting. For more information, see the man pages for
# modprobe, lsmod, modinfo, insmod and rmmod.
#
# If you say Y here, you will need to run "make
# modules_install" to put the modules under /lib/modules/
# where modprobe can find them (you may need to be root to do
# this).
#
# If unsure, say Y.
#
# value = n
# visibility = y
# currently assignable values: n, y
# defined at init/Kconfig:1674
import sys
from kconfiglib import Kconfig, TRI_TO_STR
if len(sys.argv) < 3:
sys.exit('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=<name>')
kconf = Kconfig(sys.argv[1])
sym = kconf.syms[sys.argv[2]]
print(sym)
print("value = " + sym.str_value)
print("visibility = " + TRI_TO_STR[sym.visibility])
print("currently assignable values: " +
", ".join([TRI_TO_STR[v] for v in sym.assignable]))
for node in sym.nodes:
print("defined at {}:{}".format(node.filename, node.linenr))

View File

@ -0,0 +1,75 @@
# Prints the menu tree of the configuration. Dependencies between symbols can
# sometimes implicitly alter the menu structure (see kconfig-language.txt), and
# that's implemented too.
#
# Note: See the Kconfig.node_iter() function as well, which provides a simpler
# interface for walking the menu tree.
#
# Usage:
#
# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py
#
# Example output:
#
# ...
# config HAVE_KERNEL_LZO
# config HAVE_KERNEL_LZ4
# choice
# config KERNEL_GZIP
# config KERNEL_BZIP2
# config KERNEL_LZMA
# config KERNEL_XZ
# config KERNEL_LZO
# config KERNEL_LZ4
# config DEFAULT_HOSTNAME
# config SWAP
# config SYSVIPC
# config SYSVIPC_SYSCTL
# config POSIX_MQUEUE
# config POSIX_MQUEUE_SYSCTL
# config CROSS_MEMORY_ATTACH
# config FHANDLE
# config USELIB
# config AUDIT
# config HAVE_ARCH_AUDITSYSCALL
# config AUDITSYSCALL
# config AUDIT_WATCH
# config AUDIT_TREE
# menu "IRQ subsystem"
# config MAY_HAVE_SPARSE_IRQ
# config GENERIC_IRQ_LEGACY
# config GENERIC_IRQ_PROBE
# ...
import sys
from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT
def indent_print(s, indent):
print(indent*" " + s)
def print_items(node, indent):
while node:
if isinstance(node.item, Symbol):
indent_print("config " + node.item.name, indent)
elif isinstance(node.item, Choice):
indent_print("choice", indent)
elif node.item == MENU:
indent_print('menu "{}"'.format(node.prompt[0]), indent)
elif node.item == COMMENT:
indent_print('comment "{}"'.format(node.prompt[0]), indent)
if node.list:
print_items(node.list, indent + 2)
node = node.next
kconf = Kconfig(sys.argv[1])
print_items(kconf.top_node, 0)

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Generates a header file with #defines from the configuration, matching the
format of include/generated/autoconf.h in the Linux kernel.
Optionally, also writes the configuration output as a .config file. See
--config-out.
The --sync-deps, --file-list, and --env-list options generate information that
can be used to avoid needless rebuilds/reconfigurations.
Before writing a header or configuration file, Kconfiglib compares the old
contents of the file against the new contents. If there's no change, the write
is skipped. This avoids updating file metadata like the modification time, and
might save work depending on your build setup.
By default, the configuration is generated from '.config'. A different
configuration file can be passed in the KCONFIG_CONFIG environment variable.
A custom header string can be inserted at the beginning of generated
configuration and header files by setting the KCONFIG_CONFIG_HEADER and
KCONFIG_AUTOHEADER_HEADER environment variables, respectively (this also works
for other scripts). The string is not automatically made a comment (this is by
design, to allow anything to be added), and no trailing newline is added, so
add '/* */', '#', and newlines as appropriate.
See https://www.gnu.org/software/make/manual/make.html#Multi_002dLine for a
handy way to define multi-line variables in makefiles, for use with custom
headers. Remember to export the variable to the environment.
"""
import argparse
import os
import sys
import kconfiglib
DEFAULT_SYNC_DEPS_PATH = "deps/"
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--header-path",
metavar="HEADER_FILE",
help="""
Path to write the generated header file to. If not specified, the path in the
environment variable KCONFIG_AUTOHEADER is used if it is set, and 'config.h'
otherwise.
""")
parser.add_argument(
"--config-out",
metavar="CONFIG_FILE",
help="""
Write the configuration to CONFIG_FILE. This is useful if you include .config
files in Makefiles, as the generated configuration file will be a full .config
file even if .config is outdated. The generated configuration matches what
olddefconfig would produce. If you use sync-deps, you can include
deps/auto.conf instead. --config-out is meant for cases where incremental build
information isn't needed.
""")
parser.add_argument(
"--sync-deps",
metavar="OUTPUT_DIR",
nargs="?",
const=DEFAULT_SYNC_DEPS_PATH,
help="""
Enable generation of symbol dependency information for incremental builds,
optionally specifying the output directory (default: {}). See the docstring of
Kconfig.sync_deps() in Kconfiglib for more information.
""".format(DEFAULT_SYNC_DEPS_PATH))
parser.add_argument(
"--file-list",
metavar="OUTPUT_FILE",
help="""
Write a list of all Kconfig files to OUTPUT_FILE, with one file per line. The
paths are relative to $srctree (or to the current directory if $srctree is
unset). Files appear in the order they're 'source'd.
""")
parser.add_argument(
"--env-list",
metavar="OUTPUT_FILE",
help="""
Write a list of all environment variables referenced in Kconfig files to
OUTPUT_FILE, with one variable per line. Each line has the format NAME=VALUE.
Only environment variables referenced with the preprocessor $(VAR) syntax are
included, and not variables referenced with the older $VAR syntax (which is
only supported for backwards compatibility).
""")
parser.add_argument(
"kconfig",
metavar="KCONFIG",
nargs="?",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
kconf.load_config()
if args.header_path is None:
if "KCONFIG_AUTOHEADER" in os.environ:
kconf.write_autoconf()
else:
# Kconfiglib defaults to include/generated/autoconf.h to be
# compatible with the C tools. 'config.h' is used here instead for
# backwards compatibility. It's probably a saner default for tools
# as well.
kconf.write_autoconf("config.h")
else:
kconf.write_autoconf(args.header_path)
if args.config_out is not None:
kconf.write_config(args.config_out, save_old=False)
if args.sync_deps is not None:
kconf.sync_deps(args.sync_deps)
if args.file_list is not None:
with _open_write(args.file_list) as f:
for path in kconf.kconfig_filenames:
f.write(path + "\n")
if args.env_list is not None:
with _open_write(args.env_list) as f:
for env_var in kconf.env_vars:
f.write("{}={}\n".format(env_var, os.environ[env_var]))
def _open_write(path):
# Python 2/3 compatibility. io.open() is available on both, but makes
# write() expect 'unicode' strings on Python 2.
if sys.version_info[0] < 3:
return open(path, "w")
return open(path, "w", encoding="utf-8")
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Lists all user-modifiable symbols that are not given a value in the
configuration file. Usually, these are new symbols that have been added to the
Kconfig files.
The default configuration filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
"""
from __future__ import print_function
import argparse
import sys
from kconfiglib import Kconfig, BOOL, TRISTATE, INT, HEX, STRING, TRI_TO_STR
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--show-help", "-l",
action="store_true",
help="Show any help texts as well")
parser.add_argument(
"kconfig",
metavar="KCONFIG",
nargs="?",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
args = parser.parse_args()
kconf = Kconfig(args.kconfig, suppress_traceback=True)
# Make it possible to filter this message out
print(kconf.load_config(), file=sys.stderr)
for sym in kconf.unique_defined_syms:
# Only show symbols that can be toggled. Choice symbols are a special
# case in that sym.assignable will be (2,) (length 1) for visible
# symbols in choices in y mode, but they can still be toggled by
# selecting some other symbol.
if sym.user_value is None and \
(len(sym.assignable) > 1 or
(sym.visibility and (sym.orig_type in (INT, HEX, STRING) or
sym.choice))):
# Don't reuse the 'config_string' format for bool/tristate symbols,
# to show n-valued symbols as 'CONFIG_FOO=n' instead of
# '# CONFIG_FOO is not set'. This matches the C tools.
if sym.orig_type in (BOOL, TRISTATE):
s = "{}{}={}\n".format(kconf.config_prefix, sym.name,
TRI_TO_STR[sym.tri_value])
else:
s = sym.config_string
print(s, end="")
if args.show_help:
for node in sym.nodes:
if node.help is not None:
# Indent by two spaces. textwrap.indent() is not
# available in Python 2 (it's 3.3+).
print("\n".join(" " + line
for line in node.help.split("\n")))
break
if __name__ == "__main__":
main()

View File

@ -0,0 +1,48 @@
From 93daf46f309b0c8f86149ef58c4906387d054c22 Mon Sep 17 00:00:00 2001
From: Ulf Magnusson <ulfalizer@gmail.com>
Date: Tue, 9 Jun 2015 13:01:34 +0200
Subject: [PATCH] Kconfiglib scripts/kconfig/Makefile patch
---
scripts/kconfig/Makefile | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 3f327e21f60e..8b7dd1292005 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -27,2 +27,31 @@ gconfig: $(obj)/gconf
+PHONY += scriptconfig iscriptconfig kmenuconfig guiconfig dumpvarsconfig
+
+PYTHONCMD ?= python
+kpython := PYTHONPATH=$(srctree)/Kconfiglib:$$PYTHONPATH $(PYTHONCMD)
+
+ifneq ($(filter scriptconfig,$(MAKECMDGOALS)),)
+ifndef SCRIPT
+$(error Use "make scriptconfig SCRIPT=<path to script> [SCRIPT_ARG=<argument>]")
+endif
+endif
+
+scriptconfig:
+ $(Q)$(kpython) $(SCRIPT) $(Kconfig) $(if $(SCRIPT_ARG),"$(SCRIPT_ARG)")
+
+iscriptconfig:
+ $(Q)$(kpython) -i -c \
+ "import kconfiglib; \
+ kconf = kconfiglib.Kconfig('$(Kconfig)'); \
+ print('A Kconfig instance \'kconf\' for the architecture $(ARCH) has been created.')"
+
+kmenuconfig:
+ $(Q)$(kpython) $(srctree)/Kconfiglib/menuconfig.py $(Kconfig)
+
+guiconfig:
+ $(Q)$(kpython) $(srctree)/Kconfiglib/guiconfig.py $(Kconfig)
+
+dumpvarsconfig:
+ $(Q)$(kpython) $(srctree)/Kconfiglib/examples/dumpvars.py $(Kconfig)
+
menuconfig: $(obj)/mconf
--
2.20.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,246 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Implements oldconfig functionality.
1. Loads existing .config
2. Prompts for the value of all modifiable symbols/choices that
aren't already set in the .config
3. Writes an updated .config
The default input/output filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
Entering '?' displays the help text of the symbol/choice, if any.
Unlike 'make oldconfig', this script doesn't print menu titles and comments,
but gives Kconfig definition locations. Printing menus and comments would be
pretty easy to add: Look at the parents of each item, and print all menu
prompts and comments unless they have already been printed (assuming you want
to skip "irrelevant" menus).
"""
from __future__ import print_function
import sys
from kconfiglib import Symbol, Choice, BOOL, TRISTATE, HEX, standard_kconfig
# Python 2/3 compatibility hack
if sys.version_info[0] < 3:
input = raw_input
def _main():
# Earlier symbols in Kconfig files might depend on later symbols and become
# visible if their values change. This flag is set to True if the value of
# any symbol changes, in which case we rerun the oldconfig to check for new
# visible symbols.
global conf_changed
kconf = standard_kconfig(__doc__)
print(kconf.load_config())
while True:
conf_changed = False
for node in kconf.node_iter():
oldconfig(node)
if not conf_changed:
break
print(kconf.write_config())
def oldconfig(node):
"""
Prompts the user for a value if node.item is a visible symbol/choice with
no user value.
"""
# See main()
global conf_changed
# Only symbols and choices can be configured
if not isinstance(node.item, (Symbol, Choice)):
return
# Skip symbols and choices that aren't visible
if not node.item.visibility:
return
# Skip symbols and choices that don't have a prompt (at this location)
if not node.prompt:
return
if isinstance(node.item, Symbol):
sym = node.item
# Skip symbols that already have a user value
if sym.user_value is not None:
return
# Skip symbols that can only have a single value, due to selects
if len(sym.assignable) == 1:
return
# Skip symbols in choices in y mode. We ask once for the entire choice
# instead.
if sym.choice and sym.choice.tri_value == 2:
return
# Loop until the user enters a valid value or enters a blank string
# (for the default value)
while True:
val = input("{} ({}) [{}] ".format(
node.prompt[0], _name_and_loc_str(sym),
_default_value_str(sym)))
if val == "?":
_print_help(node)
continue
# Substitute a blank string with the default value the symbol
# would get
if not val:
val = sym.str_value
# Automatically add a "0x" prefix for hex symbols, like the
# menuconfig interface does. This isn't done when loading .config
# files, hence why set_value() doesn't do it automatically.
if sym.type == HEX and not val.startswith(("0x", "0X")):
val = "0x" + val
old_str_val = sym.str_value
# Kconfiglib itself will print a warning here if the value
# is invalid, so we don't need to bother
if sym.set_value(val):
# Valid value input. We're done with this node.
if sym.str_value != old_str_val:
conf_changed = True
return
else:
choice = node.item
# Skip choices that already have a visible user selection...
if choice.user_selection and choice.user_selection.visibility == 2:
# ...unless there are new visible symbols in the choice. (We know
# they have y (2) visibility in that case, because m-visible
# symbols get demoted to n-visibility in y-mode choices, and the
# user-selected symbol had visibility y.)
for sym in choice.syms:
if sym is not choice.user_selection and sym.visibility and \
sym.user_value is None:
# New visible symbols in the choice
break
else:
# No new visible symbols in the choice
return
# Get a list of available selections. The mode of the choice limits
# the visibility of the choice value symbols, so this will indirectly
# skip choices in n and m mode.
options = [sym for sym in choice.syms if sym.visibility == 2]
if not options:
# No y-visible choice value symbols
return
# Loop until the user enters a valid selection or a blank string (for
# the default selection)
while True:
print("{} ({})".format(node.prompt[0], _name_and_loc_str(choice)))
for i, sym in enumerate(options, 1):
print("{} {}. {} ({})".format(
">" if sym is choice.selection else " ",
i,
# Assume people don't define choice symbols with multiple
# prompts. That generates a warning anyway.
sym.nodes[0].prompt[0],
sym.name))
sel_index = input("choice[1-{}]: ".format(len(options)))
if sel_index == "?":
_print_help(node)
continue
# Pick the default selection if the string is blank
if not sel_index:
choice.selection.set_value(2)
break
try:
sel_index = int(sel_index)
except ValueError:
print("Bad index", file=sys.stderr)
continue
if not 1 <= sel_index <= len(options):
print("Bad index", file=sys.stderr)
continue
# Valid selection
if options[sel_index - 1].tri_value != 2:
conf_changed = True
options[sel_index - 1].set_value(2)
break
# Give all of the non-selected visible choice symbols the user value n.
# This makes it so that the choice is no longer considered new once we
# do additional passes, if the reason that it was considered new was
# that it had new visible choice symbols.
#
# Only giving visible choice symbols the user value n means we will
# prompt for the choice again if later user selections make more new
# choice symbols visible, which is correct.
for sym in choice.syms:
if sym is not choice.user_selection and sym.visibility:
sym.set_value(0)
def _name_and_loc_str(sc):
# Helper for printing the name of the symbol/choice 'sc' along with the
# location(s) in the Kconfig files where it is defined. Unnamed choices
# return "choice" instead of the name.
return "{}, defined at {}".format(
sc.name or "choice",
", ".join("{}:{}".format(node.filename, node.linenr)
for node in sc.nodes))
def _print_help(node):
print("\n" + (node.help or "No help text\n"))
def _default_value_str(sym):
# Returns the "m/M/y" string in e.g.
#
# TRISTATE_SYM prompt (TRISTATE_SYM, defined at Kconfig:9) [n/M/y]:
#
# For string/int/hex, returns the default value as-is.
if sym.type in (BOOL, TRISTATE):
return "/".join(("NMY" if sym.tri_value == tri else "nmy")[tri]
for tri in sym.assignable)
# string/int/hex
return sym.str_value
if __name__ == "__main__":
_main()

View File

@ -0,0 +1,28 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Updates an old .config file or creates a new one, by filling in default values
for all new symbols. This is the same as picking the default selection for all
symbols in oldconfig, or entering the menuconfig interface and immediately
saving.
The default input/output filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
print(kconf.load_config())
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,49 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Saves a minimal configuration file that only lists symbols that differ in value
from their defaults. Loading such a configuration file is equivalent to loading
the "full" configuration file.
Minimal configuration files are handy to start from when editing configuration
files by hand.
The default input configuration file is '.config'. A different input filename
can be passed in the KCONFIG_CONFIG environment variable.
Note: Minimal configurations can also be generated from within the menuconfig
interface.
"""
import argparse
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"--out",
metavar="MINIMAL_CONFIGURATION",
default="defconfig",
help="Output filename for minimal configuration (default: defconfig)")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config())
print(kconf.write_min_config(args.out))
if __name__ == "__main__":
main()

View File

@ -0,0 +1,92 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Simple utility for setting configuration values from the command line.
Sample usage:
$ setconfig FOO_SUPPORT=y BAR_BITS=8
Note: Symbol names should not be prefixed with 'CONFIG_'.
The exit status on errors is 1.
The default input/output configuration file is '.config'. A different filename
can be passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
"""
import argparse
import sys
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"--no-check-exists",
dest="check_exists",
action="store_false",
help="Ignore assignments to non-existent symbols instead of erroring "
"out")
parser.add_argument(
"--no-check-value",
dest="check_value",
action="store_false",
help="Ignore assignments that didn't \"take\" (where the symbol got a "
"different value, e.g. due to unsatisfied dependencies) instead "
"of erroring out")
parser.add_argument(
"assignments",
metavar="ASSIGNMENT",
nargs="*",
help="A 'NAME=value' assignment")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config())
for arg in args.assignments:
if "=" not in arg:
sys.exit("error: no '=' in assignment: '{}'".format(arg))
name, value = arg.split("=", 1)
if name not in kconf.syms:
if not args.check_exists:
continue
sys.exit("error: no symbol '{}' in configuration".format(name))
sym = kconf.syms[name]
if not sym.set_value(value):
sys.exit("error: '{}' is an invalid value for the {} symbol {}"
.format(value, kconfiglib.TYPE_TO_STR[sym.orig_type],
name))
if args.check_value and sym.str_value != value:
sys.exit("error: {} was assigned the value '{}', but got the "
"value '{}'. Check the symbol's dependencies, and make "
"sure that it has a prompt."
.format(name, value, sym.str_value))
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,7 @@
[bdist_wheel]
# We support both Python 2 and Python 3
universal = 1
[metadata]
# Include the license file in wheels
license_file = LICENSE.txt

View File

@ -0,0 +1,96 @@
import io
import os
import setuptools
setuptools.setup(
name="kconfiglib",
# MAJOR.MINOR.PATCH, per http://semver.org
version="14.1.0",
description="A flexible Python Kconfig implementation",
# Make sure that README.rst decodes on Python 3 in environments that use
# the C locale (which implies ASCII), by explicitly giving the encoding.
#
# io.open() has the 'encoding' parameter on both Python 2 and 3. open()
# doesn't have it on Python 2. This lets us use the same code for both.
long_description=io.open(
os.path.join(os.path.dirname(__file__), "README.rst"),
encoding="utf-8"
).read(),
url="https://github.com/ulfalizer/Kconfiglib",
author='Ulf "Ulfalizer" Magnusson',
author_email="ulfalizer@gmail.com",
keywords="kconfig, kbuild, menuconfig, configuration-management",
license="ISC",
py_modules=(
"kconfiglib",
"menuconfig",
"guiconfig",
"genconfig",
"oldconfig",
"olddefconfig",
"savedefconfig",
"defconfig",
"alldefconfig",
"allnoconfig",
"allmodconfig",
"allyesconfig",
"listnewconfig",
"setconfig",
),
entry_points={
"console_scripts": (
"menuconfig = menuconfig:_main",
"guiconfig = guiconfig:_main",
"genconfig = genconfig:main",
"oldconfig = oldconfig:_main",
"olddefconfig = olddefconfig:main",
"savedefconfig = savedefconfig:main",
"defconfig = defconfig:main",
"alldefconfig = alldefconfig:main",
"allnoconfig = allnoconfig:main",
"allmodconfig = allmodconfig:main",
"allyesconfig = allyesconfig:main",
"listnewconfig = listnewconfig:main",
"setconfig = setconfig:main",
)
},
# Note: windows-curses is not automatically installed on Windows anymore,
# because it made Kconfiglib impossible to install on MSYS2 with pip
# Needs support for unnumbered {} in format() and argparse
python_requires=">=2.7,!=3.0.*,!=3.1.*",
project_urls={
"GitHub repository": "https://github.com/ulfalizer/Kconfiglib",
"Examples": "https://github.com/ulfalizer/Kconfiglib/tree/master/examples",
},
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"Topic :: System :: Operating System Kernels :: Linux",
"License :: OSI Approved :: ISC License (ISCL)",
"Operating System :: POSIX",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
)

View File

@ -0,0 +1,12 @@
config MODULES
def_bool y
config BOOL
bool "bool 1"
config STRING
string "string"
config IGNOREME
bool "ignore me"
default y

View File

@ -0,0 +1,230 @@
config MODULES
bool "modules"
option modules
# Things that should never be .assignable
if UNDEFINED && "const"
endif
config NO_PROMPT
bool
config STRING
string "string"
config INT
int "int"
config HEX
hex "hex"
# Non-selected symbols
config Y_VIS_BOOL
bool "y-vis bool"
config M_VIS_BOOL
bool "m-vis bool" if m
config N_VIS_BOOL
bool "n-vis bool" if n
config Y_VIS_TRI
tristate "y-vis tri"
config M_VIS_TRI
tristate "m-vis tri" if m
config N_VIS_TRI
tristate "n-vis tri" if n
# Symbols selected to y
config Y_SELECTOR
def_tristate y
select Y_SEL_Y_VIS_BOOL
select Y_SEL_M_VIS_BOOL
select Y_SEL_N_VIS_BOOL
select Y_SEL_Y_VIS_TRI
select Y_SEL_M_VIS_TRI
select Y_SEL_N_VIS_TRI
config Y_SEL_Y_VIS_BOOL
bool "y-sel y-vis bool"
config Y_SEL_M_VIS_BOOL
bool "y-sel m-vis bool" if m
config Y_SEL_N_VIS_BOOL
bool "y-sel n-vis bool" if n
config Y_SEL_Y_VIS_TRI
tristate "y-sel y-vis tri"
config Y_SEL_M_VIS_TRI
tristate "y-sel m-vis tri" if m
config Y_SEL_N_VIS_TRI
tristate "y-sel n-vis tri" if n
# Symbols selected to m
config M_SELECTOR
def_tristate m
select M_SEL_Y_VIS_BOOL
select M_SEL_M_VIS_BOOL
select M_SEL_N_VIS_BOOL
select M_SEL_Y_VIS_TRI
select M_SEL_M_VIS_TRI
select M_SEL_N_VIS_TRI
config M_SEL_Y_VIS_BOOL
bool "m-sel y-vis bool"
config M_SEL_M_VIS_BOOL
bool "m-sel m-vis bool" if m
config M_SEL_N_VIS_BOOL
bool "m-sel n-vis bool" if n
config M_SEL_Y_VIS_TRI
tristate "m-sel y-vis tri"
config M_SEL_M_VIS_TRI
tristate "m-sel m-vis tri" if m
config M_SEL_N_VIS_TRI
tristate "m-sel n-vis tri" if n
# Symbols implied to y
config Y_IMPLIER
def_tristate y
imply Y_IMP_Y_VIS_BOOL
imply Y_IMP_M_VIS_BOOL
imply Y_IMP_N_VIS_BOOL
imply Y_IMP_Y_VIS_TRI
imply Y_IMP_M_VIS_TRI
imply Y_IMP_N_VIS_TRI
config Y_IMP_Y_VIS_BOOL
bool "y-imp y-vis bool"
config Y_IMP_M_VIS_BOOL
bool "y-imp m-vis bool" if m
config Y_IMP_N_VIS_BOOL
bool "y-imp n-vis bool" if n
config Y_IMP_Y_VIS_TRI
tristate "y-imp y-vis tri"
config Y_IMP_M_VIS_TRI
tristate "y-imp m-vis tri" if m
config Y_IMP_N_VIS_TRI
tristate "y-imp n-vis tri" if n
# Symbols implied to m (never affects assignable values)
config M_IMPLIER
def_tristate m
imply M_IMP_Y_VIS_BOOL
imply M_IMP_M_VIS_BOOL
imply M_IMP_N_VIS_BOOL
imply M_IMP_Y_VIS_TRI
imply M_IMP_M_VIS_TRI
imply M_IMP_N_VIS_TRI
config M_IMP_Y_VIS_BOOL
bool "m-imp y-vis bool"
config M_IMP_M_VIS_BOOL
bool "m-imp m-vis bool" if m
config M_IMP_N_VIS_BOOL
bool "m-imp n-vis bool" if n
config M_IMP_Y_VIS_TRI
tristate "m-imp y-vis tri"
config M_IMP_M_VIS_TRI
tristate "m-imp m-vis tri" if m
config M_IMP_N_VIS_TRI
tristate "m-imp n-vis tri" if n
# Symbols in y-mode choice
choice Y_CHOICE
bool "y-mode choice"
config Y_CHOICE_BOOL
bool "y-mode choice bool"
config Y_CHOICE_TRISTATE
tristate "y-mode choice tristate"
config Y_CHOICE_N_VIS_TRISTATE
tristate "y-mode choice tristate invisible" if n
endchoice
# Symbols in m/y-mode choice
choice MY_CHOICE
tristate "m/y-mode choice"
config MY_CHOICE_BOOL
bool "m/y-mode choice bool"
config MY_CHOICE_TRISTATE
tristate "m/y-mode choice tristate"
config MY_CHOICE_N_VIS_TRISTATE
tristate "m/y-mode choice tristate invisible" if n
endchoice
# Choices with some other possible modes
choice NMY_CHOICE
tristate "n/m/y-mode choice"
optional
endchoice
choice NY_CHOICE
bool "n/y-mode choice"
optional
endchoice
choice NM_CHOICE
tristate "n/m-mode choice" if m
optional
endchoice
choice M_CHOICE
tristate "m-mode choice" if m
endchoice
choice N_CHOICE
tristate "n-mode choice" if n
endchoice

View File

@ -0,0 +1,198 @@
config MODULES
bool "modules"
# bool/tristate and optional
choice BOOL
bool "bool"
config B_1
tristate "B_1"
config B_2
tristate "B_2"
endchoice
choice BOOL_OPT
bool "bool optional"
optional
config BO_1
tristate "BO_1"
config BO_2
tristate "BO_2"
endchoice
choice TRISTATE
tristate "tristate"
config T_1
tristate "T_1"
config T_2
tristate "T_2"
endchoice
choice TRISTATE_OPT
tristate "tristate optional"
optional
config TO_1
tristate "TO_1"
config TO_2
tristate "TO_2"
endchoice
# m-visibility
choice BOOL_M
bool "bool m" if m
config BM_1
tristate "BM_1"
config BM_2
tristate "BM_2"
endchoice
choice TRISTATE_M
tristate "tristate m" if m
config TM_1
tristate "TM_1"
config TM_2
tristate "TM_2"
endchoice
# Defaults
config TRISTATE_SYM
tristate "tristate"
choice DEFAULTS
bool "defaults"
default OPT_1 if n
default OPT_2 if TRISTATE_SYM
default OPT_4
config OPT_1
tristate "OPT_1"
config OPT_2
tristate "OPT_2"
config OPT_3
tristate "OPT_3"
config OPT_4
tristate "OPT_4"
endchoice
choice DEFAULTS_NOT_VISIBLE
bool "defaults not visible"
# Skipped due to condition
default OPT_6 if n
# Skipped because OPT_7 is not visible
default OPT_7
# This one should apply
default OPT_8
config OPT_5
tristate "OPT_5"
config OPT_6
tristate "OPT_6"
config OPT_7
tristate "OPT_7" if n
config OPT_8
tristate "OPT_8"
config OPT_9
tristate "OPT_9"
endchoice
# Choices without an explicitly specified type should get the type of the first
# symbol with a type
choice NO_TYPE_BOOL
prompt "no type bool"
config NTB_1
bool "NTB_1"
config NTB_2
tristate "NTB_2"
endchoice
choice NO_TYPE_TRISTATE
prompt "no type tristate"
config NTT_1
config NTT_2
tristate "NTB_2"
config NTT_3
bool "NTT_3"
endchoice
# Choice items without an explicitly specified type should get the type of the
# choice
choice MISSING_MEMBER_TYPES_1
bool "missing member types"
config MMT_1
config MMT_2
config MMT_3
tristate
endchoice
choice MISSING_MEMBER_TYPES_2
config MMT_4
config MMT_5
bool
endchoice
# Choice where the default selection (the first symbol) depends on another
# symbol. If that symbol becomes 'n', the default selection should change to
# the first visible symbol in the choice.
choice DEFAULT_WITH_DEP
bool "default with dep"
config A
bool "A"
depends on DEP
config B
bool "B"
endchoice
config DEP
bool "dep"
# Choice with symbols that shouldn't be considered choice symbols because they
# depend on the preceding symbol. This might be a kconfig bug, but some things
# use it, so we need to emulate it.
choice WEIRD_SYMS
bool "weird symbols that aren't considered part of the choice"
# Only WS1 is part of the choice
config WS1
bool "WS1"
config WS2
bool "WS2"
depends on WS1
config WS3
bool
depends on WS2
config WS4
bool
depends on WS1
config WS5
bool "WS5" if WS1
# 'if' has the same effect, so only WS6 is part of the choice
config WS6
bool "WS6"
if WS6
config WS7
bool
config WS8
bool "WS8"
endif
# Should also be part of the choice
config WS9
bool "WS9"
endchoice

View File

@ -0,0 +1,8 @@
# $FOO is "defconfig_2"
config A
string
option defconfig_list
default "Kconfiglib/tests/defconfig_1" if y && !n && n
default "Kconfiglib/tests/$FOO"
default "Kconfiglib/tests/defconfig_1"

View File

@ -0,0 +1,10 @@
# $FOO is "defconfig_2"
# Should produce None due to the "depends on n"
config A
string
depends on n
option defconfig_list
default "Kconfiglib/tests/defconfig_1" if y && !n && n
default "Kconfiglib/tests/$FOO"
default "Kconfiglib/tests/defconfig_1"

View File

@ -0,0 +1,5 @@
config A
string
option defconfig_list
default "Kconfiglib/tests/non_existent_1"
default "Kconfiglib/tests/non_existent_2"

View File

@ -0,0 +1,5 @@
config A
string
option defconfig_list
default "sub/defconfig_in_sub" # Assume this doesn't exist
default "Kconfiglib/tests/defconfig_2"

View File

@ -0,0 +1,173 @@
# We verify that the properties below end up in definition order
config MULTIDEF
bool
default A
default B
select AA
imply AA
if FOO
config MULTIDEF
default C
default D
select BB
imply BB
if BAR
config MULTIDEF
default E
default F
select CC
imply CC
menu "menu"
config MULTIDEF
default G
default H
select DD
imply DD
config MULTIDEF
default I
default J
select EE
imply EE
endmenu
config MULTIDEF
default K
default L
select FF
imply FF
config MULTIDEF
default M
default N
select GG
imply GG
endif
config MULTIDEF
default O
default P
select HH
select II
imply HH
imply II
endif
config MULTIDEF
default Q
default R
select JJ
imply JJ
# Same test with choice symbols involved
config MULTIDEF_CHOICE
bool
select A
choice
bool "choice"
config MULTIDEF_CHOICE
bool "multidef choice"
select B
endchoice
config MULTIDEF_CHOICE
bool
select C
# Same test with ranges involved
config MULTIDEF_RANGE
int
range A _
menu "menu"
config MULTIDEF_RANGE
int
range B _
if FOO
config MULTIDEF_RANGE
int
range C _
endif
config MULTIDEF_RANGE
int
range D _
endmenu
config MULTIDEF_RANGE
int
range E _
config MULTIDEF_RANGE
int
range F _
# Same test for a choice
choice MULTICHOICE
bool "choice"
default A
config A
bool "A"
config B
bool "B"
config C
bool "C"
config D
bool "C"
config E
bool "C"
endchoice
if FOO
choice MULTICHOICE
default B
endchoice
menu "menu"
choice MULTICHOICE
default C
endchoice
endmenu
choice MULTICHOICE
default D
endchoice
endif
choice MULTICHOICE
default E
endchoice

View File

@ -0,0 +1,3 @@
config FOO
bool
depends on FOO

View File

@ -0,0 +1,3 @@
config FOO
bool
select FOO

View File

@ -0,0 +1,48 @@
config A
bool
depends on B
config B
bool
depends on C = 7
config C
int
range D 8
config D
int
default 3 if E
default 8
config E
bool
config F
bool
select E if G
config G
bool
depends on H
choice
bool "choice"
config H
bool "H"
depends on I
endchoice
choice
bool "choice" if J
config I
bool "I"
endchoice
config J
bool
depends on A

View File

@ -0,0 +1,3 @@
config FOO
bool
default FOO

View File

@ -0,0 +1,3 @@
config FOO
bool
default y if FOO

View File

@ -0,0 +1,7 @@
config FOO
bool
depends on BAR
config BAR
bool
depends on FOO

View File

@ -0,0 +1,7 @@
config FOO
bool
select BAR
config BAR
bool
select FOO

View File

@ -0,0 +1,6 @@
config FOO
bool
config BAR
bool
select FOO if FOO

View File

@ -0,0 +1,11 @@
choice
bool "choice"
config FOO
bool "foo"
depends on BAR
config BAR
bool "bar"
endchoice

View File

@ -0,0 +1,8 @@
choice
bool "choice"
default FOO if FOO
config FOO
bool "foo"
endchoice

View File

@ -0,0 +1,7 @@
choice
bool "choice" if FOO
config FOO
bool "foo"
endchoice

View File

@ -0,0 +1,30 @@
config NO_DEP_SYM
bool
config DEP_SYM
bool
depends on A
config DEP_SYM
depends on B && C
config DEP_SYM
depends on !D
choice NO_DEP_CHOICE
bool "no dep. choice"
endchoice
choice DEP_CHOICE
bool "dep. choice"
depends on A
endchoice
choice DEP_CHOICE
depends on B
endchoice
choice DEP_CHOICE
depends on C
endchoice

View File

@ -0,0 +1,3 @@
config STRING
string "string"
default "\"\\"

View File

@ -0,0 +1,34 @@
# Enabled/disabled in the test
config MODULES
bool "modules"
option modules
config N
def_tristate n
config M
def_tristate m
menuconfig Y
def_tristate y
prompt "foo"
config Y_STRING
string
default "y"
config FOO_BAR_STRING
string
default "foo bar"
config INT_37
int
default 37
config HEX_0X37
hex
default 0x37
config HEX_37
hex
default 37

View File

@ -0,0 +1,11 @@
config TEST
bool
default A && (B || !C && D = "E") || F > G || !!!H
choice CHOICE
bool "choice"
config TEST_CHOICE
bool "test choice" if A
endchoice

View File

@ -0,0 +1,5 @@
# Used to test headers in .config and header files
config FOO
bool "foo"
default y

View File

@ -0,0 +1,50 @@
config TWO_HELP_STRINGS
bool
help
first help string
config TWO_HELP_STRINGS
help
second help string
config NO_BLANK_AFTER_HELP
bool
help
help for
NO_BLANK_AFTER_HELP
choice CHOICE_HELP
bool "choice with help"
help
help for
CHOICE_HELP
endchoice
config HELP_TERMINATED_BY_COMMENT
bool
help
a
b
c
#
config TRICKY_HELP
bool
-help---
a
b
c
d
e
f
g
h
i
#

View File

@ -0,0 +1,99 @@
# Test some tricky cases that give consecutive 'if' nodes even after
# flattening. Simple cases are exercised a ton elsewhere.
if X
endif
if X
endif
config A
if X
endif
if X
endif
config B
if X
endif
if X
endif
if X
endif
config C
if X
if X
if X
endif
if X
endif
endif
if X
if X
endif
if X
endif
endif
config D
endif
if X
endif
menu "E"
if X
if X
endif
endif
if X
if X
endif
endif
endmenu
menu "F"
if X
endif
if X
endif
if X
if X
endif
if X
endif
menu "G"
endmenu
endif
endmenu
choice H
if X
if X
endif
endif
if X
if X
endif
endif
endchoice
choice I
if X
endif
if X
endif
if X
if X
endif
if X
endif
config J
endif
endchoice
if X
endif
if X
endif

View File

@ -0,0 +1,145 @@
config MODULES
def_bool y
option modules
#
# Implied symbols with unmet and met direct dependencies
#
config IMPLY_DIRECT_DEPS
def_tristate y
imply UNMET_DIRECT_1
imply UNMET_DIRECT_2
imply UNMET_DIRECT_3
imply MET_DIRECT_1
imply MET_DIRECT_2
imply MET_DIRECT_3
imply MET_DIRECT_4
config UNMET_DIRECT_1
tristate
depends on n
if n
config UNMET_DIRECT_2
tristate
endif
menu "menu"
depends on n
config UNMET_DIRECT_3
tristate
endmenu
config MET_DIRECT_1
tristate
config MET_DIRECT_2
depends on y
tristate
if y
config MET_DIRECT_3
tristate
endif
menu "menu"
depends on y
config MET_DIRECT_4
tristate
endmenu
#
# 'imply' with condition
#
config IMPLY_COND
def_tristate y
tristate
imply IMPLIED_N_COND if n
imply IMPLIED_M_COND if m
imply IMPLIED_Y_COND if y
config IMPLIED_N_COND
tristate
config IMPLIED_M_COND
tristate
config IMPLIED_Y_COND
tristate
#
# Implying from symbol with value n
#
# Will default to 'n'
config IMPLY_N_1
tristate
imply IMPLIED_FROM_N_1
# This test also disables the imply, so it's kinda redundant, but why not
if n
config IMPLY_N_2
tristate
imply IMPLIED_FROM_N_2
endif
config IMPLIED_FROM_N_1
tristate
config IMPLIED_FROM_N_2
tristate
#
# Implying from symbol with value m
#
config IMPLY_M
def_tristate m
imply IMPLIED_M
# Implying a bool to 'm' makes it default to 'y'
imply IMPLIED_M_BOOL
config IMPLIED_M
tristate
config IMPLIED_M_BOOL
bool
#
# 'imply' which should raise an 'm' default to 'y'
#
config IMPLY_M_TO_Y
tristate
default y
imply IMPLIED_M_TO_Y
config IMPLIED_M_TO_Y
tristate
default m
#
# Used for testing user values
#
config DIRECT_DEP
tristate "direct dep"
config IMPLY
tristate "imply"
imply IMPLIED_TRISTATE
imply IMPLIED_BOOL
config IMPLIED_TRISTATE
tristate "implied tristate"
depends on DIRECT_DEP
config IMPLIED_BOOL
bool "implied bool"
depends on DIRECT_DEP

View File

@ -0,0 +1,12 @@
config TOP
bool
source "Kinclude_path_sourced_1"
config TOP
bool
source "Kinclude_path_sourced_1"
config TOP
bool

View File

@ -0,0 +1,12 @@
config ONE_DOWN
bool
source "Kinclude_path_sourced_2"
config ONE_DOWN
bool
source "Kinclude_path_sourced_2"
config ONE_DOWN
bool

View File

@ -0,0 +1,11 @@
config TWO_DOWN
bool
menu "menu"
endmenu
comment "comment"
choice
bool "choice"
endchoice

View File

@ -0,0 +1,36 @@
comment "comment 1"
choice
bool "choice 1"
endchoice
menu "menu 1"
choice NAMED
bool "choice 2"
endchoice
menu "menu 2"
menu "menu 3"
comment "comment 2"
endmenu
choice
bool "choice 3"
endchoice
choice NAMED
bool
endchoice
endmenu
menu "menu 4"
endmenu
comment "comment 3"
endmenu
menu "menu 5"
endmenu

View File

@ -0,0 +1,78 @@
if UNDEFINED
endif
config ONE_DEF
bool
config TWO_DEF
bool
config TWO_DEF
bool
config MANY_DEF
bool
# Throw in some line continuations too to make sure it doesn't mess up the line
# numbers
if y && \
y
if y && \
y && \
y
# Throw in some help texts too
config HELP_1
bool "help 1"
help
config HELP_2
bool "help 2"
help
foo
bar
baz
config HELP_3
help
foo
bar
bool
config \
MANY_DEF
config MANY_DEF
endif
endif
# Expands to "tests/Klocation_sourced"
source "$TESTS_DIR_FROM_ENV/Klocation$_SOURCED"
# Expands to "sub/Klocation_rsourced"
rsource "$SUB_DIR_FROM_ENV/Klocation$_RSOURCED"
# Expands to "tests/*ub/Klocation_gsourced[12]", matching
# tests/sub/Klocation_gsourced{1,2}
source "$TESTS_DIR_FROM_ENV/*ub/Klocation$_GSOURCED[12]"
# Test old syntax too
gsource "$TESTS_DIR_FROM_ENV/*ub/Klocation$_GSOURCED[12]"
# Expands to "sub/Klocation_grsourced[12]", matching
# tests/sub/Klocation_grsourced{1,2}
rsource "$SUB_DIR_FROM_ENV/Klocation$_GRSOURCED[12]"
# Test old syntax too
grsource "$SUB_DIR_FROM_ENV/Klocation$_GRSOURCED[12]"
# No-ops
osource "nonexistent"
osource "nonexistent*"
gsource "nonexistent"
gsource "nonexistent*"
orsource "nonexistent"
orsource "nonexistent*"
grsource "nonexistent"
grsource "nonexistent*"
config MANY_DEF

View File

@ -0,0 +1,26 @@
config MANY_DEF
choice CHOICE_ONE_DEF
bool "one-def choice"
endchoice
choice CHOICE_TWO_DEF
bool "two-def choice 1"
endchoice
choice CHOICE_TWO_DEF
bool "two-def choice 2"
endchoice
config MENU_HOOK
bool
menu "menu"
endmenu
config COMMENT_HOOK
bool
comment "comment"

View File

@ -0,0 +1,5 @@
config FOO
string
option env="FOO"
mainmenu "---$FOO---"

View File

@ -0,0 +1,37 @@
# Menu nodes with is_menuconfig False
config NOT_MENUCONFIG_1
bool
config NOT_MENUCONFIG_2
bool "not menuconfig 2"
config MENUCONFIG_MULTI_DEF
bool "menuconfig multi def 1"
config COMMENT_HOOK
bool
comment "not menuconfig 3"
# Menu nodes with is_menuconfig True
menuconfig MENUCONFIG_1
bool "menuconfig 1"
menuconfig MENUCONFIG_MULTI_DEF
bool "menuconfig multi def 2"
config MENU_HOOK
bool
menu "menuconfig 2"
endmenu
config CHOICE_HOOK
bool
choice
bool "menuconfig 3"
endchoice

View File

@ -0,0 +1,82 @@
# For testing various minor APIs
# optional choices
choice NOT_OPTIONAL
bool "not optional"
config A
bool "A"
config B
bool "B"
endchoice
choice OPTIONAL
tristate "optional"
optional
config C
tristate "C"
config D
tristate "D"
# Quirky symbols - not proper choice symbol
config Q1
tristate "Q1"
depends on D
config Q2
tristate "Q2"
depends on Q1
config Q3
tristate "Q3"
depends on D
endchoice
# User values
config BOOL
bool "bool" if NOT_DEFINED_1
config TRISTATE
tristate # Visibility should not affect user value
config STRING
string "string"
config INT
int # Visibility should not affect user value
config HEX
hex "hex"
depends on NOT_DEFINED_2
config COMMENT_HOOK
comment "comment"
config MENU_HOOK
menu "menu"
depends on NOT_DEFINED_3 || NOT_DEFINED_2
depends on !NOT_DEFINED_4
endmenu
config FROM_ENV
string "from env"
option env="ENV_VAR"
config FROM_ENV_MISSING
string "from env missing"
option env="MISSING_ENV_VAR"
default "missing"
config FROM_ENV_WEIRD
string
default "weird"
option env="ENV_VAR"
config NOT_ALLNOCONFIG_Y
bool "not allnoconfig_y"
config ALLNOCONFIG_Y
bool "allnoconfig_y"
option allnoconfig_y

View File

@ -0,0 +1 @@
rsource "nonexistent"

View File

@ -0,0 +1 @@
source "nonexistent"

View File

@ -0,0 +1,35 @@
config O
int "O"
default 0
config R
int "R"
default 1
config D
int "D"
default 2
config E
int "E"
default 3
# Defined twice
config R
int "R"
config R2
int "R2"
default 4
config I
int "I"
default 5
config N
int "N"
default 6
config G
int "G"
default 7

View File

@ -0,0 +1,151 @@
# Simple assignments (with bad formatting, as an additional test)
simple-recursive=foo
simple-immediate:=bar
# Should become recursive
simple-recursive-2+=baz
whitespaced = foo
# Simple += test. += should preserve the flavor of the variable (simple vs.
# recursive).
preserve-recursive = foo
preserve-recursive += bar
preserve-immediate := foo
preserve-immediate += bar
# Recursive substitution
recursive = $(foo) $(bar) $($(b-char)a$(z-char))
recursive += $(indir)
foo = abc
bar = def
baz = ghi
b-char = b
z-char = z
indir = jkl $(indir-2)
indir-2 = mno
# Immediate substitution
def = foo
immediate := $(undef)$(def)$(undef)$(def)
def = bar
undef = bar
# Function calls
# Chained function call
quote = "$(1)" "$(2)"
rev-quote = $(quote,$(2),$(1))
surround-rev-quote = $(0) $(rev-quote,$(1),$(2)) $(0)
surround-rev-quote-unused-arg = $(surround-rev-quote,$(1),$(2)) $(3)
# No value is passed for $(3), so it expands to nothing
fn-indir = surround-rev-quote
messy-fn-res = $($(fn-indir)-unused-arg, a b (,) , c d )
# Special characters in function call
comma = ,
right-paren = )
dollar = $
left-paren = (
fn = "$(1)"
special-chars-fn-res = $(fn,$(comma)$(dollar)$(left-paren)foo$(right-paren))
# Variable expansions in various locations (verified by checking how the symbol
# prints)
qaz = QAZ
echo = $(1)
ignore-first = $(2)
config PRINT_ME
string "$(ENV_1)" if ($(echo,FOO) && $(echo,BAR)) || !$(echo,BAZ) || !(($(qaz)))
default "$(echo,"foo")" if "foo $(echo,"bar") baz" = "$(undefined)"
# Expansion within a symbol token, with deliberate sloppiness
config PRINT_$(ignore-first, ,ME)_TOO
bool "foo"
default FOO$(ignore-first, ,BAR)BAZ$(qaz) if $(qaz)&&$(qaz)FOO&&x$(ignore-first, ,xx)
# Recursive expansion (throws an exception)
rec-1 = x $(rec-2) y
rec-2 = x $(rec-3) y
rec-3 = x $(rec-1) y
# Functions are allowed to reference themselves, but an exception is thrown if
# the function seems to be stuck (the recursion gets too deep)
safe-fn-rec = $($(1))
safe-fn-rec-2 = $(safe-fn-rec,safe-fn-rec-3)
safe-fn-rec-3 = foo
safe-fn-rec-res = $(safe-fn-rec,safe-fn-rec-2)
unsafe-fn-rec = $(unsafe-fn-rec,$(1))
# Expansion in the left-hand side of assignments
dummy-arg-fn = bar
lhs-indir-1 = lhs-indir-2
lhs-indir-2 = -baz
rhs = value
# LHS expands to foo-bar-baz
foo-$(dummy-arg-fn, ignored argument )$($(lhs-indir-1)) = $(rhs)
# Expands to empty string, accepted
$(undefined)
# Variable with a space in its name
empty =
space = $(empty) $(empty)
foo$(space)bar = value
space-var-res = $(foo bar)
# Built-in functions
# Expands to "baz qaz"
shell-res = $(shell,false && echo foo bar || echo baz qaz)
# Warns about output on stderr, expands to nothing
shell-stderr-res := $(shell,echo message on stderr >&2)
# Nested parens in macro call. Should give a single argument. Test it with
# $(shell) to get a free argument number check.
parens-res = pre-$(shell,echo '(a,$(b-char),(c,d),e)')-post
# Expands to the current location
location-res := $(filename):$(lineno)
# Adds one warning, expands to nothing
$(warning-if,,no warning)
$(warning-if,n,no warning)
warning-res := $(warning-if,y,a warning)
# Does not cause an error, expands to nothing
error-n-res := $(error-if,n,oops)
# Causes an error when expanded
error-y-res = $(error-if,y,oops)
# Environment variables (for testing Kconfig.env_vars). ENV_1 is already
# referenced above.
env_ref_1 := xxx $(ENV_2) xxx
env_ref_2 := $(shell,echo $(ENV_3))
env_ref_3 :=
env_ref_3 += $(ENV_4)
$(warning-if,$(ENV_5),$(ENV_UNDEFINED))
source "$(ENV_6)"
env_ref_4 = $(ENV_7) # Never evaluated

Some files were not shown because too many files have changed in this diff Show More