1# SPDX-License-Identifier: Apache-2.0
2
3# This file provides Zephyr Config Package functionality.
4#
5# The purpose of this files is to allow users to decide if they want to:
6# - Use ZEPHYR_BASE environment setting for explicitly set select a zephyr installation
7# - Support automatic Zephyr installation lookup through the use of find_package(ZEPHYR)
8
9# First check to see if user has provided a Zephyr base manually.
10# Set Zephyr base to environment setting.
11# It will be empty if not set in environment.
12
13# Internal Zephyr CMake package message macro.
14#
15# This macro is only intended to be used within the Zephyr CMake package.
16# The function `find_package()` supports an optional QUIET argument, and to
17# honor that argument, the package_message() macro will not print messages when
18# said flag has been given.
19#
20# Arguments to zephyr_package_message() are identical to regular CMake message()
21# function.
22macro(zephyr_package_message)
23  if(NOT Zephyr_FIND_QUIETLY)
24    message(${ARGN})
25  endif()
26endmacro()
27
28macro(include_boilerplate location)
29  set(Zephyr_DIR ${ZEPHYR_BASE}/share/zephyr-package/cmake CACHE PATH
30      "The directory containing a CMake configuration file for Zephyr." FORCE
31  )
32  list(PREPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/cmake/modules)
33  if(ZEPHYR_UNITTEST)
34    zephyr_package_message(DEPRECATION "The ZephyrUnittest CMake package has been deprecated.\n"
35                           "ZephyrUnittest has been replaced with Zephyr CMake module 'unittest' \n"
36                           "and can be loaded as: 'find_package(Zephyr COMPONENTS unittest)'"
37    )
38    set(ZephyrUnittest_FOUND True)
39    set(Zephyr_FIND_COMPONENTS unittest)
40  else()
41    set(Zephyr_FOUND True)
42  endif()
43
44  if(NOT DEFINED APPLICATION_SOURCE_DIR)
45    set(APPLICATION_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
46        "Application Source Directory"
47    )
48  endif()
49
50  if(NOT DEFINED APPLICATION_BINARY_DIR)
51    set(APPLICATION_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH
52        "Application Binary Directory"
53    )
54  endif()
55
56  set(__build_dir ${APPLICATION_BINARY_DIR}/zephyr)
57  set(PROJECT_BINARY_DIR ${__build_dir})
58
59  if(NOT NO_BOILERPLATE)
60    list(LENGTH Zephyr_FIND_COMPONENTS components_length)
61    # The module messages are intentionally higher than STATUS to avoid the -- prefix
62    # and make them more visible to users. This does result in them being output
63    # to stderr, but that is an implementation detail of cmake.
64    if(components_length EQUAL 0)
65      zephyr_package_message(NOTICE "Loading Zephyr default modules (${location}).")
66      include(zephyr_default NO_POLICY_SCOPE)
67    else()
68      string(JOIN " " msg_components ${Zephyr_FIND_COMPONENTS})
69      zephyr_package_message(NOTICE "Loading Zephyr module(s) (${location}): ${msg_components}")
70      foreach(component ${Zephyr_FIND_COMPONENTS})
71        if(${component} MATCHES "^\([^:]*\):\(.*\)$")
72          string(REPLACE "," ";" SUB_COMPONENTS ${CMAKE_MATCH_2})
73          set(component ${CMAKE_MATCH_1})
74        endif()
75        include(${component})
76      endforeach()
77    endif()
78  else()
79    zephyr_package_message(DEPRECATION "The NO_BOILERPLATE setting has been deprecated.\n"
80                           "Please use: 'find_package(Zephyr COMPONENTS <components>)'"
81    )
82  endif()
83endmacro()
84
85set(ENV_ZEPHYR_BASE $ENV{ZEPHYR_BASE})
86if((NOT DEFINED ZEPHYR_BASE) AND (DEFINED ENV_ZEPHYR_BASE))
87  # Get rid of any double folder string before comparison, as example, user provides
88  # ZEPHYR_BASE=//path/to//zephyr_base/
89  # must also work.
90  get_filename_component(ZEPHYR_BASE ${ENV_ZEPHYR_BASE} ABSOLUTE)
91  set(ZEPHYR_BASE ${ZEPHYR_BASE} CACHE PATH "Zephyr base")
92  include_boilerplate("Zephyr base")
93  return()
94endif()
95
96if (DEFINED ZEPHYR_BASE)
97  include_boilerplate("Zephyr base (cached)")
98  return()
99endif()
100
101# If ZEPHYR_CANDIDATE is set, it means this file was include instead of called via find_package directly.
102if(ZEPHYR_CANDIDATE)
103  set(IS_INCLUDED TRUE)
104else()
105  include(${CMAKE_CURRENT_LIST_DIR}/zephyr_package_search.cmake)
106endif()
107
108# Find out the current Zephyr base.
109get_filename_component(CURRENT_ZEPHYR_DIR ${CMAKE_CURRENT_LIST_FILE}/${ZEPHYR_RELATIVE_DIR} ABSOLUTE)
110get_filename_component(CURRENT_WORKSPACE_DIR ${CMAKE_CURRENT_LIST_FILE}/${WORKSPACE_RELATIVE_DIR} ABSOLUTE)
111
112string(FIND "${CMAKE_CURRENT_SOURCE_DIR}" "${CURRENT_ZEPHYR_DIR}/" COMMON_INDEX)
113if (COMMON_INDEX EQUAL 0)
114  # Project is in Zephyr repository.
115  # We are in Zephyr repository.
116  set(ZEPHYR_BASE ${CURRENT_ZEPHYR_DIR} CACHE PATH "Zephyr base")
117  include_boilerplate("Zephyr repository")
118  return()
119endif()
120
121if(IS_INCLUDED)
122  # A higher level did the checking and included us and as we are not in Zephyr repository
123  # (checked above) then we must be in Zephyr workspace.
124  set(ZEPHYR_BASE ${CURRENT_ZEPHYR_DIR} CACHE PATH "Zephyr base")
125  include_boilerplate("Zephyr workspace")
126endif()
127
128if(NOT IS_INCLUDED)
129  string(FIND "${CMAKE_CURRENT_SOURCE_DIR}" "${CURRENT_WORKSPACE_DIR}/" COMMON_INDEX)
130  if (COMMON_INDEX EQUAL 0)
131    # Project is in Zephyr workspace.
132    # This means this Zephyr is likely the correct one, but there could be an alternative installed along-side
133    # Thus, check if there is an even better candidate.
134    # This check works the following way.
135    # CMake finds packages will look all packages registered in the user package registry.
136    # As this code is processed inside registered packages, we simply test if another package has a
137    # common path with the current sample.
138    # and if so, we will return here, and let CMake call into the other registered package for real
139    # version checking.
140    check_zephyr_package(WORKSPACE_DIR ${CURRENT_WORKSPACE_DIR})
141
142    if(ZEPHYR_PREFER)
143      check_zephyr_package(SEARCH_PARENTS CANDIDATES_PREFERENCE_LIST ${ZEPHYR_PREFER})
144    endif()
145
146    # We are the best candidate, so let's include boiler plate.
147    set(ZEPHYR_BASE ${CURRENT_ZEPHYR_DIR} CACHE PATH "Zephyr base")
148    include_boilerplate("Zephyr workspace")
149    return()
150  endif()
151
152  check_zephyr_package(SEARCH_PARENTS CANDIDATES_PREFERENCE_LIST ${ZEPHYR_PREFER})
153
154  # Ending here means there were no candidates in workspace of the app.
155  # Thus, the app is built as a Zephyr Freestanding application.
156  # CMake find_package has already done the version checking, so let's just include boiler plate.
157  # Previous find_package would have cleared Zephyr_FOUND variable, thus set it again.
158  set(ZEPHYR_BASE ${CURRENT_ZEPHYR_DIR} CACHE PATH "Zephyr base")
159  include_boilerplate("Freestanding")
160endif()
161