blob: 68e790e50e60b5dadc2b228e2a27453b7186f817 [file] [log] [blame]
Benedek Tomasik90bd41e2021-03-10 11:23:45 +00001#-------------------------------------------------------------------------------
Gyorgy Szingc3271e72023-04-18 15:44:49 +02002# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
Benedek Tomasik90bd41e2021-03-10 11:23:45 +00003#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#-------------------------------------------------------------------------------
7
8# Determine the number of processes to run while running parallel builds.
9# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
10if(NOT DEFINED PROCESSOR_COUNT)
11 include(ProcessorCount)
12 ProcessorCount(PROCESSOR_COUNT)
13 set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.")
14endif()
15
16#[===[.rst:
17Common fetch interface for external dependencies.
18-------------------------------------------------
19#]===]
20
21#[===[.rst:
22.. cmake:command:: LazyFetch_Fetch
23
24 .. code:: cmake
25 LazyFetch_Fetch(DEP_NAME <dependency name> OPTIONS <list of options for FetchContent_Declare>)
26
27 INPUTS:
28 ``DEP_NAME``
29 Unique name for the dependency, used by FetchContent_* functions
30 ``OPTIONS``
31 List of options for FetchContent_Declare, e.g. git url and refspec, check cmake documentations for more
32 information
33 #]===]
34
35function(LazyFetch_Fetch DEP_NAME OPTIONS)
36 include(FetchContent)
37
38 # Fetching dependency
39 FetchContent_Declare(
40 ${DEP_NAME}
41 ${OPTIONS}
42 )
43
44 FetchContent_GetProperties(${DEP_NAME})
45 if(NOT "${DEP_NAME}_POPULATED")
46 message(STATUS "Fetching ${DEP_NAME}")
47 FetchContent_Populate(${DEP_NAME})
48 endif()
49endfunction()
50
51#[===[.rst:
52.. cmake:command:: LazyFetch_ConfigAndBuild
53
54 .. code:: cmake
55 LazyFetch_ConfigAndBuild(DEP_NAME <dependency name> SRC_DIR <source code dir> BIN_DIR <binary dir>
56 CACHE_FILE <path to the initial cache file> INSTALL_DIR <install path>)
57
58 INPUTS:
59 ``DEP_NAME``
60 Unique name for the dependency
61 ``SRC_DIR``
62 Source directory
63 ``BIN_DIR``
64 Build directory
65 ``CACHE_FILE``
66 Path to the initial cache file. Setting cache variables in this file can be used to augment
67 the configure process. The file goes through :cmake:function:`configure_file(... @ONLY)`, this
68 can be used to pass variables to the external project.
69 ``INSTALL_DIR``
70 Install path. If not set, the install step will be skipped.
71 #]===]
72
73function(LazyFetch_ConfigAndBuild)
74 set(oneValueArgs DEP_NAME SRC_DIR BIN_DIR CACHE_FILE INSTALL_DIR)
75 cmake_parse_arguments(BUILD "${__options}" "${oneValueArgs}" "${_multipleValueArgs}" ${ARGN})
76 message(STATUS "Configuring and building ${BUILD_DEP_NAME}")
77
78 # Store config file in build dir, so it gets cleaned up
79 set(CONFIGURED_CACHE_FILE ${CMAKE_BINARY_DIR}/${BUILD_DEP_NAME}-init-cache.cmake)
80 configure_file(${BUILD_CACHE_FILE} ${CONFIGURED_CACHE_FILE} @ONLY)
81
Gyorgy Szing34aaf212022-10-20 07:26:23 +020082 string(TOUPPER ${BUILD_DEP_NAME} UC_DEP_NAME)
83
84 if (NOT DEFINED ${UC_DEP_NAME}_BUILD_TYPE)
85 message(FATAL_ERROR "Build type for external component ${DEP_NAME} is not set. Please pass "
86 "-D${UC_DEP_NAME}_BUILD_TYPE=<build type> to cmake. Supported build types are"
87 "component specific. Pleas refer to the upstream documentation for more information.")
88 endif()
89
Benedek Tomasik90bd41e2021-03-10 11:23:45 +000090 execute_process(COMMAND
91 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
92 ${CMAKE_COMMAND}
93 "-C${CONFIGURED_CACHE_FILE}"
Gyorgy Szingc3271e72023-04-18 15:44:49 +020094 -DCMAKE_BUILD_TYPE=${${UC_DEP_NAME}_BUILD_TYPE}
Benedek Tomasik90bd41e2021-03-10 11:23:45 +000095 -S ${BUILD_SRC_DIR}
96 -B ${BUILD_BIN_DIR}
97 RESULT_VARIABLE
98 _exec_error
99 )
100 if (NOT _exec_error EQUAL 0)
101 message(FATAL_ERROR "Configuring ${BUILD_DEP_NAME} build failed. `${_exec_error}`")
102 endif()
103
104 if (BUILD_INSTALL_DIR)
105 execute_process(COMMAND
106 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
107 ${CMAKE_COMMAND}
108 --build ${BUILD_BIN_DIR}
109 --parallel ${PROCESSOR_COUNT}
110 --target install
111 RESULT_VARIABLE
112 _exec_error
113 )
114 else()
115 execute_process(COMMAND
116 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
117 ${CMAKE_COMMAND}
118 --build ${BUILD_BIN_DIR}
119 --parallel ${PROCESSOR_COUNT}
120 RESULT_VARIABLE
121 _exec_error
122 )
123 endif()
124 if (NOT _exec_error EQUAL 0)
125 message(FATAL_ERROR "Building ${BUILD_DEP_NAME} failed. ${_exec_error}")
126 endif()
127endfunction()
128
129#[===[.rst:
130.. cmake:command:: LazyFetch_MakeAvailable
131
132 .. code:: cmake
133 LazyFetch_MakeAvailable(DEP_NAME <dependency name> INSTALL_DIR <install path>
134 PACKAGE_DIR <directory of moduleConfig.cmake file>
135 CACHE_FILE <path to the cache init file> FETCH_OPTIONS <options for the fetching process>)
136
137 INPUTS:
138 ``DEP_NAME``
139 If set, this path overwrites the default base path for the FetchContent process
140 ``SOURCE_DIR``
141 Location of source code.
142 ``INSTALL_DIR``
143 Build install path
144 ``PACKAGE_DIR``
145 If set find_package will search this directory for the config file
146 ``CACHE_FILE``
147 Path to the cache init file, setting cache variables in this file can be used to augment the
148 configure process. The file goes through the :cmake:function:`configure_file(... @ONLY)`, this
149 can be used to pass variables to the cache file
150 ``FETCH_OPTIONS``
151 Configure the dependency fetching process, this is passed to FetchContent_Declare, check the
152 cmake documentation for more info
153 ``SOURCE_SUBDIR``
154 A subdirectory relative to the top level directory of the fetched component, where the CMakeLists.txt file
155 can be found.
156 #]===]
157
158macro(LazyFetch_MakeAvailable)
159 set(oneValueArgs DEP_NAME SOURCE_DIR BINARY_DIR INSTALL_DIR PACKAGE_DIR CACHE_FILE SOURCE_SUBDIR)
160 set(multipleValueArgs FETCH_OPTIONS)
161 cmake_parse_arguments(MY "${__options}" "${oneValueArgs}" "${multipleValueArgs}" ${ARGN})
162 message(STATUS "Looking for dependency ${MY_DEP_NAME}")
163
164 if (NOT DEFINED MY_DEP_NAME)
165 message(FATAL_ERROR "Mandatory parameter DEP_NAME is missing.")
166 endif()
167
168 # FetchContent* functions use this form
169 string(TOLOWER ${MY_DEP_NAME} MY_LC_DEP_NAME)
170
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000171 # Look for name collision. We can collide with project() commands, other external components defined with
172 # LazyFetch, FetchCOntent or ExternalProject.
173 if(DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR AND NOT DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
174 string(CONCAT _msg "External dependency name \"${MY_DEP_NAME}\" collides with a project or another external"
175 " dependency name.")
176 message(FATAL_ERROR ${_msg})
177 endif()
178 # This variable is used to avoid false colision detection when re-configuring the project.
179 set(${MY_LC_DEP_NAME}_BINARY_DIR_LZF On CACHE BOOL "")
180 mark_as_advanced(${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000181 # These two variables are also set by the normal FetchContent process and users could depend on them,
182 # so they are not unset at the end of the macro
183 if (MY_BINARY_DIR)
184 set(${MY_LC_DEP_NAME}_BINARY_DIR ${MY_BINARY_DIR})
185 else()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000186 set(${MY_LC_DEP_NAME}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-build)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000187 endif()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000188 set(${MY_LC_DEP_NAME}_BINARY_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR} CACHE PATH
189 "Build directory for ${MY_LC_DEP_NAME}" FORCE)
190
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000191 if (MY_SOURCE_DIR)
192 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${MY_SOURCE_DIR})
193 else()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000194 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-src)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000195 endif()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000196 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR} CACHE PATH
197 "Source directory for ${MY_LC_DEP_NAME}" FORCE)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000198
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000199 set(${MY_LC_DEP_NAME}_SUBBUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-subbuild CACHE
200 STRING "Sub-build directory for ${MY_LC_DEP_NAME}")
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000201
202 list(APPEND MY_FETCH_OPTIONS
203 SOURCE_DIR "${${MY_LC_DEP_NAME}_SOURCE_DIR}"
204 BINARY_DIR "${${MY_LC_DEP_NAME}_BINARY_DIR}"
205 SUBBUILD_DIR "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
206
207 if (NOT DEFINED MY_INSTALL_DIR OR NOT EXISTS ${MY_INSTALL_DIR})
208 if (NOT EXISTS ${${MY_LC_DEP_NAME}_BINARY_DIR} OR NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
209 if (NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
210 LazyFetch_Fetch(${MY_LC_DEP_NAME} "${MY_FETCH_OPTIONS}")
211 file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_BINARY_DIR}")
212 file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
213 endif()
214 if (MY_CACHE_FILE)
215 LazyFetch_ConfigAndBuild(
216 DEP_NAME ${MY_LC_DEP_NAME}
217 SRC_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR}/${MY_SOURCE_SUBDIR}
218 BIN_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR}
219 CACHE_FILE ${MY_CACHE_FILE}
220 INSTALL_DIR ${MY_INSTALL_DIR}
221 )
222 endif()
223 elseif(DEFINED MY_INSTALL_DIR)
224 execute_process(COMMAND
225 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
226 ${CMAKE_COMMAND}
227 --build ${${MY_LC_DEP_NAME}_BINARY_DIR}
228 --parallel ${PROCESSOR_COUNT}
229 --target install
230 RESULT_VARIABLE
231 _exec_error
232 )
233 if (NOT _exec_error EQUAL 0)
234 message(FATAL_ERROR "Installing ${BUILD_DEP_NAME} failed. ${_exec_error}")
235 endif()
236 endif()
237 endif()
238
239 # Run find_package again if we just needed the build and install step
240 if (MY_PACKAGE_DIR)
241 unset(${MY_LC_DEP_NAME}_DIR)
242 unset(${MY_LC_DEP_NAME}_DIR CACHE)
243 unset(${MY_DEP_NAME}-FOUND CACHE)
244 find_package(${MY_DEP_NAME} CONFIG REQUIRED NO_DEFAULT_PATH PATHS ${MY_PACKAGE_DIR})
245 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MY_DEP_NAME}_CONFIG)
246 endif()
247
248 unset(MY_DEP_NAME)
249 unset(MY_SOURCE_DIR)
250 unset(MY_BINARY_DIR)
251 unset(MY_INSTALL_DIR)
252 unset(MY_PACKAGE_DIR)
253 unset(MY_CACHE_FILE)
254 unset(MY_SOURCE_SUBDIR)
255 unset(MY_FETCH_OPTIONS)
256 unset(MY_LC_DEP_NAME)
257 unset(oneValueArgs)
258 unset(multipleValueArgs)
259endmacro()