diff --git a/cmake/app/boilerplate.cmake b/cmake/app/boilerplate.cmake index 0e04b6f6292..ee39172ae63 100644 --- a/cmake/app/boilerplate.cmake +++ b/cmake/app/boilerplate.cmake @@ -175,215 +175,14 @@ add_custom_target( # Dummy add to generate files. zephyr_linker_sources(SECTIONS) -# 'BOARD_ROOT' is a prioritized list of directories where boards may -# be found. It always includes ${ZEPHYR_BASE} at the lowest priority. zephyr_file(APPLICATION_ROOT BOARD_ROOT) -list(APPEND BOARD_ROOT ${ZEPHYR_BASE}) zephyr_file(APPLICATION_ROOT SOC_ROOT) zephyr_file(APPLICATION_ROOT ARCH_ROOT) -# Check that BOARD has been provided, and that it has not changed. -zephyr_check_cache(BOARD REQUIRED) - -string(FIND "${BOARD}" "@" REVISION_SEPARATOR_INDEX) -if(NOT (REVISION_SEPARATOR_INDEX EQUAL -1)) - math(EXPR BOARD_REVISION_INDEX "${REVISION_SEPARATOR_INDEX} + 1") - string(SUBSTRING ${BOARD} ${BOARD_REVISION_INDEX} -1 BOARD_REVISION) - string(SUBSTRING ${BOARD} 0 ${REVISION_SEPARATOR_INDEX} BOARD) -endif() - -set(BOARD_MESSAGE "Board: ${BOARD}") - -if(DEFINED ENV{ZEPHYR_BOARD_ALIASES}) - include($ENV{ZEPHYR_BOARD_ALIASES}) - if(${BOARD}_BOARD_ALIAS) - set(BOARD_ALIAS ${BOARD} CACHE STRING "Board alias, provided by user") - set(BOARD ${${BOARD}_BOARD_ALIAS}) - message(STATUS "Aliased BOARD=${BOARD_ALIAS} changed to ${BOARD}") - endif() -endif() -include(${ZEPHYR_BASE}/boards/deprecated.cmake) -if(${BOARD}_DEPRECATED) - set(BOARD_DEPRECATED ${BOARD} CACHE STRING "Deprecated board name, provided by user") - set(BOARD ${${BOARD}_DEPRECATED}) - message(WARNING "Deprecated BOARD=${BOARD_DEPRECATED} name specified, board automatically changed to: ${BOARD}.") -endif() - -zephyr_boilerplate_watch(BOARD) - -foreach(root ${BOARD_ROOT}) - # Check that the board root looks reasonable. - if(NOT IS_DIRECTORY "${root}/boards") - message(WARNING "BOARD_ROOT element without a 'boards' subdirectory: -${root} -Hints: - - if your board directory is '/foo/bar/boards//my_board' then add '/foo/bar' to BOARD_ROOT, not the entire board directory - - if in doubt, use absolute paths") - endif() - - # NB: find_path will return immediately if the output variable is - # already set - if (BOARD_ALIAS) - find_path(BOARD_HIDDEN_DIR - NAMES ${BOARD_ALIAS}_defconfig - PATHS ${root}/boards/*/* - NO_DEFAULT_PATH - ) - if(BOARD_HIDDEN_DIR) - message("Board alias ${BOARD_ALIAS} is hiding the real board of same name") - endif() - endif() - find_path(BOARD_DIR - NAMES ${BOARD}_defconfig - PATHS ${root}/boards/*/* - NO_DEFAULT_PATH - ) - if(BOARD_DIR AND NOT (${root} STREQUAL ${ZEPHYR_BASE})) - set(USING_OUT_OF_TREE_BOARD 1) - endif() -endforeach() - -if(EXISTS ${BOARD_DIR}/revision.cmake) - # Board provides revision handling. - include(${BOARD_DIR}/revision.cmake) -elseif(BOARD_REVISION) - message(WARNING "Board revision ${BOARD_REVISION} specified for ${BOARD}, \ - but board has no revision so revision will be ignored.") -endif() - -if(DEFINED BOARD_REVISION) - set(BOARD_MESSAGE "${BOARD_MESSAGE}, Revision: ${BOARD_REVISION}") - if(DEFINED ACTIVE_BOARD_REVISION) - set(BOARD_MESSAGE "${BOARD_MESSAGE} (Active: ${ACTIVE_BOARD_REVISION})") - set(BOARD_REVISION ${ACTIVE_BOARD_REVISION}) - endif() - - string(REPLACE "." "_" BOARD_REVISION_STRING ${BOARD_REVISION}) -endif() - -# Check that SHIELD has not changed. -zephyr_check_cache(SHIELD WATCH) - -if(SHIELD) - set(BOARD_MESSAGE "${BOARD_MESSAGE}, Shield(s): ${SHIELD}") -endif() - -message(STATUS "${BOARD_MESSAGE}") - -if(DEFINED SHIELD) - string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}") -endif() -# SHIELD-NOTFOUND is a real CMake list, from which valid shields can be popped. -# After processing all shields, only invalid shields will be left in this list. -set(SHIELD-NOTFOUND ${SHIELD_AS_LIST}) - -# Use BOARD to search for a '_defconfig' file. -# e.g. zephyr/boards/arm/96b_carbon_nrf51/96b_carbon_nrf51_defconfig. -# When found, use that path to infer the ARCH we are building for. -foreach(root ${BOARD_ROOT}) - set(shield_dir ${root}/boards/shields) - # Match the Kconfig.shield files in the shield directories to make sure we are - # finding shields, e.g. x_nucleo_iks01a1/Kconfig.shield - file(GLOB_RECURSE shields_refs_list ${shield_dir}/*/Kconfig.shield) - - # The above gives a list like - # x_nucleo_iks01a1/Kconfig.shield;x_nucleo_iks01a2/Kconfig.shield - # we construct a list of shield names by extracting the folder and find - # and overlay files in there. Each overlay corresponds to a shield. - # We obtain the shield name by removing the overlay extension. - unset(SHIELD_LIST) - foreach(shields_refs ${shields_refs_list}) - get_filename_component(shield_path ${shields_refs} DIRECTORY) - file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay) - foreach(overlay ${shield_overlays}) - get_filename_component(shield ${overlay} NAME_WE) - list(APPEND SHIELD_LIST ${shield}) - set(SHIELD_DIR_${shield} ${shield_path}) - endforeach() - endforeach() - - if(DEFINED SHIELD) - foreach(s ${SHIELD_AS_LIST}) - if(NOT ${s} IN_LIST SHIELD_LIST) - continue() - endif() - - list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) - - # if shield config flag is on, add shield overlay to the shield overlays - # list and dts_fixup file to the shield fixup file - list(APPEND - shield_dts_files - ${SHIELD_DIR_${s}}/${s}.overlay - ) - - list(APPEND - shield_dts_fixups - ${SHIELD_DIR_${s}}/dts_fixup.h - ) - - list(APPEND - SHIELD_DIRS - ${SHIELD_DIR_${s}} - ) - - # search for shield/shield.conf file - if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) - # add shield.conf to the shield config list - list(APPEND - shield_conf_files - ${SHIELD_DIR_${s}}/${s}.conf - ) - endif() - - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards - DTS shield_dts_files - KCONF shield_conf_files - ) - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} - DTS shield_dts_files - KCONF shield_conf_files - ) - endforeach() - endif() -endforeach() - -if(NOT BOARD_DIR) - message("No board named '${BOARD}' found. - -Please choose one of the following boards: -") - execute_process( - COMMAND - ${CMAKE_COMMAND} - -DZEPHYR_BASE=${ZEPHYR_BASE} - -DBOARD_ROOT=${BOARD_ROOT} - -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} - -P ${ZEPHYR_BASE}/cmake/boards.cmake - ) - unset(CACHED_BOARD CACHE) - message(FATAL_ERROR "Invalid BOARD; see above.") -endif() - -if(DEFINED SHIELD AND NOT (SHIELD-NOTFOUND STREQUAL "")) - foreach (s ${SHIELD-NOTFOUND}) - message("No shield named '${s}' found") - endforeach() - message("Please choose from among the following shields:") - string(REPLACE ";" "\\;" SHIELD_LIST_ESCAPED "${SHIELD_LIST}") - execute_process( - COMMAND - ${CMAKE_COMMAND} - -DZEPHYR_BASE=${ZEPHYR_BASE} - -DSHIELD_LIST=${SHIELD_LIST_ESCAPED} - -P ${ZEPHYR_BASE}/cmake/shields.cmake - ) - unset(CACHED_SHIELD CACHE) - message(FATAL_ERROR "Invalid SHIELD; see above.") -endif() - +include(${ZEPHYR_BASE}/cmake/boards.cmake) +include(${ZEPHYR_BASE}/cmake/shields.cmake) include(${ZEPHYR_BASE}/cmake/arch.cmake) if(DEFINED APPLICATION_CONFIG_DIR) diff --git a/cmake/boards.cmake b/cmake/boards.cmake index 16216c4f2a5..1ddca18c59d 100644 --- a/cmake/boards.cmake +++ b/cmake/boards.cmake @@ -1,40 +1,152 @@ # SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA -set(arch_root_args) -foreach(root ${ARCH_ROOT}) - list(APPEND arch_root_args "--arch-root=${root}") -endforeach() +# Validate board and setup boards target. +# +# This CMake module will validate the BOARD argument as well as splitting the +# BOARD argument into and . +# +# If a board implementation is not found for the specified board an error will +# be raised and list of valid boards will be printed. +# +# If user provided board is a board alias, the board will be adjusted to real +# board name. +# +# If board name is deprecated, then board will be adjusted to new board name and +# a deprecation warning will be printed to the user. +# +# Outcome: +# The following variables will be defined when this CMake module completes: +# +# - BOARD: Board, without revision field. +# - BOARD_REVISION: Board revision +# - BOARD_DIR: Board directory with the implementation for selected board +# - ARCH_DIR: Arch dir for extracted from selected board +# - BOARD_ROOT: BOARD_ROOT with ZEPHYR_BASE appended +# +# The following targets will be defined when this CMake module completes: +# - board : when invoked a list of valid boards will be printed +# +# Required variables: +# - BOARD: Board name, including any optional revision field, for example: `foo` or `foo@1.0.0` +# +# Optional variables: +# - BOARD_ROOT: CMake list of board roots containing board implementations +# - ARCH_ROOT: CMake list of arch roots containing arch implementations +# +# Optional environment variables: +# - ZEPHYR_BOARD_ALIASES: Environment setting pointing to a CMake file +# containing board aliases. +# +# Variables set by this module and not mentioned above are considered internal +# use only and may be removed, renamed, or re-purposed without prior notice. + +# Check that BOARD has been provided, and that it has not changed. +# If user tries to change the BOARD, the BOARD value is reset to the BOARD_CACHED value. +zephyr_check_cache(BOARD REQUIRED) + +# 'BOARD_ROOT' is a prioritized list of directories where boards may +# be found. It always includes ${ZEPHYR_BASE} at the lowest priority. +list(APPEND BOARD_ROOT ${ZEPHYR_BASE}) + +string(FIND "${BOARD}" "@" REVISION_SEPARATOR_INDEX) +if(NOT (REVISION_SEPARATOR_INDEX EQUAL -1)) + math(EXPR BOARD_REVISION_INDEX "${REVISION_SEPARATOR_INDEX} + 1") + string(SUBSTRING ${BOARD} ${BOARD_REVISION_INDEX} -1 BOARD_REVISION) + string(SUBSTRING ${BOARD} 0 ${REVISION_SEPARATOR_INDEX} BOARD) +endif() + +if(DEFINED ENV{ZEPHYR_BOARD_ALIASES}) + include($ENV{ZEPHYR_BOARD_ALIASES}) + if(${BOARD}_BOARD_ALIAS) + set(BOARD_ALIAS ${BOARD} CACHE STRING "Board alias, provided by user") + set(BOARD ${${BOARD}_BOARD_ALIAS}) + message(STATUS "Aliased BOARD=${BOARD_ALIAS} changed to ${BOARD}") + endif() +endif() +include(${ZEPHYR_BASE}/boards/deprecated.cmake) +if(${BOARD}_DEPRECATED) + set(BOARD_DEPRECATED ${BOARD} CACHE STRING "Deprecated board name, provided by user") + set(BOARD ${${BOARD}_DEPRECATED}) + message(WARNING "Deprecated BOARD=${BOARD_DEPRECATED} name specified, board automatically changed to: ${BOARD}.") +endif() + +zephyr_boilerplate_watch(BOARD) -set(board_root_args) foreach(root ${BOARD_ROOT}) - list(APPEND board_root_args "--board-root=${root}") + # Check that the board root looks reasonable. + if(NOT IS_DIRECTORY "${root}/boards") + message(WARNING "BOARD_ROOT element without a 'boards' subdirectory: +${root} +Hints: + - if your board directory is '/foo/bar/boards//my_board' then add '/foo/bar' to BOARD_ROOT, not the entire board directory + - if in doubt, use absolute paths") + endif() + + # NB: find_path will return immediately if the output variable is + # already set + if (BOARD_ALIAS) + find_path(BOARD_HIDDEN_DIR + NAMES ${BOARD_ALIAS}_defconfig + PATHS ${root}/boards/*/* + NO_DEFAULT_PATH + ) + if(BOARD_HIDDEN_DIR) + message("Board alias ${BOARD_ALIAS} is hiding the real board of same name") + endif() + endif() + find_path(BOARD_DIR + NAMES ${BOARD}_defconfig + PATHS ${root}/boards/*/* + NO_DEFAULT_PATH + ) + if(BOARD_DIR AND NOT (${root} STREQUAL ${ZEPHYR_BASE})) + set(USING_OUT_OF_TREE_BOARD 1) + endif() endforeach() +if(EXISTS ${BOARD_DIR}/revision.cmake) + # Board provides revision handling. + include(${BOARD_DIR}/revision.cmake) +elseif(BOARD_REVISION) + message(WARNING "Board revision ${BOARD_REVISION} specified for ${BOARD}, \ + but board has no revision so revision will be ignored.") +endif() + +set(board_message "Board: ${BOARD}") + +if(DEFINED BOARD_REVISION) + set(board_message "${board_message}, Revision: ${BOARD_REVISION}") + if(DEFINED ACTIVE_BOARD_REVISION) + set(board_message "${board_message} (Active: ${ACTIVE_BOARD_REVISION})") + set(BOARD_REVISION ${ACTIVE_BOARD_REVISION}) + endif() + + string(REPLACE "." "_" BOARD_REVISION_STRING ${BOARD_REVISION}) +endif() + +message(STATUS "${board_message}") + +# Prepare boards usage command printing. +# This command prints all boards in the system in the following cases: +# - User specifies an invalid BOARD +# - User invokes ' boards' target +list(TRANSFORM ARCH_ROOT PREPEND "--arch-root=" OUTPUT_VARIABLE arch_root_args) +list(TRANSFORM BOARD_ROOT PREPEND "--board-root=" OUTPUT_VARIABLE board_root_args) + set(list_boards_commands - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/list_boards.py - ${arch_root_args} ${board_root_args} + COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/list_boards.py + ${arch_root_args} ${board_root_args} ) -if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE) -# If this file is invoked as a script directly with -P: -# cmake [options] -P board.cmake -# Note that CMAKE_PARENT_LIST_FILE not being set ensures that this present -# file is being invoked directly with -P, and not via an include directive from -# some other script - -# The options available are: -# ARCH_ROOT: Semi-colon separated arch roots -# BOARD_ROOT: Semi-colon separated board roots -# FILE_OUT: Set to a file path to save the boards to a file. If not defined the -# the contents will be printed to stdout -cmake_minimum_required(VERSION 3.20.0) - -set(NO_BOILERPLATE TRUE) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) - -if (FILE_OUT) - list(APPEND list_boards_commands OUTPUT_FILE "${FILE_OUT}") +if(NOT BOARD_DIR) + message("No board named '${BOARD}' found.\n\n" + "Please choose one of the following boards:\n" + ) + execute_process(${list_boards_commands}) + unset(CACHED_BOARD CACHE) + message(FATAL_ERROR "Invalid BOARD; see above.") endif() -execute_process(${list_boards_commands}) -endif() +add_custom_target(boards ${list_boards_commands} USES_TERMINAL) diff --git a/cmake/shields.cmake b/cmake/shields.cmake index 2ea062bdc60..35a2ae56dc1 100644 --- a/cmake/shields.cmake +++ b/cmake/shields.cmake @@ -1,18 +1,136 @@ -if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE) - # This file was invoked as a script directly with -P: - # cmake -P shields.cmake - # - # Unlike boards.cmake, this takes no OUTPUT_FILE option, but - # SHIELD_LIST_SPACE_SEPARATED is required. - list(SORT SHIELD_LIST) - foreach(shield ${SHIELD_LIST}) - message("${shield}") - endforeach() -else() - # This file was included into usage.cmake. - set(sorted_shield_list ${SHIELD_LIST}) - list(SORT sorted_shield_list) - foreach(shield ${sorted_shield_list}) - list(APPEND sorted_shield_cmds COMMAND ${CMAKE_COMMAND} -E echo "${shield}") - endforeach() +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Validate shields and setup shields target. +# +# This module will validate the SHIELD argument. +# +# If a shield implementation is not found for one of the specified shields an +# error will be raised and list of valid shields will be printed. +# +# Outcome: +# The following variables will be defined when this module completes: +# - shield_conf_files: List of shield specific Kconfig fragments +# - shield_dts_files : List of shield specific devicetree files +# - shield_dts_fixups: List of shield specific devicetree fixups +# - SHIELD_AS_LIST : A CMake list of shields created from SHIELD variable. +# +# Optional variables: +# - BOARD_ROOT: CMake list of board roots containing board implementations +# +# Variables set by this module and not mentioned above are considered internal +# use only and may be removed, renamed, or re-purposed without prior notice. + +# Check that SHIELD has not changed. +zephyr_check_cache(SHIELD WATCH) + +if(SHIELD) + message(STATUS "Shield(s): ${SHIELD}") endif() + +if(DEFINED SHIELD) + string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}") +endif() +# SHIELD-NOTFOUND is a real CMake list, from which valid shields can be popped. +# After processing all shields, only invalid shields will be left in this list. +set(SHIELD-NOTFOUND ${SHIELD_AS_LIST}) + +# Use BOARD to search for a '_defconfig' file. +# e.g. zephyr/boards/arm/96b_carbon_nrf51/96b_carbon_nrf51_defconfig. +# When found, use that path to infer the ARCH we are building for. +foreach(root ${BOARD_ROOT}) + set(shield_dir ${root}/boards/shields) + # Match the Kconfig.shield files in the shield directories to make sure we are + # finding shields, e.g. x_nucleo_iks01a1/Kconfig.shield + file(GLOB_RECURSE shields_refs_list ${shield_dir}/*/Kconfig.shield) + + # The above gives a list like + # x_nucleo_iks01a1/Kconfig.shield;x_nucleo_iks01a2/Kconfig.shield + # we construct a list of shield names by extracting the folder and find + # and overlay files in there. Each overlay corresponds to a shield. + # We obtain the shield name by removing the overlay extension. + unset(SHIELD_LIST) + foreach(shields_refs ${shields_refs_list}) + get_filename_component(shield_path ${shields_refs} DIRECTORY) + file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay) + foreach(overlay ${shield_overlays}) + get_filename_component(shield ${overlay} NAME_WE) + list(APPEND SHIELD_LIST ${shield}) + set(SHIELD_DIR_${shield} ${shield_path}) + endforeach() + endforeach() + + if(DEFINED SHIELD) + foreach(s ${SHIELD_AS_LIST}) + if(NOT ${s} IN_LIST SHIELD_LIST) + continue() + endif() + + list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) + + # if shield config flag is on, add shield overlay to the shield overlays + # list and dts_fixup file to the shield fixup file + list(APPEND + shield_dts_files + ${SHIELD_DIR_${s}}/${s}.overlay + ) + + list(APPEND + shield_dts_fixups + ${SHIELD_DIR_${s}}/dts_fixup.h + ) + + list(APPEND + SHIELD_DIRS + ${SHIELD_DIR_${s}} + ) + + # search for shield/shield.conf file + if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) + # add shield.conf to the shield config list + list(APPEND + shield_conf_files + ${SHIELD_DIR_${s}}/${s}.conf + ) + endif() + + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards + DTS shield_dts_files + KCONF shield_conf_files + ) + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} + DTS shield_dts_files + KCONF shield_conf_files + ) + endforeach() + endif() +endforeach() + +# Prepare shield usage command printing. +# This command prints all ishield in the system in the following cases: +# - User specifies an invalid SHIELD +# - User invokes ' shields' target +list(SORT SHIELD_LIST) + +if(DEFINED SHIELD AND NOT (SHIELD-NOTFOUND STREQUAL "")) + # Convert the list to pure string with newlines for printing. + string(REPLACE ";" "\n" shield_string "${SHIELD_LIST}") + + foreach (s ${SHIELD-NOTFOUND}) + message("No shield named '${s}' found") + endforeach() + message("Please choose from among the following shields:\n" + "${shield_string}" + ) + unset(CACHED_SHIELD CACHE) + message(FATAL_ERROR "Invalid SHIELD; see above.") +endif() + +# Prepend each shield with COMMAND -E echo " for printing. +# Each shield is printed as new command because build files are not fond of newlines. +list(TRANSFORM SHIELD_LIST PREPEND "COMMAND;${CMAKE_COMMAND};-E;echo;" + OUTPUT_VARIABLE shields_target_cmd +) + +add_custom_target(shields ${shields_target_cmd} USES_TERMINAL) diff --git a/cmake/usage/CMakeLists.txt b/cmake/usage/CMakeLists.txt index 88ccbd79843..5205b71353b 100644 --- a/cmake/usage/CMakeLists.txt +++ b/cmake/usage/CMakeLists.txt @@ -1,15 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -include (${ZEPHYR_BASE}/cmake/shields.cmake) -include (${ZEPHYR_BASE}/cmake/boards.cmake) - -# shields.cmake and boards.cmake can be run with cmake -P for printing -# help output on user error when settings BOARD or SHIELD, and -# add_custom_target() is not available in script mode, so we place -# them in here. -add_custom_target(shields ${sorted_shield_cmds} USES_TERMINAL) -add_custom_target(boards ${list_boards_commands} USES_TERMINAL) - add_custom_target( usage ${CMAKE_COMMAND}