Commit 13a8e352 authored by Martí Bolívar's avatar Martí Bolívar
Browse files

cmake: modules: dts: refactor for readability



Improve comments, rearrange variable definitions to better match the
control flow of the module, and avoid nesting by adding a return()
statement.

No functional changes expected.

Signed-off-by: default avatarMartí Bolívar <marti.bolivar@nordicsemi.no>
parent 869aee9c
Loading
Loading
Loading
Loading
+311 −237
Original line number Diff line number Diff line
@@ -8,49 +8,112 @@ include(boards)
find_package(HostTools)
find_package(Dtc 1.4.6)

file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include/generated)

# Zephyr code can configure itself based on a KConfig'uration with the
# header file autoconf.h. There exists an analogous file devicetree_generated.h
# that allows configuration based on information encoded in DTS.
# Zephyr code is usually configured using devicetree, but this is
# still technically optional (see e.g. CONFIG_HAS_DTS).
#
# Here we call on dtc, the gcc preprocessor and
# scripts/dts/gen_defines.py to generate various DT-related files at
# CMake configure-time.
# This module makes information from the devicetree available to
# various build stages, as well as to other arbitrary Python scripts:
#
# See the Devicetree user guide in the Zephyr documentation for details.
set(GEN_DEFINES_SCRIPT          ${ZEPHYR_BASE}/scripts/dts/gen_defines.py)
set(ZEPHYR_DTS                  ${PROJECT_BINARY_DIR}/zephyr.dts)
# This contains the edtlib.EDT object created from zephyr.dts in Python's
# pickle data marshalling format (https://docs.python.org/3/library/pickle.html)
#   - To Zephyr and application source code files, as a C macro API
#     defined in <zephyr/devicetree.h>
#
#   - To other arbitrary Python scripts (like twister) using a
#     serialized edtlib.EDT object in Python's pickle format
#     (https://docs.python.org/3/library/pickle.html)
#
#   - To users as a final devicetree source (DTS) file which can
#     be used for debugging
#
# Its existence is an implementation detail used to speed up further
# use of the devicetree by processes that run later on in the build,
# and should not be made part of the documentation.
#   - To CMake files, after this module has finished running, using
#     devicetree extensions defined in cmake/modules/extensions.cmake
#
#   - To Kconfig files, both using some Kconfig symbols we generate
#     here as well as the extension functions defined in
#     scripts/kconfig/kconfigfunctions.py
#
# See the specific API documentation for each of these cases for more
# information on what is currently available to you.
#
# We rely on the C preprocessor, the devicetree python package, and
# files in scripts/dts to make all this work. We also optionally will
# run the dtc tool if it is found, in order to catch any additional
# warnings or errors it generates.

# We will place some generated include files in here.
set(BINARY_DIR_INCLUDE           ${PROJECT_BINARY_DIR}/include)
set(BINARY_DIR_INCLUDE_GENERATED ${BINARY_DIR_INCLUDE}/generated)
# Unconditionally create it, even if we don't have DTS support. This
# is a historical artifact, and users expect this directory to exist
# to put their own generated content inside.
file(MAKE_DIRECTORY ${BINARY_DIR_INCLUDE_GENERATED})

# The directory containing devicetree related scripts.
set(DT_SCRIPTS                  ${ZEPHYR_BASE}/scripts/dts)

# This generates DT information needed by the C macro APIs,
# along with a few other things.
set(GEN_DEFINES_SCRIPT          ${DT_SCRIPTS}/gen_defines.py)
# The edtlib.EDT object in pickle format.
set(EDT_PICKLE                  ${PROJECT_BINARY_DIR}/edt.pickle)
set(DEVICETREE_GENERATED_H      ${PROJECT_BINARY_DIR}/include/generated/devicetree_generated.h)
set(DEVICE_EXTERN_H             ${PROJECT_BINARY_DIR}/include/generated/device_extern.h)
# The generated file containing the final DTS, for debugging.
set(ZEPHYR_DTS                  ${PROJECT_BINARY_DIR}/zephyr.dts)
# The generated C header needed by <zephyr/devicetree.h>
set(DEVICETREE_GENERATED_H      ${BINARY_DIR_INCLUDE_GENERATED}/devicetree_generated.h)
# Legacy; ignore this.
set(DEVICE_EXTERN_H             ${BINARY_DIR_INCLUDE_GENERATED}/device_extern.h)
# Generated build system internals.
set(DTS_POST_CPP                ${PROJECT_BINARY_DIR}/zephyr.dts.pre)
set(DTS_DEPS                    ${PROJECT_BINARY_DIR}/zephyr.dts.d)
# The location of a list of known vendor prefixes.
# This is relative to each element of DTS_ROOT.
set(VENDOR_PREFIXES             dts/bindings/vendor-prefixes.txt)

# Devicetree in Kconfig.
set(GEN_DRIVER_KCONFIG_SCRIPT   ${ZEPHYR_BASE}/scripts/dts/gen_driver_kconfig_dts.py)
# This generates DT information needed by the Kconfig APIs.
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)

# Devicetree in CMake.
set(DTS_CMAKE_SCRIPT            ${ZEPHYR_BASE}/scripts/dts/gen_dts_cmake.py)
# 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.
set(VENDOR_PREFIXES             dts/bindings/vendor-prefixes.txt)

# The C preprocessor to use.
set_ifndef(CMAKE_DTS_PREPROCESSOR ${CMAKE_C_COMPILER})

#
# Halt execution early if there is no devicetree.
#

# TODO: What to do about non-posix platforms where NOT CONFIG_HAS_DTS (xtensa)?
# Drop support for NOT CONFIG_HAS_DTS perhaps?
set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts)
if(EXISTS ${DTS_SOURCE})
  # We found a devicetree. Check for a board revision overlay.
  if(BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay)
    list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay)
  endif()
else()
  # If we don't have a devicetree after all, there's not much to do.
  set(header_template ${ZEPHYR_BASE}/misc/generated/generated_header.template)
  zephyr_file_copy(${header_template} ${DEVICETREE_GENERATED_H} ONLY_IF_DIFFERENT)
  return()
endif()

#
# Finalize the value of DTS_ROOT, so we know where all our
# DTS files, bindings, and vendor prefixes are.
#

# Convert relative paths to absolute paths relative to the application
# source directory.
zephyr_file(APPLICATION_ROOT DTS_ROOT)

# 'DTS_ROOT' is a list of directories where a directory tree with DT
# files may be found. It always includes the application directory,
# the board directory, and ${ZEPHYR_BASE}.
# DTS_ROOT always includes the application directory, the board
# directory, shield directories, and ZEPHYR_BASE.
list(APPEND
  DTS_ROOT
  ${APPLICATION_SOURCE_DIR}
@@ -59,8 +122,11 @@ list(APPEND
  ${ZEPHYR_BASE}
  )

# DTS directories can come from multiple places. Some places like a
# user's CMakeLists.txt can preserve symbolic links. Others like
# Convert the directories in DTS_ROOT to absolute paths without
# symlinks.
#
# DTS directories can come from multiple places. Some places, like a
# user's CMakeLists.txt can preserve symbolic links. Others, like
# scripts/zephyr_module.py --settings-out resolve them.
unset(real_dts_root)
foreach(dts_dir ${DTS_ROOT})
@@ -69,27 +135,22 @@ foreach(dts_dir ${DTS_ROOT})
endforeach()
set(DTS_ROOT ${real_dts_root})

# Finally, de-duplicate the list.
list(REMOVE_DUPLICATES
  DTS_ROOT
  )

# TODO: What to do about non-posix platforms where NOT CONFIG_HAS_DTS (xtensa)?
# Drop support for NOT CONFIG_HAS_DTS perhaps?
if(EXISTS ${DTS_SOURCE})
  set(SUPPORTS_DTS 1)
  if(BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay)
    list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay)
  endif()
else()
  set(SUPPORTS_DTS 0)
endif()
#
# Find all the DTS files we need to concatenate and preprocess, as
# well as all the devicetree bindings and vendor prefixes associated
# with them.
#

set(dts_files
  ${DTS_SOURCE}
  ${shield_dts_files}
  )

if(SUPPORTS_DTS)
if(DTC_OVERLAY_FILE)
  # Convert from space-separated files into file list
  string(CONFIGURE "${DTC_OVERLAY_FILE}" DTC_OVERLAY_FILE_EXPANDED)
@@ -157,15 +218,14 @@ if(SUPPORTS_DTS)
set(CACHED_DTS_ROOT_BINDINGS ${DTS_ROOT_BINDINGS} CACHE INTERNAL
  "DT bindings root directories")

  if(NOT DEFINED CMAKE_DTS_PREPROCESSOR)
    set(CMAKE_DTS_PREPROCESSOR ${CMAKE_C_COMPILER})
  endif()
#
# Run the C preprocessor on the devicetree source, so we can parse it
# (using the Python devicetree package) in later steps.
#

# TODO: Cut down on CMake configuration time by avoiding
# regeneration of devicetree_generated.h on every configure. How
  # challenging is this? What are the dts dependencies? We run the
  # preprocessor, and it seems to be including all kinds of
  # directories with who-knows how many header files.
# challenging is this? Can we cache the dts dependencies?

# Run the preprocessor on the DTS input files. We are leaving
# linemarker directives enabled on purpose. This tells dtlib where
@@ -191,27 +251,33 @@ if(SUPPORTS_DTS)
  message(FATAL_ERROR "command failed with return code: ${ret}")
endif()

#
# Make sure we re-run CMake if any devicetree sources or transitive
# includes change.
#

# Parse the generated dependency file to find the DT sources that
  # were included, including any transitive includes, and then add
  # them to the list of files that trigger a re-run of CMake.
# were included, including any transitive includes.
toolchain_parse_make_rule(${DTS_DEPS}
  include_files # Output parameter
  )

# Add the results to the list of files that, when change, force the
# build system to re-run CMake.
set_property(DIRECTORY APPEND PROPERTY
  CMAKE_CONFIGURE_DEPENDS
  ${include_files}
  ${GEN_DEFINES_SCRIPT}
  ${GEN_DRIVER_KCONFIG_SCRIPT}
    ${DTS_CMAKE_SCRIPT}
  ${GEN_DTS_CMAKE_SCRIPT}
  )

#
  # Run gen_defines.py to create a header file, zephyr.dts, and edt.pickle.
# Run GEN_DEFINES_SCRIPT.
#

string(REPLACE ";" " " EXTRA_DTC_FLAGS_RAW "${EXTRA_DTC_FLAGS}")
  set(CMD_EXTRACT ${PYTHON_EXECUTABLE} ${GEN_DEFINES_SCRIPT}
set(CMD_GEN_DEFINES ${PYTHON_EXECUTABLE} ${GEN_DEFINES_SCRIPT}
--dts ${DTS_POST_CPP}
--dtc-flags '${EXTRA_DTC_FLAGS_RAW}'
--bindings-dirs ${DTS_ROOT_BINDINGS}
@@ -222,12 +288,12 @@ if(SUPPORTS_DTS)
)

execute_process(
    COMMAND ${CMD_EXTRACT}
  COMMAND ${CMD_GEN_DEFINES}
  WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  RESULT_VARIABLE ret
  )
if(NOT "${ret}" STREQUAL "0")
    message(STATUS "In: ${PROJECT_BINARY_DIR}, command: ${CMD_EXTRACT}")
  message(STATUS "In: ${PROJECT_BINARY_DIR}, command: ${CMD_GEN_DEFINES}")
  message(FATAL_ERROR "gen_defines.py failed with return code: ${ret}")
else()
  zephyr_file_copy(${ZEPHYR_DTS}.new ${ZEPHYR_DTS} ONLY_IF_DIFFERENT)
@@ -239,6 +305,9 @@ if(SUPPORTS_DTS)
  message(STATUS "Generated devicetree_generated.h: ${DEVICETREE_GENERATED_H}")
endif()

#
# Run GEN_DRIVER_KCONFIG_SCRIPT.
#

execute_process(
  COMMAND ${PYTHON_EXECUTABLE} ${GEN_DRIVER_KCONFIG_SCRIPT}
@@ -251,8 +320,12 @@ if(SUPPORTS_DTS)
  message(FATAL_ERROR "gen_driver_kconfig_dts.py failed with return code: ${ret}")
endif()

#
# Run GEN_DTS_CMAKE_SCRIPT.
#

execute_process(
    COMMAND ${PYTHON_EXECUTABLE} ${DTS_CMAKE_SCRIPT}
  COMMAND ${PYTHON_EXECUTABLE} ${GEN_DTS_CMAKE_SCRIPT}
  --edt-pickle ${EDT_PICKLE}
  --cmake-out ${DTS_CMAKE}
  WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
@@ -266,22 +339,25 @@ if(SUPPORTS_DTS)
endif()

#
  # Run dtc on the final devicetree source, just to catch any
  # warnings/errors from it. dtlib and edtlib parse the devicetree files
  # themselves, so we don't rely on dtc otherwise.
# Run dtc if it was found.
#
# This is just to generate warnings and errors; we discard the output.
#

if(DTC)

set(DTC_WARN_UNIT_ADDR_IF_ENABLED "")
check_dtc_flag("-Wunique_unit_address_if_enabled" check)
if (check)
  set(DTC_WARN_UNIT_ADDR_IF_ENABLED "-Wunique_unit_address_if_enabled")
endif()

set(DTC_NO_WARN_UNIT_ADDR "")
check_dtc_flag("-Wno-unique_unit_address" check)
if (check)
  set(DTC_NO_WARN_UNIT_ADDR "-Wno-unique_unit_address")
endif()

set(VALID_EXTRA_DTC_FLAGS "")
foreach(extra_opt ${EXTRA_DTC_FLAGS})
  check_dtc_flag(${extra_opt} check)
@@ -290,6 +366,7 @@ if(SUPPORTS_DTS)
  endif()
endforeach()
set(EXTRA_DTC_FLAGS ${VALID_EXTRA_DTC_FLAGS})

execute_process(
  COMMAND ${DTC}
  -O dts
@@ -304,11 +381,8 @@ if(SUPPORTS_DTS)
  WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  RESULT_VARIABLE ret
  )

if(NOT "${ret}" STREQUAL "0")
  message(FATAL_ERROR "command failed with return code: ${ret}")
endif()
endif(DTC)
else()
  set(header_template ${ZEPHYR_BASE}/misc/generated/generated_header.template)
  zephyr_file_copy(${header_template} ${DEVICETREE_GENERATED_H} ONLY_IF_DIFFERENT)
endif(SUPPORTS_DTS)