zephyr/cmake/modules/zephyr_default.cmake
Torsten Rasmussen 8b199b0fbb cmake: test CMake and issue error if using 3.22.1 / 3.22.2 from PyPI
Fixes: #43099

The CMake 3.22.1 / 3.22.2 PyPI version suffers a bug in the
`cmake_path(... PARENT_PATH)` implementation.

Therefore, when CMake version 3.22.1 / 3.22.2 is detected, test if the
CMake version is suffering from the bug, and in case the bug is present,
fail with an error regarding the issue.

The reason for failing, and not implementing work arounds is that Zephyr
already uses `cmake_path()` at two locations, and we cannot prevent
contributors from adding code which uses this function.

Secondly, Zephyr modules may also use `cmake_path()`, and thus be
affected by said bug.
It is impractical to implement work arounds at all possible locations
for something that is a CMake bug.

Therefore the safest solution is to test CMake itself, to check if the
version in use suffers said bug, and fail with a proper error message
if an affected CMake version is used.

See more here:
https://gitlab.kitware.com/cmake/cmake/-/issues/23187
https://github.com/scikit-build/cmake-python-distributions/issues/221

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2022-02-25 10:16:25 -08:00

131 lines
4.5 KiB
CMake

# SPDX-License-Identifier: Apache-2.0
#
# Copyright (c) 2021, Nordic Semiconductor ASA
# This CMake module will load all Zephyr CMake modules in correct order for
# default Zephyr build system.
#
# Outcome:
# See individual CMake module descriptions
include_guard(GLOBAL)
# The code line below defines the real minimum supported CMake version.
#
# Unfortunately CMake requires the toplevel CMakeLists.txt file to define the
# required version, not even invoking it from a CMake module is sufficient.
# It is however permitted to have multiple invocations of cmake_minimum_required.
cmake_minimum_required(VERSION 3.20.0)
message(STATUS "Application: ${APPLICATION_SOURCE_DIR}")
find_package(ZephyrBuildConfiguration
QUIET NO_POLICY_SCOPE
NAMES ZephyrBuild
PATHS ${ZEPHYR_BASE}/../*
NO_CMAKE_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_PACKAGE_REGISTRY
NO_CMAKE_SYSTEM_PATH
NO_CMAKE_SYSTEM_PACKAGE_REGISTRY
)
# Test and error-out if we are affected by the PyPI CMake 3.22.1 / 3.22.2 bug
if(${CMAKE_VERSION} VERSION_EQUAL 3.22.1 OR ${CMAKE_VERSION} VERSION_EQUAL 3.22.2)
# It seems only pip-installed builds are affected so we test to see if we are affected
cmake_path(GET ZEPHYR_BASE PARENT_PATH test_cmake_path)
if(ZEPHYR_BASE STREQUAL test_cmake_path)
message(FATAL_ERROR "The CMake version ${CMAKE_VERSION} installed suffers"
" the \n 'cmake_path(... PARENT_PATH)' bug, see: \n"
"https://gitlab.kitware.com/cmake/cmake/-/issues/23187\n"
"https://github.com/scikit-build/cmake-python-distributions/issues/221\n"
"Please install another CMake version or use a build of CMake that"
" does not come from PyPI."
)
endif()
endif()
# Prepare user cache
list(APPEND zephyr_cmake_modules python)
list(APPEND zephyr_cmake_modules user_cache)
# Load Zephyr extensions
list(APPEND zephyr_cmake_modules extensions)
list(APPEND zephyr_cmake_modules version)
#
# Find tools
#
list(APPEND zephyr_cmake_modules west)
list(APPEND zephyr_cmake_modules ccache)
# Load default root settings
list(APPEND zephyr_cmake_modules root)
#
# Find Zephyr modules.
# Those may contain additional DTS, BOARD, SOC, ARCH ROOTs.
# Also create the Kconfig binary dir for generated Kconf files.
#
list(APPEND zephyr_cmake_modules zephyr_module)
list(APPEND zephyr_cmake_modules boards)
list(APPEND zephyr_cmake_modules shields)
list(APPEND zephyr_cmake_modules arch)
list(APPEND zephyr_cmake_modules configuration_files)
list(APPEND zephyr_cmake_modules verify-toolchain)
list(APPEND zephyr_cmake_modules host-tools)
# Include board specific device-tree flags before parsing.
set(pre_dt_board "\${BOARD_DIR}/pre_dt_board.cmake" OPTIONAL)
list(APPEND zephyr_cmake_modules "\${pre_dt_board}")
# DTS should be close to kconfig because CONFIG_ variables from
# kconfig and dts should be available at the same time.
#
# The DT system uses a C preprocessor for it's code generation needs.
# This creates an awkward chicken-and-egg problem, because we don't
# always know exactly which toolchain the user needs until we know
# more about the target, e.g. after DT and Kconfig.
#
# To resolve this we find "some" C toolchain, configure it generically
# with the minimal amount of configuration needed to have it
# preprocess DT sources, and then, after we have finished processing
# both DT and Kconfig we complete the target-specific configuration,
# and possibly change the toolchain.
list(APPEND zephyr_cmake_modules generic_toolchain)
list(APPEND zephyr_cmake_modules dts)
list(APPEND zephyr_cmake_modules kconfig)
list(APPEND zephyr_cmake_modules soc)
list(APPEND zephyr_cmake_modules target_toolchain)
foreach(component ${SUB_COMPONENTS})
if(NOT ${component} IN_LIST zephyr_cmake_modules)
message(FATAL_ERROR
"Subcomponent '${component}' not default module for Zephyr CMake build system.\n"
"Please choose one or more valid components: ${zephyr_cmake_modules}"
)
endif()
endforeach()
foreach(module IN LISTS zephyr_cmake_modules)
# Ensures any module of type `${module}` are properly expanded to list before
# passed on the `include(${module})`.
# This is done twice to support cases where the content of `${module}` itself
# contains a variable, like `${BOARD_DIR}`.
string(CONFIGURE "${module}" module)
string(CONFIGURE "${module}" module)
include(${module})
list(REMOVE_ITEM SUB_COMPONENTS ${module})
if(DEFINED SUB_COMPONENTS AND NOT SUB_COMPONENTS)
# All requested Zephyr CMake modules have been loaded, so let's return.
return()
endif()
endforeach()
include(kernel)