change(gen_soc_caps_kconfig): check if config options have the same type

Also introduce ignore pragma to prevent some #defines from .h files to
be translated to Kconfig files.
This commit is contained in:
Jan Beran
2025-05-07 13:37:05 +02:00
parent da5f469d16
commit 2ee0b6c4dd
9 changed files with 143 additions and 89 deletions

View File

@ -3,18 +3,6 @@
# using gen_soc_caps_kconfig.py, do not edit manually # 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 config SOC_CAPS_ECO_VER_MAX
int int
default 301 default 301
@ -279,6 +267,10 @@ config SOC_ADC_SHARED_POWER
bool bool
default y default y
config SOC_BROWNOUT_RESET_SUPPORTED
bool
default y
config SOC_SHARED_IDCACHE_SUPPORTED config SOC_SHARED_IDCACHE_SUPPORTED
bool bool
default y default y
@ -312,8 +304,8 @@ config SOC_CPU_WATCHPOINTS_NUM
default 2 default 2
config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
int hex
default 64 default 0x40
config SOC_DAC_CHAN_NUM config SOC_DAC_CHAN_NUM
int int
@ -804,8 +796,8 @@ config SOC_MPI_MEM_BLOCKS_NUM
default 4 default 4
config SOC_MPI_OPERATIONS_NUM config SOC_MPI_OPERATIONS_NUM
bool int
default y default 1
config SOC_RSA_MAX_BIT_LEN config SOC_RSA_MAX_BIT_LEN
int int
@ -828,8 +820,8 @@ config SOC_SECURE_BOOT_V1
default y default y
config SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS config SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
bool int
default y default 1
config SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX config SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX
int int

View File

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

View File

@ -348,8 +348,8 @@ config SOC_CPU_WATCHPOINTS_NUM
default 2 default 2
config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
int hex
default 64 default 0x40
config SOC_DAC_CHAN_NUM config SOC_DAC_CHAN_NUM
int int
@ -768,8 +768,8 @@ config SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED
default y default y
config SOC_SYSTIMER_COUNTER_NUM config SOC_SYSTIMER_COUNTER_NUM
bool int
default y default 1
config SOC_SYSTIMER_ALARM_NUM config SOC_SYSTIMER_ALARM_NUM
int 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -22,8 +22,8 @@
* x 0`, it's still a risk.) * x 0`, it's still a risk.)
* *
* ECO & exceptions: * ECO & exceptions:
* For ECO-ed booleans, `#define x "Not determined"` for them. This will cause error when used by * 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. * `#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 * These defines are parsed and imported as kconfig variables via the script
* `tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py` * `tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py`
@ -148,7 +148,7 @@
#define SOC_CPU_BREAKPOINTS_NUM 2 #define SOC_CPU_BREAKPOINTS_NUM 2
#define SOC_CPU_WATCHPOINTS_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 ----------------------------------------*/ /*-------------------------- DAC CAPS ----------------------------------------*/
#define SOC_DAC_CHAN_NUM 2 #define SOC_DAC_CHAN_NUM 2
@ -327,7 +327,7 @@
#define SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED 1 #define SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED 1
/*-------------------------- SYSTIMER CAPS ----------------------------------*/ /*-------------------------- 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_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_LO 32 // Bit width of systimer low part
#define SOC_SYSTIMER_BIT_WIDTH_HI 32 // Bit width of systimer high part #define SOC_SYSTIMER_BIT_WIDTH_HI 32 // Bit width of systimer high part

View File

@ -412,8 +412,8 @@ config SOC_CPU_WATCHPOINTS_NUM
default 2 default 2
config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
int hex
default 64 default 0x40
config SOC_SIMD_PREFERRED_DATA_ALIGNMENT config SOC_SIMD_PREFERRED_DATA_ALIGNMENT
int int
@ -832,8 +832,8 @@ config SOC_LP_IO_CLOCK_IS_INDEPENDENT
default y default y
config SOC_SDM_GROUPS config SOC_SDM_GROUPS
bool int
default y default 1
config SOC_SDM_CHANNELS_PER_GROUP config SOC_SDM_CHANNELS_PER_GROUP
int 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -146,7 +146,7 @@
#define SOC_CPU_BREAKPOINTS_NUM 2 #define SOC_CPU_BREAKPOINTS_NUM 2
#define SOC_CPU_WATCHPOINTS_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 #define SOC_SIMD_PREFERRED_DATA_ALIGNMENT 16 // The preferred data alignment accepted by the SIMD instructions, in bytes
@ -325,7 +325,7 @@
#define SOC_LP_IO_CLOCK_IS_INDEPENDENT 1 #define SOC_LP_IO_CLOCK_IS_INDEPENDENT 1
/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ /*-------------------------- Sigma Delta Modulator CAPS -----------------*/
#define SOC_SDM_GROUPS 1 #define SOC_SDM_GROUPS (1U)
#define SOC_SDM_CHANNELS_PER_GROUP 8 #define SOC_SDM_CHANNELS_PER_GROUP 8
#define SOC_SDM_CLK_SUPPORT_APB 1 #define SOC_SDM_CLK_SUPPORT_APB 1

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. 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,6 +1,6 @@
#!/usr/bin/env python #!/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 # SPDX-License-Identifier: Apache-2.0
""" """
Generate Kconfig.soc_caps.in with defines from soc_caps.h Generate Kconfig.soc_caps.in with defines from soc_caps.h
@ -9,6 +9,7 @@ import argparse
import inspect import inspect
import io import io
import logging import logging
import os
import sys import sys
from difflib import unified_diff from difflib import unified_diff
from os import path from os import path
@ -22,11 +23,12 @@ from pyparsing import Char
from pyparsing import Combine from pyparsing import Combine
from pyparsing import Group from pyparsing import Group
from pyparsing import hexnums from pyparsing import hexnums
from pyparsing import Keyword
from pyparsing import Literal from pyparsing import Literal
from pyparsing import nums from pyparsing import nums
from pyparsing import OneOrMore from pyparsing import OneOrMore
from pyparsing import Optional 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 QuotedString
from pyparsing import restOfLine from pyparsing import restOfLine
from pyparsing import Suppress from pyparsing import Suppress
@ -40,50 +42,49 @@ except ImportError:
pass pass
class KconfigWriter(): class KconfigWriter:
PREAMBLE = inspect.cleandoc(''' PREAMBLE = inspect.cleandoc("""
##################################################### #####################################################
# This file is auto-generated from SoC caps # This file is auto-generated from SoC caps
# using gen_soc_caps_kconfig.py, do not edit manually # using gen_soc_caps_kconfig.py, do not edit manually
##################################################### #####################################################
''') """)
KCONFIG_ENTRY_TEMPLATE = Template( KCONFIG_ENTRY_TEMPLATE = Template(
inspect.cleandoc(''' inspect.cleandoc("""
config $name config $name
$entry_type $entry_type
default $value default $value
''')) """)
)
KCONFIG_CONDITION_SOURCE_TEMPLATE = Template( KCONFIG_CONDITION_SOURCE_TEMPLATE = Template(
inspect.cleandoc(''' inspect.cleandoc("""
if $condition if $condition
source "$source_path" source "$source_path"
endif 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 = io.StringIO('')
self.kconfig_text.write(self.PREAMBLE) 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: if name in self.entries:
logging.info('Duplicate entry: {}'.format(name)) logging.info('Duplicate entry: {}'.format(name))
return return
self.entries.add(name)
self.kconfig_text.write('\n\n')
# Format values for kconfig # Format values for kconfig
if entry_type == 'bool': if entry_type == 'bool':
value = 'y' if value else 'n' value = 'y' if value else 'n'
elif entry_type == 'string': elif entry_type == 'string':
value = '"' + value + '"' value = '"' + value + '"'
self.entries[name] = (entry_type, value)
entry = self.KCONFIG_ENTRY_TEMPLATE.substitute(name=name, entry_type=entry_type, value=value)
self.kconfig_text.write(entry)
def add_source(self, source_path, condition): # type: (str, str) -> None def add_source(self, source_path, condition): # type: (str, str) -> None
self.kconfig_text.write('\n\n') self.kconfig_text.write('\n\n')
@ -93,10 +94,16 @@ class KconfigWriter():
else: else:
self.kconfig_text.write('source "' + source_path + '"') 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: 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() old_content = f.readlines()
except FileNotFoundError: except FileNotFoundError:
old_content = [''] old_content = ['']
@ -105,17 +112,17 @@ class KconfigWriter():
new_content = self.kconfig_text.readlines() new_content = self.kconfig_text.readlines()
new_content[-1] += '\n' # Add final newline to end of file 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 # 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: for line in diff:
print(line, end='') print(line, end='')
file_needs_update = True file_needs_update = True
if file_needs_update: if file_needs_update:
print('\n' + 'Updating file: {}'.format(kconfig_path)) print('\n' + 'Updating file: {}'.format(self.kconfig_path))
with open(kconfig_path, 'w', encoding='utf-8') as f: with open(self.kconfig_path, 'w', encoding='utf-8') as f:
f.writelines(new_content) f.writelines(new_content)
return file_needs_update return file_needs_update
@ -138,7 +145,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]] def parse_define(define_line): # type: (str) -> typing.Any[typing.Type[ParserElement]]
# Group for parsing literal suffix of a numbers, e.g. 100UL # Group for parsing literal suffix of a numbers, e.g. 100UL
literal_symbol = Group(CaselessLiteral('L') | CaselessLiteral('U')) literal_symbol = Group(CaselessLiteral('L') | CaselessLiteral('U'))
literal_suffix = OneOrMore(literal_symbol) literal_suffix = OneOrMore(literal_symbol)
@ -148,23 +154,29 @@ def parse_define(define_line): # type: (str) -> typing.Any[typing.Type[ParserEl
# Define value, either a hex, int or a string # Define value, either a hex, int or a string
hex_value = Combine(Literal('0x') + Word(hexnums) + Optional(literal_suffix).suppress())('hex_value') 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') str_value = QuotedString('"')('str_value')
# Remove optional parenthesis around values # 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) res = expr.parseString(define_line)
return res 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)) soc_headers = list(soc_caps_dir.glob(filename))
if soc_headers == []: if soc_headers == []:
return False return None
# Sort header files to make the generated files deterministic # Sort header files to make the generated files deterministic
soc_headers.sort(key=lambda file: file.name) soc_headers.sort(key=lambda file: file.name)
@ -173,13 +185,15 @@ def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str,
for soc_header in soc_headers: for soc_header in soc_headers:
defines.extend(get_defines(soc_header)) 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: for line in defines:
try: try:
inc = parse_include(line) inc = parse_include(line)
if 'inc_path' in inc and 'recursive' in inc and inc['inc_path'][-6:] == 'caps.h': 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 '' condition = inc['condition'].strip(' ') if 'condition' in inc else ''
writer.add_source(source_path, condition) writer.add_source(source_path, condition)
sub_soc_cap_dir = soc_caps_dir.joinpath(str(inc['inc_path'])).parent sub_soc_cap_dir = soc_caps_dir.joinpath(str(inc['inc_path'])).parent
@ -194,6 +208,10 @@ def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str,
logging.debug('Failed to parse: {}'.format(line)) logging.debug('Failed to parse: {}'.format(line))
continue continue
if res.ignore_pragma:
# Ignore this define
continue
# Add the kconfig entry corresponding to the type we parsed # Add the kconfig entry corresponding to the type we parsed
if 'str_value' in res: if 'str_value' in res:
writer.add_entry(res.name, 'string', res.str_value) writer.add_entry(res.name, 'string', res.str_value)
@ -209,10 +227,7 @@ def generate_defines(soc_caps_dir, filename, always_write): # type: (Path, str,
elif 'hex_value' in res: elif 'hex_value' in res:
writer.add_entry(res.name, 'hex', res.hex_value) writer.add_entry(res.name, 'hex', res.hex_value)
# Updates output if necessary return writer
updated = writer.update_file(Path(soc_caps_dir) / 'Kconfig.soc_caps.in', always_write)
return updated
def get_defines(header_path): # type: (Path) -> list[str] def get_defines(header_path): # type: (Path) -> list[str]
@ -230,12 +245,15 @@ def get_defines(header_path): # type: (Path) -> list[str]
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-d', '--dir', help='SoC caps folder paths, support wildcards', nargs='+', default=[]) parser.add_argument('-d', '--dir', help='SoC caps folder paths, support wildcards', nargs='+', default=[])
parser.add_argument('-n', '--filename', nargs='?', default='*caps.h', parser.add_argument('-n', '--filename', nargs='?', default='*caps.h', help='SoC caps filename, support wildcards')
help='SoC caps filename, support wildcards') parser.add_argument(
parser.add_argument('-v', '--verbose', action='count', help='Increase the logging level of the script. Can be specified multiple times.') '-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') parser.add_argument('--always-write', help='Always generate new output files', action='store_true')
args = parser.parse_args() args = parser.parse_args()
@ -249,10 +267,47 @@ if __name__ == '__main__':
logging.basicConfig(level=log_level) logging.basicConfig(level=log_level)
files_updated = [] files_updated = []
writers = [] # type: typing.List[typing.Optional[KconfigWriter]]
for caps_dir in args.dir: for caps_dir in args.dir:
soc_caps_dirs = Path().glob(caps_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))) print('Updated {} files'.format(sum(files_updated)))
sys.exit(all(files_updated)) sys.exit(all(files_updated))

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python #!/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 # SPDX-License-Identifier: Apache-2.0
import sys import sys
import unittest import unittest
@ -13,7 +12,6 @@ except ImportError:
class ParserTests(unittest.TestCase): class ParserTests(unittest.TestCase):
def test_parse_name(self): def test_parse_name(self):
res = gen_soc_caps_kconfig.parse_define('#define TEST_NAME (2)') res = gen_soc_caps_kconfig.parse_define('#define TEST_NAME (2)')
self.assertEqual(res.name, 'TEST_NAME') self.assertEqual(res.name, 'TEST_NAME')
@ -44,10 +42,17 @@ class ParserTests(unittest.TestCase):
self.assertEqual(res.int_value, '329000') self.assertEqual(res.int_value, '329000')
def test_parse_float(self): 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)') res = gen_soc_caps_kconfig.parse_define('#define TEST_FLOAT (3.14)')
self.assertEqual(res.value, '') 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__': if __name__ == '__main__':
print('Running gen_soc_caps_config tests...') print('Running gen_soc_caps_config tests...')