blob: 0c00bcedff3d0e414ab17a3cfbb738e0b354877d [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-------------------------------------------------
Gyorgy Szingf934bab2023-08-31 10:48:40 +000019
Gyorgy Szing838c3e52023-08-31 18:24:50 +020020The following variables can be set in cmake or in the environment to configure various aspect of
21building and external component.
22Note: <DEP_NAME> is the name of the dependency as set int the cmake files with all characters
23converted to uppercase.
Gyorgy Szingf934bab2023-08-31 10:48:40 +000024
25``<DEP_NAME>_VERBOSE_CONFIG``
26 Global variable or environment variable.
27 Pass `--trace-expand` to cmake if set.
Gyorgy Szing838c3e52023-08-31 18:24:50 +020028
Gyorgy Szingf934bab2023-08-31 10:48:40 +000029``<DEP_NAME>_VERBOSE_BUILD``
30 Global variable or environment variable.
31 Turn the build step to verbose mode if set.
32
Gyorgy Szing838c3e52023-08-31 18:24:50 +020033``<DEP_NAME>_GENERATOR``
34 Global variable or environment variable.
35 Set the cmake generator to a specific value. If not set, the value of CMAKE_GENERATOR
36 will be used.
Benedek Tomasik90bd41e2021-03-10 11:23:45 +000037#]===]
38
39#[===[.rst:
40.. cmake:command:: LazyFetch_Fetch
41
42 .. code:: cmake
43 LazyFetch_Fetch(DEP_NAME <dependency name> OPTIONS <list of options for FetchContent_Declare>)
44
45 INPUTS:
46 ``DEP_NAME``
47 Unique name for the dependency, used by FetchContent_* functions
48 ``OPTIONS``
49 List of options for FetchContent_Declare, e.g. git url and refspec, check cmake documentations for more
50 information
51 #]===]
52
53function(LazyFetch_Fetch DEP_NAME OPTIONS)
54 include(FetchContent)
55
56 # Fetching dependency
57 FetchContent_Declare(
58 ${DEP_NAME}
59 ${OPTIONS}
60 )
61
62 FetchContent_GetProperties(${DEP_NAME})
63 if(NOT "${DEP_NAME}_POPULATED")
64 message(STATUS "Fetching ${DEP_NAME}")
65 FetchContent_Populate(${DEP_NAME})
66 endif()
67endfunction()
68
69#[===[.rst:
70.. cmake:command:: LazyFetch_ConfigAndBuild
71
72 .. code:: cmake
73 LazyFetch_ConfigAndBuild(DEP_NAME <dependency name> SRC_DIR <source code dir> BIN_DIR <binary dir>
74 CACHE_FILE <path to the initial cache file> INSTALL_DIR <install path>)
75
76 INPUTS:
77 ``DEP_NAME``
78 Unique name for the dependency
79 ``SRC_DIR``
80 Source directory
81 ``BIN_DIR``
82 Build directory
83 ``CACHE_FILE``
84 Path to the initial cache file. Setting cache variables in this file can be used to augment
85 the configure process. The file goes through :cmake:function:`configure_file(... @ONLY)`, this
86 can be used to pass variables to the external project.
87 ``INSTALL_DIR``
88 Install path. If not set, the install step will be skipped.
Gyorgy Szingf934bab2023-08-31 10:48:40 +000089 ``<DEP_NAME>_VERBOSE_CONFIG``
90 Global variable or environment variable.
91 Pass `--trace-expand` to cmake if set.
92 ``<DEP_NAME>_VERBOSE_BUILD``
93 Global variable or environment variable.
94 Turn the build step to verbose mode if set.
Benedek Tomasik90bd41e2021-03-10 11:23:45 +000095 #]===]
96
97function(LazyFetch_ConfigAndBuild)
98 set(oneValueArgs DEP_NAME SRC_DIR BIN_DIR CACHE_FILE INSTALL_DIR)
99 cmake_parse_arguments(BUILD "${__options}" "${oneValueArgs}" "${_multipleValueArgs}" ${ARGN})
100 message(STATUS "Configuring and building ${BUILD_DEP_NAME}")
101
102 # Store config file in build dir, so it gets cleaned up
103 set(CONFIGURED_CACHE_FILE ${CMAKE_BINARY_DIR}/${BUILD_DEP_NAME}-init-cache.cmake)
104 configure_file(${BUILD_CACHE_FILE} ${CONFIGURED_CACHE_FILE} @ONLY)
105
Gyorgy Szing34aaf212022-10-20 07:26:23 +0200106 string(TOUPPER ${BUILD_DEP_NAME} UC_DEP_NAME)
107
108 if (NOT DEFINED ${UC_DEP_NAME}_BUILD_TYPE)
109 message(FATAL_ERROR "Build type for external component ${DEP_NAME} is not set. Please pass "
110 "-D${UC_DEP_NAME}_BUILD_TYPE=<build type> to cmake. Supported build types are"
111 "component specific. Pleas refer to the upstream documentation for more information.")
112 endif()
113
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000114 if (DEFINED ${UC_DEP_NAME}_VERBOSE_CONFIG OR DEFINED ENV{${UC_DEP_NAME}_VERBOSE_CONFIG})
115 set(_CMAKE_VERBOSE_CFG_FLAG "--trace-expand")
116 endif()
117
Gyorgy Szing838c3e52023-08-31 18:24:50 +0200118 if(NOT DEFINED ${UC_DEP_NAME}_GENERATOR)
119 if(DEFINED ENV{${UC_DEP_NAME}_GENERATOR})
120 set(${UC_DEP_NAME}_GENERATOR ENV{${UC_DEP_NAME}_GENERATOR} CACHE STRING "CMake generator used for ${UC_DEP_NAME}.")
121 else()
122 set(${UC_DEP_NAME}_GENERATOR ${CMAKE_GENERATOR} CACHE STRING "CMake generator used for ${UC_DEP_NAME}.")
123 endif()
124 endif()
125
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000126 execute_process(COMMAND
127 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
128 ${CMAKE_COMMAND}
129 "-C${CONFIGURED_CACHE_FILE}"
Gyorgy Szingc3271e72023-04-18 15:44:49 +0200130 -DCMAKE_BUILD_TYPE=${${UC_DEP_NAME}_BUILD_TYPE}
Gyorgy Szing838c3e52023-08-31 18:24:50 +0200131 -G${${UC_DEP_NAME}_GENERATOR}
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000132 -S ${BUILD_SRC_DIR}
133 -B ${BUILD_BIN_DIR}
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000134 ${_CMAKE_VERBOSE_CFG_FLAG}
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000135 RESULT_VARIABLE
136 _exec_error
137 )
138 if (NOT _exec_error EQUAL 0)
139 message(FATAL_ERROR "Configuring ${BUILD_DEP_NAME} build failed. `${_exec_error}`")
140 endif()
141
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000142 if (DEFINED ${UC_DEP_NAME}_VERBOSE_BUILD OR DEFINED ENV{${UC_DEP_NAME}_VERBOSE_BUILD})
143 set(_CMAKE_VERBOSE_CFG_FLAG "--verbose")
144 endif()
145
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000146 if (BUILD_INSTALL_DIR)
147 execute_process(COMMAND
148 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
149 ${CMAKE_COMMAND}
150 --build ${BUILD_BIN_DIR}
151 --parallel ${PROCESSOR_COUNT}
152 --target install
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000153 ${_CMAKE_VERBOSE_BLD_FLAG}
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000154 RESULT_VARIABLE
155 _exec_error
156 )
157 else()
158 execute_process(COMMAND
159 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
160 ${CMAKE_COMMAND}
161 --build ${BUILD_BIN_DIR}
162 --parallel ${PROCESSOR_COUNT}
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000163 ${_CMAKE_VERBOSE_BLD_FLAG}
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000164 RESULT_VARIABLE
165 _exec_error
166 )
167 endif()
168 if (NOT _exec_error EQUAL 0)
169 message(FATAL_ERROR "Building ${BUILD_DEP_NAME} failed. ${_exec_error}")
170 endif()
171endfunction()
172
173#[===[.rst:
174.. cmake:command:: LazyFetch_MakeAvailable
175
176 .. code:: cmake
177 LazyFetch_MakeAvailable(DEP_NAME <dependency name> INSTALL_DIR <install path>
178 PACKAGE_DIR <directory of moduleConfig.cmake file>
179 CACHE_FILE <path to the cache init file> FETCH_OPTIONS <options for the fetching process>)
180
181 INPUTS:
182 ``DEP_NAME``
183 If set, this path overwrites the default base path for the FetchContent process
184 ``SOURCE_DIR``
185 Location of source code.
186 ``INSTALL_DIR``
187 Build install path
188 ``PACKAGE_DIR``
189 If set find_package will search this directory for the config file
190 ``CACHE_FILE``
191 Path to the cache init file, setting cache variables in this file can be used to augment the
192 configure process. The file goes through the :cmake:function:`configure_file(... @ONLY)`, this
193 can be used to pass variables to the cache file
194 ``FETCH_OPTIONS``
195 Configure the dependency fetching process, this is passed to FetchContent_Declare, check the
196 cmake documentation for more info
197 ``SOURCE_SUBDIR``
198 A subdirectory relative to the top level directory of the fetched component, where the CMakeLists.txt file
199 can be found.
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000200 ``<DEP_NAME>_VERBOSE_CONFIG``
201 Global variable or environment variable.
202 Pass `--trace-expand` to cmake if set.
203 ``<DEP_NAME>_VERBOSE_BUILD``
204 Global variable or environment variable.
205 Turn the build step to verbose mode if set.
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000206 #]===]
207
208macro(LazyFetch_MakeAvailable)
209 set(oneValueArgs DEP_NAME SOURCE_DIR BINARY_DIR INSTALL_DIR PACKAGE_DIR CACHE_FILE SOURCE_SUBDIR)
210 set(multipleValueArgs FETCH_OPTIONS)
211 cmake_parse_arguments(MY "${__options}" "${oneValueArgs}" "${multipleValueArgs}" ${ARGN})
212 message(STATUS "Looking for dependency ${MY_DEP_NAME}")
213
214 if (NOT DEFINED MY_DEP_NAME)
215 message(FATAL_ERROR "Mandatory parameter DEP_NAME is missing.")
216 endif()
217
218 # FetchContent* functions use this form
219 string(TOLOWER ${MY_DEP_NAME} MY_LC_DEP_NAME)
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000220 # We also need the upper case version
221 string(TOUPPER ${MY_DEP_NAME} MY_UC_DEP_NAME)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000222
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000223 # Look for name collision. We can collide with project() commands, other external components defined with
224 # LazyFetch, FetchCOntent or ExternalProject.
225 if(DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR AND NOT DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
226 string(CONCAT _msg "External dependency name \"${MY_DEP_NAME}\" collides with a project or another external"
227 " dependency name.")
228 message(FATAL_ERROR ${_msg})
229 endif()
230 # This variable is used to avoid false colision detection when re-configuring the project.
231 set(${MY_LC_DEP_NAME}_BINARY_DIR_LZF On CACHE BOOL "")
232 mark_as_advanced(${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000233 # These two variables are also set by the normal FetchContent process and users could depend on them,
234 # so they are not unset at the end of the macro
235 if (MY_BINARY_DIR)
236 set(${MY_LC_DEP_NAME}_BINARY_DIR ${MY_BINARY_DIR})
237 else()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000238 set(${MY_LC_DEP_NAME}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-build)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000239 endif()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000240 set(${MY_LC_DEP_NAME}_BINARY_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR} CACHE PATH
241 "Build directory for ${MY_LC_DEP_NAME}" FORCE)
242
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000243 if (MY_SOURCE_DIR)
244 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${MY_SOURCE_DIR})
245 else()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000246 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-src)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000247 endif()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000248 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR} CACHE PATH
249 "Source directory for ${MY_LC_DEP_NAME}" FORCE)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000250
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000251 set(${MY_LC_DEP_NAME}_SUBBUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-subbuild CACHE
252 STRING "Sub-build directory for ${MY_LC_DEP_NAME}")
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000253
254 list(APPEND MY_FETCH_OPTIONS
255 SOURCE_DIR "${${MY_LC_DEP_NAME}_SOURCE_DIR}"
256 BINARY_DIR "${${MY_LC_DEP_NAME}_BINARY_DIR}"
257 SUBBUILD_DIR "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
258
259 if (NOT DEFINED MY_INSTALL_DIR OR NOT EXISTS ${MY_INSTALL_DIR})
260 if (NOT EXISTS ${${MY_LC_DEP_NAME}_BINARY_DIR} OR NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
261 if (NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
262 LazyFetch_Fetch(${MY_LC_DEP_NAME} "${MY_FETCH_OPTIONS}")
263 file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_BINARY_DIR}")
264 file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
265 endif()
266 if (MY_CACHE_FILE)
267 LazyFetch_ConfigAndBuild(
268 DEP_NAME ${MY_LC_DEP_NAME}
269 SRC_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR}/${MY_SOURCE_SUBDIR}
270 BIN_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR}
271 CACHE_FILE ${MY_CACHE_FILE}
272 INSTALL_DIR ${MY_INSTALL_DIR}
273 )
274 endif()
275 elseif(DEFINED MY_INSTALL_DIR)
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000276 if(DEFINED ${MY_UC_DEP_NAME}_VERBOSE_BUILD OR DEFINED ENV{${MY_UC_DEP_NAME}_VERBOSE_BUILD})
277 set(_CMAKE_VERBOSE_BLD_FLAG "--verbose")
278 endif()
279
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000280 execute_process(COMMAND
281 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
282 ${CMAKE_COMMAND}
283 --build ${${MY_LC_DEP_NAME}_BINARY_DIR}
284 --parallel ${PROCESSOR_COUNT}
285 --target install
Gyorgy Szingf934bab2023-08-31 10:48:40 +0000286 ${_CMAKE_VERBOSE_BLD_FLAG}
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000287 RESULT_VARIABLE
288 _exec_error
289 )
290 if (NOT _exec_error EQUAL 0)
291 message(FATAL_ERROR "Installing ${BUILD_DEP_NAME} failed. ${_exec_error}")
292 endif()
293 endif()
294 endif()
295
296 # Run find_package again if we just needed the build and install step
297 if (MY_PACKAGE_DIR)
298 unset(${MY_LC_DEP_NAME}_DIR)
299 unset(${MY_LC_DEP_NAME}_DIR CACHE)
300 unset(${MY_DEP_NAME}-FOUND CACHE)
301 find_package(${MY_DEP_NAME} CONFIG REQUIRED NO_DEFAULT_PATH PATHS ${MY_PACKAGE_DIR})
302 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MY_DEP_NAME}_CONFIG)
303 endif()
304
305 unset(MY_DEP_NAME)
306 unset(MY_SOURCE_DIR)
307 unset(MY_BINARY_DIR)
308 unset(MY_INSTALL_DIR)
309 unset(MY_PACKAGE_DIR)
310 unset(MY_CACHE_FILE)
311 unset(MY_SOURCE_SUBDIR)
312 unset(MY_FETCH_OPTIONS)
313 unset(MY_LC_DEP_NAME)
314 unset(oneValueArgs)
315 unset(multipleValueArgs)
316endmacro()