From 468db1838930a9bd8df1f93a077128351535b406 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Tue, 20 May 2025 16:41:02 +0200 Subject: [PATCH] cmake: modules: Add zephyr_dt_import Extract the part of `dts.cmake` that invokes `gen_dts_cmake.py`, then generalize it into a CMake extension, which can be reused by sysbuild. The Python script itself is also updated, so that the generated CMake file can accept an input variable DEVICETREE_TARGET, which comes from the `zephyr_dt_import(TARGET ...)` argument. Signed-off-by: Grzegorz Swiderski --- cmake/modules/dts.cmake | 34 ++++------------------------- cmake/modules/extensions.cmake | 39 ++++++++++++++++++++++++++++++++++ scripts/dts/gen_dts_cmake.py | 20 +++++++---------- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/cmake/modules/dts.cmake b/cmake/modules/dts.cmake index bd14a678ef5..1822d89fc4a 100644 --- a/cmake/modules/dts.cmake +++ b/cmake/modules/dts.cmake @@ -122,12 +122,6 @@ set(GEN_DRIVER_KCONFIG_SCRIPT ${DT_SCRIPTS}/gen_driver_kconfig_dts.py) # Generated Kconfig symbols go here. set(DTS_KCONFIG ${KCONFIG_BINARY_DIR}/Kconfig.dts) -# This generates DT information needed by the CMake APIs. -set(GEN_DTS_CMAKE_SCRIPT ${DT_SCRIPTS}/gen_dts_cmake.py) -# The generated information itself, which we include() after -# creating it. -set(DTS_CMAKE ${PROJECT_BINARY_DIR}/dts.cmake) - # The location of a file containing known vendor prefixes, relative to # each element of DTS_ROOT. Users can define their own in their own # modules. @@ -283,7 +277,6 @@ set_property(DIRECTORY APPEND PROPERTY ${GEN_EDT_SCRIPT} ${GEN_DEFINES_SCRIPT} ${GEN_DRIVER_KCONFIG_SCRIPT} - ${GEN_DTS_CMAKE_SCRIPT} ) # @@ -356,31 +349,12 @@ if(NOT "${ret}" STREQUAL "0") endif() # -# Run GEN_DTS_CMAKE_SCRIPT. -# -# A temporary file is copied to the original file if it differs. This prevents issue such as a -# cycle when sysbuild is used of configuring and building multiple times due to the dts.cmake file -# of images having a newer modification time than the sysbuild build.ninja file, despite the -# output having not changed +# Import devicetree contents into CMake. +# This enables the CMake dt_* API. # -set(dts_cmake_tmp ${DTS_CMAKE}.new) -execute_process( - COMMAND ${PYTHON_EXECUTABLE} ${GEN_DTS_CMAKE_SCRIPT} - --edt-pickle ${EDT_PICKLE} - --cmake-out ${dts_cmake_tmp} - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - RESULT_VARIABLE ret - ) -if(NOT "${ret}" STREQUAL "0") - message(FATAL_ERROR "gen_dts_cmake.py failed with return code: ${ret}") -else() - zephyr_file_copy(${dts_cmake_tmp} ${DTS_CMAKE} ONLY_IF_DIFFERENT) - file(REMOVE ${dts_cmake_tmp}) - set(dts_cmake_tmp) - message(STATUS "Including generated dts.cmake file: ${DTS_CMAKE}") - include(${DTS_CMAKE}) -endif() +add_custom_target(devicetree_target) +zephyr_dt_import(EDT_PICKLE_FILE ${EDT_PICKLE} TARGET devicetree_target) # # Run dtc if it was found. diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 843590d0638..e015b1182e8 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -4625,6 +4625,45 @@ function(zephyr_dt_preprocess) endif() endfunction() +# Usage: +# zephyr_dt_import(EDT_PICKLE_FILE TARGET ) +# +# Parse devicetree information and make it available to CMake, so that +# it can be accessed by the dt_* CMake extensions from section 4.1. +# +# This requires running a Python script, which can take the output of +# edtlib and generate a CMake source file from it. If that script fails, +# a fatal error occurs. +# +# EDT_PICKLE_FILE : Input edtlib.EDT object in pickle format +# TARGET : Target to populate with devicetree properties +# +function(zephyr_dt_import) + set(req_single_args "EDT_PICKLE_FILE;TARGET") + cmake_parse_arguments(arg "" "${req_single_args}" "" ${ARGN}) + zephyr_check_arguments_required_all(${CMAKE_CURRENT_FUNCTION} arg ${req_single_args}) + + set(gen_dts_cmake_script ${ZEPHYR_BASE}/scripts/dts/gen_dts_cmake.py) + set(gen_dts_cmake_output ${arg_EDT_PICKLE_FILE}.cmake) + + if((${arg_EDT_PICKLE_FILE} IS_NEWER_THAN ${gen_dts_cmake_output}) OR + (${gen_dts_cmake_script} IS_NEWER_THAN ${gen_dts_cmake_output}) + ) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} ${gen_dts_cmake_script} + --edt-pickle ${arg_EDT_PICKLE_FILE} + --cmake-out ${gen_dts_cmake_output} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + RESULT_VARIABLE ret + COMMAND_ERROR_IS_FATAL ANY + ) + endif() + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${gen_dts_cmake_script}) + + set(DEVICETREE_TARGET ${arg_TARGET}) + include(${gen_dts_cmake_output}) +endfunction() + ######################################################## # 5. Zephyr linker functions ######################################################## diff --git a/scripts/dts/gen_dts_cmake.py b/scripts/dts/gen_dts_cmake.py index 47fd30b67b9..5dd4a8779d3 100755 --- a/scripts/dts/gen_dts_cmake.py +++ b/scripts/dts/gen_dts_cmake.py @@ -11,13 +11,12 @@ That data can then be used in the rest of the build system. The generated CMake file looks like this: - add_custom_target(devicetree_target) - set_target_properties(devicetree_target PROPERTIES + set_target_properties(${DEVICETREE_TARGET} PROPERTIES "DT_PROP|/soc|compatible" "vnd,soc;") ... -It defines a special CMake target, and saves various values in the -devicetree as CMake target properties. +It takes an input variable - DEVICETREE_TARGET - and saves various +values in the devicetree as properties of this CMake target. Be careful: @@ -170,15 +169,12 @@ def main(): cmake_comp = f'DT_COMP|{comp}' cmake_props.append(f'"{cmake_comp}" "{cmake_path}"') + cmake_props = map( + 'set_target_properties(${{DEVICETREE_TARGET}} PROPERTIES {})'.format, + cmake_props + ) with open(args.cmake_out, "w", encoding="utf-8") as cmake_file: - print('add_custom_target(devicetree_target)', file=cmake_file) - print(file=cmake_file) - - for prop in cmake_props: - print( - f'set_target_properties(devicetree_target PROPERTIES {prop})', - file=cmake_file - ) + print("\n".join(cmake_props), file=cmake_file) if __name__ == "__main__":