1# SPDX-License-Identifier: Apache-2.0
2#
3# Copyright (c) 2021, Nordic Semiconductor ASA
4
5# Configure user cache directory.
6#
7# The user cache can be used for caching of data that should be persistent
8# across builds to speed up CMake configure / build system generation and/or
9# compilation.
10#
11# Only data that can be safely re-generated should be placed in this cache.
12#
13# Zephyr build system uses this user cache to store Zephyr compiler check
14# results which significantly improve toolchain testing performance.
15# See https://github.com/zephyrproject-rtos/zephyr/pull/7102 for details.
16#
17# Outcome:
18# The following variables will be defined when this CMake module completes:
19#
20# - USER_CACHE_DIR: User cache directory in use.
21#
22# If the above variable is already set when this CMake module is loaded,
23# then no changes to the variable will happen.
24#
25# Variables set by this module and not mentioned above are considered internal
26# use only and may be removed, renamed, or re-purposed without prior notice.
27
28include_guard(GLOBAL)
29
30include(python)
31
32function(find_appropriate_cache_directory dir)
33  set(env_suffix_LOCALAPPDATA   .cache)
34
35  if(CMAKE_HOST_APPLE)
36    # On macOS, ~/Library/Caches is the preferred cache directory.
37    set(env_suffix_HOME Library/Caches)
38  else()
39    set(env_suffix_HOME .cache)
40  endif()
41
42  # Determine which env vars should be checked
43  if(CMAKE_HOST_APPLE)
44    set(dirs HOME)
45  elseif(CMAKE_HOST_WIN32)
46    set(dirs LOCALAPPDATA)
47  else()
48    # Assume Linux when we did not detect 'mac' or 'win'
49    #
50    # On Linux, freedesktop.org recommends using $XDG_CACHE_HOME if
51    # that is defined and defaulting to $HOME/.cache otherwise.
52    set(dirs
53      XDG_CACHE_HOME
54      HOME
55      )
56  endif()
57
58  foreach(env_var ${dirs})
59    if(DEFINED ENV{${env_var}})
60      set(env_dir $ENV{${env_var}})
61
62      string(JOIN "/" test_user_dir ${env_dir} ${env_suffix_${env_var}})
63
64      execute_process(COMMAND ${PYTHON_EXECUTABLE}
65        ${ZEPHYR_BASE}/scripts/build/dir_is_writeable.py ${test_user_dir}
66        RESULT_VARIABLE writable_result
67      )
68      if("${writable_result}" STREQUAL "0")
69        # The directory is write-able
70        set(user_dir ${test_user_dir})
71        break()
72      else()
73        # The directory was not writeable, keep looking for a suitable
74        # directory
75      endif()
76    endif()
77  endforeach()
78
79  # Populate local_dir with a suitable directory for caching
80  # files. Prefer a directory outside of the git repository because it
81  # is good practice to have clean git repositories.
82  if(DEFINED user_dir)
83    # Zephyr's cache files go in the "zephyr" subdirectory of the
84    # user's cache directory.
85    set(local_dir ${user_dir}/zephyr)
86  else()
87    set(local_dir ${ZEPHYR_BASE}/.cache)
88  endif()
89
90  set(${dir} ${local_dir} PARENT_SCOPE)
91endfunction()
92
93# Populate USER_CACHE_DIR with a directory that user applications may
94# write cache files to.
95if(NOT DEFINED USER_CACHE_DIR)
96  find_appropriate_cache_directory(USER_CACHE_DIR)
97endif()
98message(STATUS "Cache files will be written to: ${USER_CACHE_DIR}")
99