Merge branch 'fix/gen_soc_caps_v5.5' into 'release/v5.5'

change: config options of the same name must have the same type (v5.5)

See merge request espressif/esp-idf!39569
This commit is contained in:
Jiang Jiang Jian
2025-06-17 14:50:47 +08:00
11 changed files with 157 additions and 101 deletions

View File

@ -3,18 +3,6 @@
# using gen_soc_caps_kconfig.py, do not edit manually
#####################################################
config SOC_BROWNOUT_RESET_SUPPORTED
string
default "Not determined"
config SOC_TWAI_BRP_DIV_SUPPORTED
string
default "Not determined"
config SOC_DPORT_WORKAROUND
string
default "Not determined"
config SOC_CAPS_ECO_VER_MAX
int
default 301
@ -279,6 +267,10 @@ config SOC_ADC_SHARED_POWER
bool
default y
config SOC_BROWNOUT_RESET_SUPPORTED
bool
default y
config SOC_SHARED_IDCACHE_SUPPORTED
bool
default y
@ -312,8 +304,8 @@ config SOC_CPU_WATCHPOINTS_NUM
default 2
config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
int
default 64
hex
default 0x40
config SOC_DAC_CHAN_NUM
int
@ -836,8 +828,8 @@ config SOC_MPI_MEM_BLOCKS_NUM
default 4
config SOC_MPI_OPERATIONS_NUM
bool
default y
int
default 1
config SOC_RSA_MAX_BIT_LEN
int
@ -860,8 +852,8 @@ config SOC_SECURE_BOOT_V1
default y
config SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
bool
default y
int
default 1
config SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX
int

View File

@ -1,6 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -54,9 +54,9 @@
// Define warning strings here for ECO-ed features to show error when they are used without being
// defined correctly
#define SOC_BROWNOUT_RESET_SUPPORTED "Not determined"
#define SOC_TWAI_BRP_DIV_SUPPORTED "Not determined"
#define SOC_DPORT_WORKAROUND "Not determined"
#define SOC_BROWNOUT_RESET_SUPPORTED "Not determined" // [gen_soc_caps:ignore]
#define SOC_TWAI_BRP_DIV_SUPPORTED "Not determined" // [gen_soc_caps:ignore]
#define SOC_DPORT_WORKAROUND "Not determined" // [gen_soc_caps:ignore]
#endif
/*-------------------------- COMMON CAPS ---------------------------------------*/
@ -107,7 +107,7 @@
#define SOC_PM_SUPPORTED 1
#if SOC_CAPS_ECO_VER < 200
#define SOC_DPORT_WORKAROUND 1
#define SOC_DPORT_WORKAROUND 1 // [gen_soc_caps:ignore]
#endif // SOC_CAPS_ECO_VER < 200
#define SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL (5U)
@ -162,7 +162,7 @@
#define SOC_CPU_BREAKPOINTS_NUM 2
#define SOC_CPU_WATCHPOINTS_NUM 2
#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 64 // bytes
#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x40 // bytes
/*-------------------------- DAC CAPS ----------------------------------------*/
#define SOC_DAC_CHAN_NUM 2
@ -386,7 +386,7 @@
/*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4)
#define SOC_MPI_OPERATIONS_NUM (1)
#define SOC_MPI_OPERATIONS_NUM (1U)
/*--------------------------- RSA CAPS ---------------------------------------*/
#define SOC_RSA_MAX_BIT_LEN (4096)
@ -403,7 +403,7 @@
* Hence, for now we are handling this special capability in bootloader "security" configuration itself.
*/
#define SOC_SECURE_BOOT_V1 1
#define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 1
#define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS (1U)
/*-------------------------- Flash Encryption CAPS----------------------------*/
#define SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX (32)

View File

@ -204,8 +204,8 @@ config SOC_ADC_DMA_SUPPORTED
default y
config SOC_ADC_PERIPH_NUM
bool
default y
int
default 1
config SOC_ADC_MAX_CHANNEL_NUM
int

View File

@ -76,7 +76,7 @@
#define SOC_ADC_MONITOR_SUPPORTED 1
#define SOC_ADC_DIG_SUPPORTED_UNIT(UNIT) 1 //Digital controller supported ADC unit
#define SOC_ADC_DMA_SUPPORTED 1
#define SOC_ADC_PERIPH_NUM (1)
#define SOC_ADC_PERIPH_NUM (1U)
#define SOC_ADC_MAX_CHANNEL_NUM (4)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (4)
#define SOC_ADC_ATTEN_NUM (4)

View File

@ -348,8 +348,8 @@ config SOC_CPU_WATCHPOINTS_NUM
default 2
config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
int
default 64
hex
default 0x40
config SOC_DAC_CHAN_NUM
int
@ -776,8 +776,8 @@ config SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED
default y
config SOC_SYSTIMER_COUNTER_NUM
bool
default y
int
default 1
config SOC_SYSTIMER_ALARM_NUM
int
@ -832,8 +832,8 @@ config SOC_TOUCH_SENSOR_NUM
default 15
config SOC_TOUCH_MIN_CHAN_ID
bool
default y
int
default 1
config SOC_TOUCH_MAX_CHAN_ID
int

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -22,8 +22,8 @@
* x 0`, it's still a risk.)
*
* ECO & exceptions:
* For ECO-ed booleans, `#define x "Not determined"` for them. This will cause error when used by
* `#if x` and `#if !x`, making these missing definitions more obvious.
* For ECO-ed booleans, `#define x "Not determined" // [gen_soc_caps:ignore]` for them. This will cause error when used by
* `#if x` and `#if !x`, making these missing definitions more obvious. Ignore pragma ensures those values are not converted into config options.
*
* These defines are parsed and imported as kconfig variables via the script
* `tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py`
@ -148,7 +148,7 @@
#define SOC_CPU_BREAKPOINTS_NUM 2
#define SOC_CPU_WATCHPOINTS_NUM 2
#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 64 // bytes
#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x40 // bytes
/*-------------------------- DAC CAPS ----------------------------------------*/
#define SOC_DAC_CHAN_NUM 2
@ -329,7 +329,7 @@
#define SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED 1
/*-------------------------- SYSTIMER CAPS ----------------------------------*/
#define SOC_SYSTIMER_COUNTER_NUM 1 // Number of counter units
#define SOC_SYSTIMER_COUNTER_NUM (1U) // Number of counter units
#define SOC_SYSTIMER_ALARM_NUM 3 // Number of alarm units
#define SOC_SYSTIMER_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SOC_SYSTIMER_BIT_WIDTH_HI 32 // Bit width of systimer high part
@ -349,7 +349,7 @@
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
#define SOC_TOUCH_SENSOR_VERSION (2) /*!< Hardware version of touch sensor */
#define SOC_TOUCH_SENSOR_NUM (15) /*!< 15 Touch channels */
#define SOC_TOUCH_MIN_CHAN_ID (1) /*!< Touch minimum channel number, (0 is internal denoise channel) */
#define SOC_TOUCH_MIN_CHAN_ID (1U) /*!< Touch minimum channel number, (0 is internal denoise channel) */
#define SOC_TOUCH_MAX_CHAN_ID (14) /*!< Touch maximum channel number */
#define SOC_TOUCH_SUPPORT_BENCHMARK (1) /*!< Touch sensor supports benchmark configuration */
#define SOC_TOUCH_SUPPORT_SLEEP_WAKEUP (1) /*!< Touch sensor supports sleep awake */

View File

@ -400,8 +400,8 @@ config SOC_CPU_WATCHPOINTS_NUM
default 2
config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
int
default 64
hex
default 0x40
config SOC_SIMD_PREFERRED_DATA_ALIGNMENT
int
@ -856,8 +856,8 @@ config SOC_LP_IO_CLOCK_IS_INDEPENDENT
default y
config SOC_SDM_GROUPS
bool
default y
int
default 1
config SOC_SDM_CHANNELS_PER_GROUP
int
@ -1032,8 +1032,8 @@ config SOC_TOUCH_SENSOR_NUM
default 15
config SOC_TOUCH_MIN_CHAN_ID
bool
default y
int
default 1
config SOC_TOUCH_MAX_CHAN_ID
int

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -148,7 +148,7 @@
#define SOC_CPU_BREAKPOINTS_NUM 2
#define SOC_CPU_WATCHPOINTS_NUM 2
#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 64 // bytes
#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x40 // bytes
#define SOC_SIMD_PREFERRED_DATA_ALIGNMENT 16 // The preferred data alignment accepted by the SIMD instructions, in bytes
@ -335,7 +335,7 @@
#define SOC_LP_IO_CLOCK_IS_INDEPENDENT 1
/*-------------------------- Sigma Delta Modulator CAPS -----------------*/
#define SOC_SDM_GROUPS 1
#define SOC_SDM_GROUPS (1U)
#define SOC_SDM_CHANNELS_PER_GROUP 8
#define SOC_SDM_CLK_SUPPORT_APB 1
@ -400,7 +400,7 @@
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
#define SOC_TOUCH_SENSOR_VERSION (2) /*!< Hardware version of touch sensor */
#define SOC_TOUCH_SENSOR_NUM (15) /*!< 15 Touch channels */
#define SOC_TOUCH_MIN_CHAN_ID (1) /*!< Touch minimum channel number, (0 is internal denoise channel) */
#define SOC_TOUCH_MIN_CHAN_ID (1U) /*!< Touch minimum channel number, (0 is internal denoise channel) */
#define SOC_TOUCH_MAX_CHAN_ID (14) /*!< Touch maximum channel number */
#define SOC_TOUCH_SUPPORT_BENCHMARK (1) /*!< Touch sensor supports benchmark configuration */
#define SOC_TOUCH_SUPPORT_SLEEP_WAKEUP (1) /*!< Touch sensor supports sleep awake */

View File

@ -19,3 +19,5 @@ Defines that are 0 or 1 will automatically be interpreted as Booleans. If it's n
The script is not able to evaluate expressions, e.g X*Y. If you need a variable to be available in kconfig it needs to be a simple assignment expression.
If some `#define` statement should be excluded from being converted into config option, use `// [gen_soc_caps:ignore]` pragma.

View File

@ -1,14 +1,16 @@
#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
"""
Generate Kconfig.soc_caps.in with defines from soc_caps.h
"""
import argparse
import inspect
import io
import logging
import os
import sys
from difflib import unified_diff
from os import path
@ -16,21 +18,22 @@ from pathlib import Path
from string import Template
import pyparsing
from pyparsing import alphas
from pyparsing import CaselessLiteral
from pyparsing import Char
from pyparsing import Combine
from pyparsing import Group
from pyparsing import hexnums
from pyparsing import Keyword
from pyparsing import Literal
from pyparsing import nums
from pyparsing import OneOrMore
from pyparsing import Optional
from pyparsing import ParserElement
from pyparsing import ParserElement # noqa: F401 # pylint: disable=unused-import
from pyparsing import QuotedString
from pyparsing import restOfLine
from pyparsing import Suppress
from pyparsing import Word
from pyparsing import alphas
from pyparsing import hexnums
from pyparsing import nums
from pyparsing import restOfLine
pyparsing.usePackrat = True
@ -40,50 +43,49 @@ except ImportError:
pass
class KconfigWriter():
PREAMBLE = inspect.cleandoc('''
class KconfigWriter:
PREAMBLE = inspect.cleandoc("""
#####################################################
# This file is auto-generated from SoC caps
# using gen_soc_caps_kconfig.py, do not edit manually
#####################################################
''')
""")
KCONFIG_ENTRY_TEMPLATE = Template(
inspect.cleandoc('''
inspect.cleandoc("""
config $name
$entry_type
default $value
'''))
""")
)
KCONFIG_CONDITION_SOURCE_TEMPLATE = Template(
inspect.cleandoc('''
inspect.cleandoc("""
if $condition
source "$source_path"
endif
'''))
def __init__(self): # type: () -> None
self.entries = set('')
""")
)
def __init__(self, path, always_write): # type: (str, bool) -> None
self.kconfig_text = io.StringIO('')
self.kconfig_text.write(self.PREAMBLE)
def add_entry(self, name, entry_type, value): # type: (str, str, typing.Any) -> None
# NAME: (type, val)
self.entries = dict() # type: typing.Dict[str, typing.Tuple[str, typing.Any]] # key: config name, value: tuple of (config_type, config_value)
self.kconfig_path = path
self.always_write = always_write
def add_entry(self, name, entry_type, value): # type: (str, str, typing.Any) -> None
if name in self.entries:
logging.info('Duplicate entry: {}'.format(name))
return
self.entries.add(name)
self.kconfig_text.write('\n\n')
# Format values for kconfig
if entry_type == 'bool':
value = 'y' if value else 'n'
elif entry_type == 'string':
value = '"' + value + '"'
entry = self.KCONFIG_ENTRY_TEMPLATE.substitute(name=name, entry_type=entry_type, value=value)
self.kconfig_text.write(entry)
self.entries[name] = (entry_type, value)
def add_source(self, source_path, condition): # type: (str, str) -> None
self.kconfig_text.write('\n\n')
@ -93,10 +95,16 @@ class KconfigWriter():
else:
self.kconfig_text.write('source "' + source_path + '"')
def update_file(self, kconfig_path, always_write): # type: (Path, bool) -> bool
def update_file(self): # type: () -> bool
for entry_name in self.entries:
self.kconfig_text.write('\n\n')
config_option = self.KCONFIG_ENTRY_TEMPLATE.substitute(
name=entry_name, entry_type=self.entries[entry_name][0], value=self.entries[entry_name][1]
)
self.kconfig_text.write(config_option)
try:
with open(kconfig_path, 'r', encoding='utf-8') as f:
with open(self.kconfig_path, 'r', encoding='utf-8') as f:
old_content = f.readlines()
except FileNotFoundError:
old_content = ['']
@ -105,17 +113,17 @@ class KconfigWriter():
new_content = self.kconfig_text.readlines()
new_content[-1] += '\n' # Add final newline to end of file
file_needs_update = always_write
file_needs_update = self.always_write
# Check if file was updated and print diff for users
diff = unified_diff(old_content, new_content, fromfile=str(kconfig_path), n=2)
diff = unified_diff(old_content, new_content, fromfile=str(self.kconfig_path), n=2)
for line in diff:
print(line, end='')
file_needs_update = True
if file_needs_update:
print('\n' + 'Updating file: {}'.format(kconfig_path))
with open(kconfig_path, 'w', encoding='utf-8') as f:
print('\n' + 'Updating file: {}'.format(self.kconfig_path))
with open(self.kconfig_path, 'w', encoding='utf-8') as f:
f.writelines(new_content)
return file_needs_update
@ -138,7 +146,6 @@ def parse_include(inc_line): # type: (str) -> typing.Any[typing.Type[ParserElem
def parse_define(define_line): # type: (str) -> typing.Any[typing.Type[ParserElement]]
# Group for parsing literal suffix of a numbers, e.g. 100UL
literal_symbol = Group(CaselessLiteral('L') | CaselessLiteral('U'))
literal_suffix = OneOrMore(literal_symbol)
@ -148,23 +155,29 @@ def parse_define(define_line): # type: (str) -> typing.Any[typing.Type[ParserEl
# Define value, either a hex, int or a string
hex_value = Combine(Literal('0x') + Word(hexnums) + Optional(literal_suffix).suppress())('hex_value')
int_value = Combine(Optional('-') + Word(nums))('int_value') + ~Char('.') + Optional(literal_suffix)('literal_suffix')
int_value = (
Combine(Optional('-') + Word(nums))('int_value') + ~Char('.') + Optional(literal_suffix)('literal_suffix')
)
str_value = QuotedString('"')('str_value')
# Remove optional parenthesis around values
value = Optional('(').suppress() + (hex_value ^ int_value ^ str_value)('value') + Optional(')').suppress()
value = Optional('(').suppress() + (hex_value ^ int_value ^ str_value)('value') + Optional(')').suppress()
expr = '#define' + Optional(name)('name') + Optional(value)
# Define ignore pragma (if present, define will be ignored)
ignore_pragma = Literal('//') + Keyword('[gen_soc_caps:ignore]')
expr = (
'#define' + Optional(name)('name') + Optional(value) + Optional(ignore_pragma).set_results_name('ignore_pragma')
)
res = expr.parseString(define_line)
return res
def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str, bool) -> bool
def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str, bool) -> typing.Union[KconfigWriter, None]
soc_headers = list(soc_caps_dir.glob(filename))
if soc_headers == []:
return False
return None
# Sort header files to make the generated files deterministic
soc_headers.sort(key=lambda file: file.name)
@ -173,13 +186,15 @@ def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str,
for soc_header in soc_headers:
defines.extend(get_defines(soc_header))
writer = KconfigWriter()
writer = KconfigWriter(os.path.join(soc_caps_dir, 'Kconfig.soc_caps.in'), always_write)
for line in defines:
try:
inc = parse_include(line)
if 'inc_path' in inc and 'recursive' in inc and inc['inc_path'][-6:] == 'caps.h':
source_path = path.join('$IDF_PATH', str(soc_caps_dir), path.dirname(inc['inc_path']), 'Kconfig.soc_caps.in')
source_path = path.join(
'$IDF_PATH', str(soc_caps_dir), path.dirname(inc['inc_path']), 'Kconfig.soc_caps.in'
)
condition = inc['condition'].strip(' ') if 'condition' in inc else ''
writer.add_source(source_path, condition)
sub_soc_cap_dir = soc_caps_dir.joinpath(str(inc['inc_path'])).parent
@ -194,6 +209,10 @@ def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str,
logging.debug('Failed to parse: {}'.format(line))
continue
if res.ignore_pragma:
# Ignore this define
continue
# Add the kconfig entry corresponding to the type we parsed
if 'str_value' in res:
writer.add_entry(res.name, 'string', res.str_value)
@ -209,10 +228,7 @@ def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str,
elif 'hex_value' in res:
writer.add_entry(res.name, 'hex', res.hex_value)
# Updates output if necessary
updated = writer.update_file(Path(soc_caps_dir) / 'Kconfig.soc_caps.in', always_write)
return updated
return writer
def get_defines(header_path): # type: (Path) -> list[str]
@ -230,12 +246,15 @@ def get_defines(header_path): # type: (Path) -> list[str]
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-d', '--dir', help='SoC caps folder paths, support wildcards', nargs='+', default=[])
parser.add_argument('-n', '--filename', nargs='?', default='*caps.h',
help='SoC caps filename, support wildcards')
parser.add_argument('-v', '--verbose', action='count', help='Increase the logging level of the script. Can be specified multiple times.')
parser.add_argument('-n', '--filename', nargs='?', default='*caps.h', help='SoC caps filename, support wildcards')
parser.add_argument(
'-v',
'--verbose',
action='count',
help='Increase the logging level of the script. Can be specified multiple times.',
)
parser.add_argument('--always-write', help='Always generate new output files', action='store_true')
args = parser.parse_args()
@ -249,10 +268,47 @@ if __name__ == '__main__':
logging.basicConfig(level=log_level)
files_updated = []
writers = [] # type: typing.List[typing.Optional[KconfigWriter]]
for caps_dir in args.dir:
soc_caps_dirs = Path().glob(caps_dir)
files_updated += [generate_defines(d, args.filename, args.always_write) for d in soc_caps_dirs if path.isdir(d)]
new_writers = [generate_defines(d, args.filename, args.always_write) for d in soc_caps_dirs if path.isdir(d)]
writers.extend(new_writers)
configs = dict() # type: typing.Dict[str, str] # key: config name, value: config_type
configs_with_differing_types = dict() # type: typing.Dict[str, typing.Set[str]] # key: config name, value: set of types
for writer in writers:
if writer is None:
continue
for config_name in writer.entries:
if config_name in configs:
type_in_writer = writer.entries[config_name][0]
type_in_configs = configs[config_name]
if type_in_writer != type_in_configs:
if config_name not in configs_with_differing_types:
configs_with_differing_types[config_name] = set()
configs_with_differing_types[config_name].add(type_in_writer)
configs_with_differing_types[config_name].add(type_in_configs)
else:
configs[config_name] = writer.entries[config_name][0]
if configs_with_differing_types:
print(
'The following macro constants would be translated to config options with different types'
' for different targets (which may lead to unexpected behavior).'
)
for config_name in configs_with_differing_types:
print(
f' {config_name} has types'
f'{", ".join(config_type for config_type in configs_with_differing_types[config_name])}'
)
print('Please ensure all the macro constants will translate to the same config type for all targets.')
sys.exit(1)
files_updated = [writer.update_file() for writer in writers if writer is not None]
print('Updated {} files'.format(sum(files_updated)))
sys.exit(all(files_updated))

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python
# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import sys
@ -13,7 +13,6 @@ except ImportError:
class ParserTests(unittest.TestCase):
def test_parse_name(self):
res = gen_soc_caps_kconfig.parse_define('#define TEST_NAME (2)')
self.assertEqual(res.name, 'TEST_NAME')
@ -44,10 +43,17 @@ class ParserTests(unittest.TestCase):
self.assertEqual(res.int_value, '329000')
def test_parse_float(self):
# Kconfig doesnt support floats, should not be parsed as anything
# Kconfig doesn't support floats, should not be parsed as anything
res = gen_soc_caps_kconfig.parse_define('#define TEST_FLOAT (3.14)')
self.assertEqual(res.value, '')
def test_parse_ignore_pragma(self):
res = gen_soc_caps_kconfig.parse_define('#define TEST_IGNORE // [gen_soc_caps:ignore]')
self.assertEqual(' '.join(res.ignore_pragma), '// [gen_soc_caps:ignore]')
res = gen_soc_caps_kconfig.parse_define('#define TEST_NO_IGNORE')
self.assertEqual(res.ignore_pragma, '')
if __name__ == '__main__':
print('Running gen_soc_caps_config tests...')