Skip to content

Conversation

@mathieuchopstm
Copy link
Contributor

@mathieuchopstm mathieuchopstm commented Nov 14, 2025

Follow-up to #98990 (c.f. #98990 (comment))

When the LLEXT subsystem detects that a symbol is marked for export from the main image, but the symbol group in which the export belongs is not enabled, add a marker in a special section in addition to not placing the symbol in the final export table.

Add a post-build script which consumes the special section as post-build to dump information about all discarded symbols in a build artifact, and also check for common errors (missing Kconfig symbol / improperly named groups).

While at it, rework LLEXT scripts organization a little bit - maybe a dedicated scripts/llext directory is starting to make sense though... I also wanted to create a ${PROJECT_BINARY_DIR}/llext directory for all artifacts, but I'm not super confident about how to ensure CMake will create said directory, so the report is in artifacts root for now (like SLID listings).

There's also a bit more clean-up I found along the way (namely: a single llext_discarded_strtab could replace the two sections llext_discarded_exports_strtab+llext_exports_strtab, and read_str could possibly be shared between scripts), but that can always come later.

Example output on west build samples/subsys/llext/modules:

This file lists all symbols that have been marked as LLEXT exports
but will not be added to the export table because their symbol group
has not been enabled. Refer to LLEXT Documentation for more details.

====================================================================================================
                                            Group DEVICE                                            
====================================================================================================
Symbol Name                                                  | Address
--------------------------------------------------------------------------------
__device_dts_ord_36                                          | 0800744c
__device_dts_ord_39                                          | 0800748c
__device_dts_ord_47                                          | 0800736c
__device_dts_ord_57                                          | 0800738c
__device_dts_ord_61                                          | 080074ac
__device_dts_ord_64                                          | 080074cc
__device_dts_ord_72                                          | 0800746c
__device_dts_ord_9                                           | 0800734c
__device_dts_ord_90                                          | 0800742c
__device_dts_ord_91                                          | 0800740c
__device_dts_ord_92                                          | 080073ec
__device_dts_ord_93                                          | 080073cc
__device_dts_ord_94                                          | 080073ac

Example build log + output when a group Kconfig is missing:

...
Memory region         Used Size  Region Size  %age Used
           FLASH:       39728 B       512 KB      7.58%
             RAM:        7752 B        96 KB      7.89%
           SRAM0:          0 GB        96 KB      0.00%
        IDT_LIST:          0 GB        32 KB      0.00%
Generating files from /local/zprj/builds/default/zephyr/zephyr.elf for board: nucleo_f401re
WARNING: Could not find Kconfig symbol CONFIG_LLEXT_EXPORT_SYMBOL_GROUP_NONEXISTENT
====================================================================================================
                                         Group NONEXISTENT                                          
Could not find Kconfig symbol CONFIG_LLEXT_EXPORT_SYMBOL_GROUP_NONEXISTENT:
symbol group will never be included in the LLEXT export table!
====================================================================================================
Symbol Name                                                  | Address
--------------------------------------------------------------------------------
example_fn                                                   | 080054e3

Move ELF-related utilities from the "llext_prepare_exptab" script to a
dedicated "llext_elf_toolkit" which can be reused by other LLEXT scripts.
While at it, also improve documentation of class SectionDescriptor.

Signed-off-by: Mathieu Choplain <[email protected]>
When the LLEXT subsystem detects that a symbol is marked for export from
the main image, but the symbol group in which the export belongs is not
enabled, add a marker in a special section in addition to not placing the
symbol in the final export table.

Add a post-build script which consumes the special section as post-build to
dump information about all discarded symbols in a build artifact, and also
check for common errors (missing Kconfig symbol / improperly named groups).

Signed-off-by: Mathieu Choplain <[email protected]>
Comment on lines +64 to +103
def parse_dotconfig(dotconfig_path: Path):
"""
Parses symbols from `.config` file at location 'dotconfig_path'.

Note: tri-state `"m"` is transformed into integer `2`.
"""
# Symbols should receive value 'n' if a line
# containing 'CONFIG_xxx is not set' is present
CONFIG_NOT_SET_REGEXP = re.compile(r"# (CONFIG_.+) is not set")

symbols: dict[str, str | int | bool] = {}

with dotconfig_path.open("r") as fd:
for line in fd:
line = line.strip()
if len(line) <= 1:
continue

# Handle comment lines
if line[0] == '#':
if match := CONFIG_NOT_SET_REGEXP.match(line):
symbols[match.group(1)] = False
continue

key, value = line.split("=")

if value == "y":
value = True
elif value == "n":
value = False
elif value == "m":
value = 2
elif value[0] == value[-1] == '"':
value = value.strip('"')
else:
value = int(value, base=0)

symbols[key] = value

return symbols
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally, I thought about using kconfiglib like a good citizen, but it's much less trivial to use than I hoped... c.f.:

set(COMMON_KCONFIG_ENV_SETTINGS
PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
srctree=${ZEPHYR_BASE}
${kconfig_env_dirs}
KERNELVERSION=${KERNELVERSION}
APPVERSION=${APP_VERSION_STRING}
APP_VERSION_EXTENDED_STRING=${APP_VERSION_EXTENDED_STRING}
APP_VERSION_TWEAK_STRING=${APP_VERSION_TWEAK_STRING}
APP_DIR=${APP_DIR}
CONFIG_=${KCONFIG_NAMESPACE}_
KCONFIG_CONFIG=${DOTCONFIG}
KCONFIG_BOARD_DIR=${KCONFIG_BOARD_DIR}
BOARD=${BOARD}
BOARD_REVISION=${BOARD_REVISION}
BOARD_QUALIFIERS=${BOARD_QUALIFIERS}
HWM_SCHEME=${HWM}
KCONFIG_BINARY_DIR=${KCONFIG_BINARY_DIR}
APPLICATION_SOURCE_DIR=${APPLICATION_SOURCE_DIR}
ZEPHYR_TOOLCHAIN_VARIANT=${ZEPHYR_TOOLCHAIN_VARIANT}
TOOLCHAIN_KCONFIG_DIR=${TOOLCHAIN_KCONFIG_DIR}
TOOLCHAIN_HAS_NEWLIB=${_local_TOOLCHAIN_HAS_NEWLIB}
TOOLCHAIN_HAS_PICOLIBC=${_local_TOOLCHAIN_HAS_PICOLIBC}
EDT_PICKLE=${EDT_PICKLE}
# Export all Zephyr modules to Kconfig
${ZEPHYR_KCONFIG_MODULES_DIR}
)

@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants