From ea1005b740e41b0b280f4201e0866120d3356b74 Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Thu, 14 Oct 2021 20:00:05 +0800 Subject: [PATCH] build: create BUILD_DIR/prefix_map_gdbinit when enable reproducible build add project property BUILD_COMPONENT_DIRS --- CMakeLists.txt | 26 ++++++++++++++ Kconfig | 3 +- tools/ci/test_reproducible_build.sh | 11 ++++-- tools/cmake/component.cmake | 3 ++ tools/cmake/project_description.json.in | 3 +- tools/generate_debug_prefix_map.py | 45 +++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 tools/generate_debug_prefix_map.py diff --git a/CMakeLists.txt b/CMakeLists.txt index c39d22a1ce..30126a843b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,6 +154,32 @@ if(NOT ${CMAKE_C_COMPILER_VERSION} VERSION_LESS 8.0.0) list(APPEND compile_options "-fdebug-prefix-map=${IDF_PATH}=/IDF") list(APPEND compile_options "-fdebug-prefix-map=${PROJECT_DIR}=/IDF_PROJECT") list(APPEND compile_options "-fdebug-prefix-map=${BUILD_DIR}=/IDF_BUILD") + + # component dirs + idf_build_get_property(python PYTHON) + idf_build_get_property(idf_path IDF_PATH) + idf_build_get_property(component_dirs BUILD_COMPONENT_DIRS) + + execute_process( + COMMAND ${python} + "${idf_path}/tools/generate_debug_prefix_map.py" + "${BUILD_DIR}" + "${component_dirs}" + OUTPUT_VARIABLE result + RESULT_VARIABLE ret + ) + if(NOT ret EQUAL 0) + message(FATAL_ERROR "This is a bug. Please report to https://github.com/espressif/esp-idf/issues") + endif() + + spaces2list(result) + list(LENGTH component_dirs length) + math(EXPR max_index "${length} - 1") + foreach(index RANGE ${max_index}) + list(GET component_dirs ${index} folder) + list(GET result ${index} after) + list(APPEND compile_options "-fdebug-prefix-map=${folder}=${after}") + endforeach() endif() endif() diff --git a/Kconfig b/Kconfig index 92e94cfa4a..f1ede93458 100644 --- a/Kconfig +++ b/Kconfig @@ -206,7 +206,8 @@ mainmenu "Espressif IoT Development Framework Configuration" default n select COMPILER_HIDE_PATHS_MACROS help - If enabled, all date, time, and path information would be eliminated. + If enabled, all date, time, and path information would be eliminated. A .gdbinit file would be create + automatically. (or will be append if you have one already) endmenu # Build type diff --git a/tools/ci/test_reproducible_build.sh b/tools/ci/test_reproducible_build.sh index 6cd6c66bd2..6d71c5011b 100755 --- a/tools/ci/test_reproducible_build.sh +++ b/tools/ci/test_reproducible_build.sh @@ -7,8 +7,7 @@ for path in \ "examples/bluetooth/nimble/blecent"; do cd "${IDF_PATH}/${path}" - echo "CONFIG_APP_REPRODUCIBLE_BUILD=y" >>sdkconfig.defaults - rm -f sdkconfig + echo "CONFIG_APP_REPRODUCIBLE_BUILD=y" >sdkconfig idf.py -B build_first fullclean build idf.py -B build_second fullclean build @@ -23,4 +22,12 @@ for path in \ "*.map"; do diff -s build_first/${item} build_second/${item} # use glob, don't use double quotes done + + # test gdb + rm -f gdb.txt + elf_file=$(find build_first -maxdepth 1 -iname '*.elf') + xtensa-esp32-elf-gdb -x build_first/prefix_map_gdbinit -ex 'set logging on' -ex 'set pagination off' -ex 'list' -ex 'quit' "$elf_file" + if grep "No such file or directory" gdb.txt; then + exit 1 + fi done diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 8bdba18be2..25ed8e7d52 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -189,6 +189,9 @@ function(__component_add component_dir prefix) # Set Kconfig related properties on the component __kconfig_component_init(${component_target}) + + # set BUILD_COMPONENT_DIRS build property + idf_build_set_property(BUILD_COMPONENT_DIRS ${component_dir} APPEND) endfunction() # diff --git a/tools/cmake/project_description.json.in b/tools/cmake/project_description.json.in index db18650e45..6b9b84167c 100644 --- a/tools/cmake/project_description.json.in +++ b/tools/cmake/project_description.json.in @@ -17,5 +17,6 @@ "COMPONENT_KCONFIGS_PROJBUILD" : "${COMPONENT_KCONFIGS_PROJBUILD}" }, "build_components" : ${build_components_json}, - "build_component_paths" : ${build_component_paths_json} + "build_component_paths" : ${build_component_paths_json}, + "debug_prefix_map_gdbinit": "${BUILD_DIR}/prefix_map_gdbinit" } diff --git a/tools/generate_debug_prefix_map.py b/tools/generate_debug_prefix_map.py new file mode 100644 index 0000000000..d9d46b4e2f --- /dev/null +++ b/tools/generate_debug_prefix_map.py @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +# General Workflow: +# 1. read all components dirs, a semicolon-separated string (cmake list) +# 2. map the component dir with a unique prefix /COMPONENT__DIR +# 2. write the prefix mapping file to $BUILD_DIR/prefix_map_gdbinit +# 3. print the unique prefix out, a space-separated string, will be used by the build system to add compile options. + +import argparse +import os +from typing import List + + +def component_name(component_dir: str) -> str: + return '/COMPONENT_{}_DIR'.format(os.path.basename(component_dir).upper()) + + +GDB_SUBSTITUTE_PATH_FMT = 'set substitute-path {} {}\n' + + +def write_gdbinit(build_dir: str, folders: List[str]) -> None: + gdb_init_filepath = os.path.join(build_dir, 'prefix_map_gdbinit') + + with open(gdb_init_filepath, 'w') as fw: + for folder in folders: + fw.write(f'{GDB_SUBSTITUTE_PATH_FMT.format(component_name(folder), folder)}') + + +def main(build_dir: str, folders: List[str]) -> None: + write_gdbinit(build_dir, folders) + print(' '.join([component_name(folder) for folder in folders]), end='') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='print the debug-prefix-map and write to ' + '$BUILD_DIR/prefix_map_gdbinit file') + + parser.add_argument('build_dir', + help='build dir') + parser.add_argument('folders', + help='component folders, semicolon separated string') + args = parser.parse_args() + + main(args.build_dir, args.folders.split(';'))