scripts: support compile_commands.json in gen_app_partitions.py

Fixes: #40590

This commit updates gen_app_partitions.py to include only files present
in the current build by extracting the information from the CMake
generated `compile_commands.json` file.

This ensures that object files in sub-projects, such as `empty_cpu0`,
will not be considered by the script.

Using the compile_commands.json instead of walking the whole build tree
for finding object files also improves performance:

Time of executing `gen_app_partitions.py` (Old):
__________________________
Executed in  480.06 millis
   usr time  425.83 millis
   sys time   49.55 millis

Time of executing `gen_app_partitions.py` (New):
________________________________________________________
Executed in   76.22 millis
   usr time   49.00 millis
   sys time   24.59 millis

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
Torsten Rasmussen 2021-11-24 15:35:47 +01:00 committed by Anas Nashif
commit f643b8b369
3 changed files with 34 additions and 1 deletions

View file

@ -880,7 +880,7 @@ if(CONFIG_USERSPACE)
OUTPUT ${APP_SMEM_UNALIGNED_LD} ${APP_SMEM_PINNED_UNALIGNED_LD} OUTPUT ${APP_SMEM_UNALIGNED_LD} ${APP_SMEM_PINNED_UNALIGNED_LD}
COMMAND ${PYTHON_EXECUTABLE} COMMAND ${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/gen_app_partitions.py ${ZEPHYR_BASE}/scripts/gen_app_partitions.py
-d ${OBJ_FILE_DIR} -f ${CMAKE_BINARY_DIR}/compile_commands.json
-o ${APP_SMEM_UNALIGNED_LD} -o ${APP_SMEM_UNALIGNED_LD}
$<$<BOOL:${APP_SMEM_PINNED_UNALIGNED_LD}>:--pinoutput=${APP_SMEM_PINNED_UNALIGNED_LD}> $<$<BOOL:${APP_SMEM_PINNED_UNALIGNED_LD}>:--pinoutput=${APP_SMEM_PINNED_UNALIGNED_LD}>
${APP_SMEM_PINNED_PARTITION_LIST_ARG} ${APP_SMEM_PINNED_PARTITION_LIST_ARG}

View file

@ -558,6 +558,14 @@ set(SOC_SERIES ${CONFIG_SOC_SERIES})
set(SOC_TOOLCHAIN_NAME ${CONFIG_SOC_TOOLCHAIN_NAME}) set(SOC_TOOLCHAIN_NAME ${CONFIG_SOC_TOOLCHAIN_NAME})
set(SOC_FAMILY ${CONFIG_SOC_FAMILY}) set(SOC_FAMILY ${CONFIG_SOC_FAMILY})
# For the gen_app_partitions.py to work correctly, we must ensure that
# all targets exports their compile commands to fetch object files.
# We enable it unconditionally, as this is also useful for several IDEs
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE CACHE BOOL
"Export CMake compile commands. Used by gen_app_partitions.py script"
FORCE
)
if("${SOC_SERIES}" STREQUAL "") if("${SOC_SERIES}" STREQUAL "")
set(SOC_PATH ${SOC_NAME}) set(SOC_PATH ${SOC_NAME})
else() else()

View file

@ -34,6 +34,7 @@ found, into data and BSS for each partition.
import sys import sys
import argparse import argparse
import json
import os import os
import re import re
from collections import OrderedDict from collections import OrderedDict
@ -149,6 +150,26 @@ def parse_obj_files(partitions):
find_obj_file_partitions(fullname, partitions) find_obj_file_partitions(fullname, partitions)
def parse_compile_command_file(partitions):
# Iterate over all entries to find object files.
# Thereafter process each object file to find partitions
object_pattern = re.compile(r'-o\s+(\S*)')
with open(args.compile_commands_file, 'rb') as f:
commands = json.load(f)
for command in commands:
build_dir = command.get('directory')
compile_command = command.get('command')
compile_arg = object_pattern.search(compile_command)
obj_file = None if compile_arg is None else compile_arg.group(1)
if obj_file:
fullname = os.path.join(build_dir, obj_file)
# Because of issue #40635, then not all objects referenced by
# the compile_commands.json file may be available, therefore
# only include existing files.
if os.path.exists(fullname):
find_obj_file_partitions(fullname, partitions)
def parse_elf_file(partitions): def parse_elf_file(partitions):
with open(args.elf, 'rb') as f: with open(args.elf, 'rb') as f:
try: try:
@ -216,6 +237,8 @@ def parse_args():
help="Root build directory") help="Root build directory")
parser.add_argument("-e", "--elf", required=False, default=None, parser.add_argument("-e", "--elf", required=False, default=None,
help="ELF file") help="ELF file")
parser.add_argument("-f", "--compile-commands-file", required=False,
default=None, help="CMake compile commands file")
parser.add_argument("-o", "--output", required=False, parser.add_argument("-o", "--output", required=False,
help="Output ld file") help="Output ld file")
parser.add_argument("-v", "--verbose", action="count", default=0, parser.add_argument("-v", "--verbose", action="count", default=0,
@ -237,6 +260,8 @@ def main():
if args.directory is not None: if args.directory is not None:
parse_obj_files(partitions) parse_obj_files(partitions)
if args.compile_commands_file is not None:
parse_compile_command_file(partitions)
elif args.elf is not None: elif args.elf is not None:
parse_elf_file(partitions) parse_elf_file(partitions)
else: else: