1# The purpose of this file is to provide search mechanism for locating Zephyr in-work-tree package
2# even when they are not installed into CMake package system
3# Linux/MacOS: ~/.cmake/packages
4# Windows:     Registry database
5
6# Relative directory of workspace project dir as seen from Zephyr package file
7set(WORKSPACE_RELATIVE_DIR "../../../../..")
8
9# Relative directory of Zephyr dir as seen from Zephyr package file
10set(ZEPHYR_RELATIVE_DIR "../../../..")
11
12# This function updates Zephyr_DIR to the point to the candidate dir.
13# For Zephyr 3.0 and earlier, the Zephyr_DIR might in some cases be
14# `Zephyr_DIR-NOTFOUND` or pointing to the Zephyr package including the
15# boilerplate code instead of the Zephyr package of the included boilerplate.
16# This code ensures that when Zephyr releases <=3.0 is loaded, then Zephyr_DIR
17# will point correctly, see also #43094 which relates to this.
18function(set_zephyr_dir zephyr_candidate)
19  get_filename_component(zephyr_candidate_dir "${zephyr_candidate}" DIRECTORY)
20  if(NOT "${zephyr_candidate_dir}" STREQUAL "${Zephyr_DIR}")
21    set(Zephyr_DIR ${zephyr_candidate_dir} CACHE PATH
22        "The directory containing a CMake configuration file for Zephyr." FORCE
23    )
24  endif()
25endfunction()
26
27# This macro returns a list of parent folders to use for later searches.
28macro(get_search_paths START_PATH SEARCH_PATHS PREFERENCE_LIST)
29  get_filename_component(SEARCH_PATH ${START_PATH} DIRECTORY)
30  while(NOT (SEARCH_PATH STREQUAL SEARCH_PATH_PREV))
31    foreach(preference ${PREFERENCE_LIST})
32      list(APPEND SEARCH_PATHS ${SEARCH_PATH}/${preference})
33    endforeach()
34    list(APPEND SEARCH_PATHS ${SEARCH_PATH}/zephyr)
35    list(APPEND SEARCH_PATHS ${SEARCH_PATH})
36    set(SEARCH_PATH_PREV ${SEARCH_PATH})
37    get_filename_component(SEARCH_PATH ${SEARCH_PATH} DIRECTORY)
38  endwhile()
39endmacro()
40
41# This macro can check for additional Zephyr package that has a better match
42# Options:
43# - ZEPHYR_BASE                : Use the specified ZEPHYR_BASE directly.
44# - WORKSPACE_DIR              : Search for projects in specified  workspace.
45# - SEARCH_PARENTS             : Search parent folder of current source file (application)
46#                                to locate in-project-tree Zephyr candidates.
47# - CHECK_ONLY                 : Only set PACKAGE_VERSION_COMPATIBLE to false if a better candidate
48#                                is found, default is to also include the found candidate.
49# - VERSION_CHECK              : This is the version check stage by CMake find package
50# - CANDIDATES_PREFERENCE_LIST : List of candidate to be preferred, if installed
51macro(check_zephyr_package)
52  set(options CHECK_ONLY SEARCH_PARENTS VERSION_CHECK)
53  set(single_args WORKSPACE_DIR ZEPHYR_BASE)
54  set(list_args CANDIDATES_PREFERENCE_LIST)
55  cmake_parse_arguments(CHECK_ZEPHYR_PACKAGE "${options}" "${single_args}" "${list_args}" ${ARGN})
56
57  if(CHECK_ZEPHYR_PACKAGE_ZEPHYR_BASE)
58    set(SEARCH_SETTINGS PATHS ${CHECK_ZEPHYR_PACKAGE_ZEPHYR_BASE} NO_DEFAULT_PATH)
59  endif()
60
61  if(CHECK_ZEPHYR_PACKAGE_WORKSPACE_DIR)
62    set(SEARCH_SETTINGS PATHS ${CHECK_ZEPHYR_PACKAGE_WORKSPACE_DIR}/zephyr ${CHECK_ZEPHYR_PACKAGE_WORKSPACE_DIR} NO_DEFAULT_PATH)
63  endif()
64
65  if(CHECK_ZEPHYR_PACKAGE_SEARCH_PARENTS)
66    get_search_paths(${CMAKE_CURRENT_SOURCE_DIR} SEARCH_PATHS "${CHECK_ZEPHYR_PACKAGE_CANDIDATES_PREFERENCE_LIST}")
67    set(SEARCH_SETTINGS PATHS ${SEARCH_PATHS} NO_DEFAULT_PATH)
68  endif()
69
70  # Searching for version zero means there will be no match, but we obtain
71  # a list of all potential Zephyr candidates in the tree to consider.
72  find_package(Zephyr 0.0.0 EXACT QUIET ${SEARCH_SETTINGS})
73
74  # The find package will also find ourself when searching using installed candidates.
75  # So avoid re-including unless NO_DEFAULT_PATH is set.
76  # NO_DEFAULT_PATH means explicit search and we could be part of a preference list.
77  if(NOT (NO_DEFAULT_PATH IN_LIST SEARCH_SETTINGS))
78    list(REMOVE_ITEM Zephyr_CONSIDERED_CONFIGS ${CMAKE_CURRENT_LIST_DIR}/ZephyrConfig.cmake)
79  endif()
80  list(REMOVE_DUPLICATES Zephyr_CONSIDERED_CONFIGS)
81
82  foreach(ZEPHYR_CANDIDATE ${Zephyr_CONSIDERED_CONFIGS})
83    if(CHECK_ZEPHYR_PACKAGE_WORKSPACE_DIR)
84      # Check is done in Zephyr workspace already, thus check only for pure Zephyr candidates.
85      get_filename_component(CANDIDATE_DIR ${ZEPHYR_CANDIDATE}/${ZEPHYR_RELATIVE_DIR} ABSOLUTE)
86    else()
87      get_filename_component(CANDIDATE_DIR ${ZEPHYR_CANDIDATE}/${WORKSPACE_RELATIVE_DIR} ABSOLUTE)
88    endif()
89
90    if(CHECK_ZEPHYR_PACKAGE_ZEPHYR_BASE)
91        if(CHECK_ZEPHYR_PACKAGE_VERSION_CHECK)
92          string(REGEX REPLACE "\.cmake$" "Version.cmake" ZEPHYR_VERSION_CANDIDATE ${ZEPHYR_CANDIDATE})
93          include(${ZEPHYR_VERSION_CANDIDATE} NO_POLICY_SCOPE)
94          return()
95        else()
96          include(${ZEPHYR_CANDIDATE} NO_POLICY_SCOPE)
97          set_zephyr_dir(${ZEPHYR_CANDIDATE})
98          return()
99        endif()
100    endif()
101
102    string(FIND "${CMAKE_CURRENT_SOURCE_DIR}" "${CANDIDATE_DIR}/" COMMON_INDEX)
103    if (COMMON_INDEX EQUAL 0)
104      if(CHECK_ZEPHYR_PACKAGE_CHECK_ONLY)
105        # A better candidate exists, thus return
106        set(PACKAGE_VERSION_COMPATIBLE FALSE)
107        return()
108      elseif(ZEPHYR_CANDIDATE STREQUAL ${CMAKE_CURRENT_LIST_DIR}/ZephyrConfig.cmake)
109        # Current Zephyr is preferred one, let's just break the loop and continue processing.
110        break()
111      else()
112        if(CHECK_ZEPHYR_PACKAGE_VERSION_CHECK)
113          string(REGEX REPLACE "\.cmake$" "Version.cmake" ZEPHYR_VERSION_CANDIDATE ${ZEPHYR_CANDIDATE})
114          include(${ZEPHYR_VERSION_CANDIDATE} NO_POLICY_SCOPE)
115          return()
116	else()
117          include(${ZEPHYR_CANDIDATE} NO_POLICY_SCOPE)
118          set_zephyr_dir(${ZEPHYR_CANDIDATE})
119	  return()
120        endif()
121      endif()
122    endif()
123  endforeach()
124endmacro()
125