From 53f271ce108d6fa99cf92d59fe9b9dcc4b8fb45b Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Thu, 8 Jun 2023 17:31:42 +0200 Subject: [PATCH] tools: extend information in project_description.json This extends information provided in the project_description.json file. Newly added information can be used in the SBOM generating tool and also to improve hints regarding the the component dependency issues. Added fields version: This adds versioning to the project_description.json file, so it's easy to identify if it contains the required information. project_version: Can be used as a version for the resulting binary e.g. `hello_world.bin`. idf_path: This one is probably not necessary, but it allows tools to run even without esp-idf environment exported(e.g. export.sh). c_compiler: The `CMAKE_C_COMPILER` value with full path to the compiler binary. This can be used to get information about toolchain, which was used to build the project. common_component_reqs: List of common components as presented in cmake's __COMPONENT_REQUIRES_COMMON and set in tools/cmake/build.cmake:__build_init(). build_component_info: Detailed information about components used during build. It's a dictionary with the component name as a key and each component has a dictionary with detailed information. Following is an example for the efuse component. "efuse": { "alias": "idf::efuse", "target": "___idf_efuse", "prefix": "idf", "dir": "/home/fhrbata/work/esp-idf/components/efuse", "type": "LIBRARY", "lib": "__idf_efuse", "reqs": [], "priv_reqs": [ "bootloader_support", "soc", "spi_flash" ], "managed_reqs": [], "managed_priv_reqs": [], "file": "/home/fhrbata/work/blink/build/esp-idf/efuse/libefuse.a", "sources": [ "/home/fhrbata/work/esp-idf/components/efuse/esp32s3/esp_efuse_table.c", ... ], "include_dirs": [ "include", "esp32s3/include" ] } Signed-off-by: Frantisek Hrbata --- tools/cmake/project.cmake | 85 ++++++++++++++++++++++++- tools/cmake/project_description.json.in | 8 ++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index a9a4ecc2640..1fbc3cd674f 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -71,6 +71,73 @@ function(__project_get_revision var) set(${var} "${PROJECT_VER}" PARENT_SCOPE) endfunction() +function(__component_info components output) + set(components_json "") + foreach(name ${components}) + __component_get_target(target ${name}) + __component_get_property(alias ${target} COMPONENT_ALIAS) + __component_get_property(prefix ${target} __PREFIX) + __component_get_property(dir ${target} COMPONENT_DIR) + __component_get_property(type ${target} COMPONENT_TYPE) + __component_get_property(lib ${target} COMPONENT_LIB) + __component_get_property(reqs ${target} REQUIRES) + __component_get_property(include_dirs ${target} INCLUDE_DIRS) + __component_get_property(priv_reqs ${target} PRIV_REQUIRES) + __component_get_property(managed_reqs ${target} MANAGED_REQUIRES) + __component_get_property(managed_priv_reqs ${target} MANAGED_PRIV_REQUIRES) + if("${type}" STREQUAL "LIBRARY") + set(file "$") + + # The idf_component_register function is converting each source file path defined + # in SRCS into absolute one. But source files can be also added with cmake's + # target_sources and have relative paths. This is used for example in log + # component. Let's make sure all source files have absolute path. + set(sources "") + get_target_property(srcs ${lib} SOURCES) + foreach(src ${srcs}) + get_filename_component(src "${src}" ABSOLUTE BASE_DIR "${dir}") + list(APPEND sources "${src}") + endforeach() + + else() + set(file "") + set(sources "") + endif() + + make_json_list("${reqs}" reqs) + make_json_list("${priv_reqs}" priv_reqs) + make_json_list("${managed_reqs}" managed_reqs) + make_json_list("${managed_priv_reqs}" managed_priv_reqs) + make_json_list("${include_dirs}" include_dirs) + make_json_list("${sources}" sources) + + string(CONCAT component_json + " \"${name}\": {\n" + " \"alias\": \"${alias}\",\n" + " \"target\": \"${target}\",\n" + " \"prefix\": \"${prefix}\",\n" + " \"dir\": \"${dir}\",\n" + " \"type\": \"${type}\",\n" + " \"lib\": \"${lib}\",\n" + " \"reqs\": ${reqs},\n" + " \"priv_reqs\": ${priv_reqs},\n" + " \"managed_reqs\": ${managed_reqs},\n" + " \"managed_priv_reqs\": ${managed_priv_reqs},\n" + " \"file\": \"${file}\",\n" + " \"sources\": ${sources},\n" + " \"include_dirs\": ${include_dirs}\n" + " }" + ) + string(CONFIGURE "${component_json}" component_json) + if(NOT "${components_json}" STREQUAL "") + string(APPEND components_json ",\n") + endif() + string(APPEND components_json "${component_json}") + endforeach() + set(components_json "{\n ${components_json}\n }") + set(${output} "${components_json}" PARENT_SCOPE) +endfunction() + # # Output the built components to the user. Generates files for invoking idf_monitor.py # that doubles as an overview of some of the more important build properties. @@ -107,6 +174,7 @@ function(__project_info test_components) endforeach() set(PROJECT_NAME ${CMAKE_PROJECT_NAME}) + idf_build_get_property(PROJECT_VER PROJECT_VER) idf_build_get_property(PROJECT_PATH PROJECT_DIR) idf_build_get_property(BUILD_DIR BUILD_DIR) idf_build_get_property(SDKCONFIG SDKCONFIG) @@ -114,6 +182,7 @@ function(__project_info test_components) idf_build_get_property(PROJECT_EXECUTABLE EXECUTABLE) set(PROJECT_BIN ${CMAKE_PROJECT_NAME}.bin) idf_build_get_property(IDF_VER IDF_VER) + idf_build_get_property(common_component_reqs __COMPONENT_REQUIRES_COMMON) idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE) include(${sdkconfig_cmake}) @@ -124,8 +193,22 @@ function(__project_info test_components) idf_build_get_property(build_dir BUILD_DIR) make_json_list("${build_components};${test_components}" build_components_json) make_json_list("${build_component_paths};${test_component_paths}" build_component_paths_json) + make_json_list("${common_component_reqs}" common_component_reqs_json) + + __component_info("${build_components};${test_components}" build_component_info_json) + + # The configure_file function doesn't process generator expressions, which are needed + # e.g. to get component target library(TARGET_LINKER_FILE), so the project_description + # file is created in two steps. The first step, with configure_file, creates a temporary + # file with cmake's variables substituted and unprocessed generator expressions. The second + # step, with file(GENERATE), processes the temporary file and substitute generator expression + # into the final project_description.json file. configure_file("${idf_path}/tools/cmake/project_description.json.in" - "${build_dir}/project_description.json") + "${build_dir}/project_description.json.templ") + file(READ "${build_dir}/project_description.json.templ" project_description_json_templ) + file(REMOVE "${build_dir}/project_description.json.templ") + file(GENERATE OUTPUT "${build_dir}/project_description.json" + CONTENT "${project_description_json_templ}") # We now have the following component-related variables: # diff --git a/tools/cmake/project_description.json.in b/tools/cmake/project_description.json.in index d3707eb9cc2..c59b389469b 100644 --- a/tools/cmake/project_description.json.in +++ b/tools/cmake/project_description.json.in @@ -1,6 +1,9 @@ { + "version": "1", "project_name": "${PROJECT_NAME}", + "project_version": "${PROJECT_VER}", "project_path": "${PROJECT_PATH}", + "idf_path": "${IDF_PATH}", "build_dir": "${BUILD_DIR}", "config_file": "${SDKCONFIG}", "config_defaults": "${SDKCONFIG_DEFAULTS}", @@ -14,10 +17,13 @@ "phy_data_partition": "${CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION}", "monitor_baud" : "${CONFIG_ESPTOOLPY_MONITOR_BAUD}", "monitor_toolprefix": "${CONFIG_SDK_TOOLPREFIX}", + "c_compiler": "${CMAKE_C_COMPILER}", "config_environment" : { "COMPONENT_KCONFIGS" : "${COMPONENT_KCONFIGS}", "COMPONENT_KCONFIGS_PROJBUILD" : "${COMPONENT_KCONFIGS_PROJBUILD}" }, + "common_component_reqs": ${common_component_reqs_json}, "build_components" : ${build_components_json}, - "build_component_paths" : ${build_component_paths_json} + "build_component_paths" : ${build_component_paths_json}, + "build_component_info" : ${build_component_info_json} }