blob: 54200c247da1ea20aad1c5344ad61c2776a85353 [file] [log] [blame]
Benedek Tomasik90bd41e2021-03-10 11:23:45 +00001#-------------------------------------------------------------------------------
2# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
3#
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
82 execute_process(COMMAND
83 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
84 ${CMAKE_COMMAND}
85 "-C${CONFIGURED_CACHE_FILE}"
86 -S ${BUILD_SRC_DIR}
87 -B ${BUILD_BIN_DIR}
88 RESULT_VARIABLE
89 _exec_error
90 )
91 if (NOT _exec_error EQUAL 0)
92 message(FATAL_ERROR "Configuring ${BUILD_DEP_NAME} build failed. `${_exec_error}`")
93 endif()
94
95 if (BUILD_INSTALL_DIR)
96 execute_process(COMMAND
97 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
98 ${CMAKE_COMMAND}
99 --build ${BUILD_BIN_DIR}
100 --parallel ${PROCESSOR_COUNT}
101 --target install
102 RESULT_VARIABLE
103 _exec_error
104 )
105 else()
106 execute_process(COMMAND
107 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
108 ${CMAKE_COMMAND}
109 --build ${BUILD_BIN_DIR}
110 --parallel ${PROCESSOR_COUNT}
111 RESULT_VARIABLE
112 _exec_error
113 )
114 endif()
115 if (NOT _exec_error EQUAL 0)
116 message(FATAL_ERROR "Building ${BUILD_DEP_NAME} failed. ${_exec_error}")
117 endif()
118endfunction()
119
120#[===[.rst:
121.. cmake:command:: LazyFetch_MakeAvailable
122
123 .. code:: cmake
124 LazyFetch_MakeAvailable(DEP_NAME <dependency name> INSTALL_DIR <install path>
125 PACKAGE_DIR <directory of moduleConfig.cmake file>
126 CACHE_FILE <path to the cache init file> FETCH_OPTIONS <options for the fetching process>)
127
128 INPUTS:
129 ``DEP_NAME``
130 If set, this path overwrites the default base path for the FetchContent process
131 ``SOURCE_DIR``
132 Location of source code.
133 ``INSTALL_DIR``
134 Build install path
135 ``PACKAGE_DIR``
136 If set find_package will search this directory for the config file
137 ``CACHE_FILE``
138 Path to the cache init file, setting cache variables in this file can be used to augment the
139 configure process. The file goes through the :cmake:function:`configure_file(... @ONLY)`, this
140 can be used to pass variables to the cache file
141 ``FETCH_OPTIONS``
142 Configure the dependency fetching process, this is passed to FetchContent_Declare, check the
143 cmake documentation for more info
144 ``SOURCE_SUBDIR``
145 A subdirectory relative to the top level directory of the fetched component, where the CMakeLists.txt file
146 can be found.
147 #]===]
148
149macro(LazyFetch_MakeAvailable)
150 set(oneValueArgs DEP_NAME SOURCE_DIR BINARY_DIR INSTALL_DIR PACKAGE_DIR CACHE_FILE SOURCE_SUBDIR)
151 set(multipleValueArgs FETCH_OPTIONS)
152 cmake_parse_arguments(MY "${__options}" "${oneValueArgs}" "${multipleValueArgs}" ${ARGN})
153 message(STATUS "Looking for dependency ${MY_DEP_NAME}")
154
155 if (NOT DEFINED MY_DEP_NAME)
156 message(FATAL_ERROR "Mandatory parameter DEP_NAME is missing.")
157 endif()
158
159 # FetchContent* functions use this form
160 string(TOLOWER ${MY_DEP_NAME} MY_LC_DEP_NAME)
161
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000162 # Look for name collision. We can collide with project() commands, other external components defined with
163 # LazyFetch, FetchCOntent or ExternalProject.
164 if(DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR AND NOT DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
165 string(CONCAT _msg "External dependency name \"${MY_DEP_NAME}\" collides with a project or another external"
166 " dependency name.")
167 message(FATAL_ERROR ${_msg})
168 endif()
169 # This variable is used to avoid false colision detection when re-configuring the project.
170 set(${MY_LC_DEP_NAME}_BINARY_DIR_LZF On CACHE BOOL "")
171 mark_as_advanced(${MY_LC_DEP_NAME}_BINARY_DIR_LZF)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000172 # These two variables are also set by the normal FetchContent process and users could depend on them,
173 # so they are not unset at the end of the macro
174 if (MY_BINARY_DIR)
175 set(${MY_LC_DEP_NAME}_BINARY_DIR ${MY_BINARY_DIR})
176 else()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000177 set(${MY_LC_DEP_NAME}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-build)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000178 endif()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000179 set(${MY_LC_DEP_NAME}_BINARY_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR} CACHE PATH
180 "Build directory for ${MY_LC_DEP_NAME}" FORCE)
181
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000182 if (MY_SOURCE_DIR)
183 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${MY_SOURCE_DIR})
184 else()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000185 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-src)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000186 endif()
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000187 set(${MY_LC_DEP_NAME}_SOURCE_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR} CACHE PATH
188 "Source directory for ${MY_LC_DEP_NAME}" FORCE)
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000189
Gyorgy Szing9882afb2022-07-19 08:13:00 +0000190 set(${MY_LC_DEP_NAME}_SUBBUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-subbuild CACHE
191 STRING "Sub-build directory for ${MY_LC_DEP_NAME}")
Benedek Tomasik90bd41e2021-03-10 11:23:45 +0000192
193 list(APPEND MY_FETCH_OPTIONS
194 SOURCE_DIR "${${MY_LC_DEP_NAME}_SOURCE_DIR}"
195 BINARY_DIR "${${MY_LC_DEP_NAME}_BINARY_DIR}"
196 SUBBUILD_DIR "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
197
198 if (NOT DEFINED MY_INSTALL_DIR OR NOT EXISTS ${MY_INSTALL_DIR})
199 if (NOT EXISTS ${${MY_LC_DEP_NAME}_BINARY_DIR} OR NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
200 if (NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR})
201 LazyFetch_Fetch(${MY_LC_DEP_NAME} "${MY_FETCH_OPTIONS}")
202 file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_BINARY_DIR}")
203 file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}")
204 endif()
205 if (MY_CACHE_FILE)
206 LazyFetch_ConfigAndBuild(
207 DEP_NAME ${MY_LC_DEP_NAME}
208 SRC_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR}/${MY_SOURCE_SUBDIR}
209 BIN_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR}
210 CACHE_FILE ${MY_CACHE_FILE}
211 INSTALL_DIR ${MY_INSTALL_DIR}
212 )
213 endif()
214 elseif(DEFINED MY_INSTALL_DIR)
215 execute_process(COMMAND
216 ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
217 ${CMAKE_COMMAND}
218 --build ${${MY_LC_DEP_NAME}_BINARY_DIR}
219 --parallel ${PROCESSOR_COUNT}
220 --target install
221 RESULT_VARIABLE
222 _exec_error
223 )
224 if (NOT _exec_error EQUAL 0)
225 message(FATAL_ERROR "Installing ${BUILD_DEP_NAME} failed. ${_exec_error}")
226 endif()
227 endif()
228 endif()
229
230 # Run find_package again if we just needed the build and install step
231 if (MY_PACKAGE_DIR)
232 unset(${MY_LC_DEP_NAME}_DIR)
233 unset(${MY_LC_DEP_NAME}_DIR CACHE)
234 unset(${MY_DEP_NAME}-FOUND CACHE)
235 find_package(${MY_DEP_NAME} CONFIG REQUIRED NO_DEFAULT_PATH PATHS ${MY_PACKAGE_DIR})
236 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MY_DEP_NAME}_CONFIG)
237 endif()
238
239 unset(MY_DEP_NAME)
240 unset(MY_SOURCE_DIR)
241 unset(MY_BINARY_DIR)
242 unset(MY_INSTALL_DIR)
243 unset(MY_PACKAGE_DIR)
244 unset(MY_CACHE_FILE)
245 unset(MY_SOURCE_SUBDIR)
246 unset(MY_FETCH_OPTIONS)
247 unset(MY_LC_DEP_NAME)
248 unset(oneValueArgs)
249 unset(multipleValueArgs)
250endmacro()