#------------------------------------------------------------------------------- # Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # #------------------------------------------------------------------------------- # Determine the number of processes to run while running parallel builds. # Pass -DPROCESSOR_COUNT= to cmake to override. if(NOT DEFINED PROCESSOR_COUNT) include(ProcessorCount) ProcessorCount(PROCESSOR_COUNT) set(PROCESSOR_COUNT ${PROCESSOR_COUNT} CACHE STRING "Number of cores to use for parallel builds.") endif() #[===[.rst: Common fetch interface for external dependencies. ------------------------------------------------- The following variables can be set in cmake or in the environment to configure various aspect of building and external component. Note: is the name of the dependency as set int the cmake files with all characters converted to uppercase. ``_VERBOSE_CONFIG`` Global variable or environment variable. Pass `--trace-expand` to cmake if set. ``_VERBOSE_BUILD`` Global variable or environment variable. Turn the build step to verbose mode if set. ``_GENERATOR`` Global variable or environment variable. Set the cmake generator to a specific value. If not set, the value of CMAKE_GENERATOR will be used. #]===] #[===[.rst: .. cmake:command:: LazyFetch_Fetch .. code:: cmake LazyFetch_Fetch(DEP_NAME OPTIONS ) INPUTS: ``DEP_NAME`` Unique name for the dependency, used by FetchContent_* functions ``OPTIONS`` List of options for FetchContent_Declare, e.g. git url and refspec, check cmake documentations for more information #]===] function(LazyFetch_Fetch DEP_NAME OPTIONS) include(FetchContent) # Fetching dependency FetchContent_Declare( ${DEP_NAME} ${OPTIONS} ) FetchContent_GetProperties(${DEP_NAME}) if(NOT "${DEP_NAME}_POPULATED") message(STATUS "Fetching ${DEP_NAME}") FetchContent_Populate(${DEP_NAME}) endif() endfunction() #[===[.rst: .. cmake:command:: LazyFetch_ConfigAndBuild .. code:: cmake LazyFetch_ConfigAndBuild(DEP_NAME SRC_DIR BIN_DIR CACHE_FILE INSTALL_DIR ) INPUTS: ``DEP_NAME`` Unique name for the dependency ``SRC_DIR`` Source directory ``BIN_DIR`` Build directory ``CACHE_FILE`` Path to the initial cache file. Setting cache variables in this file can be used to augment the configure process. The file goes through :cmake:function:`configure_file(... @ONLY)`, this can be used to pass variables to the external project. ``INSTALL_DIR`` Install path. If not set, the install step will be skipped. ``_VERBOSE_CONFIG`` Global variable or environment variable. Pass `--trace-expand` to cmake if set. ``_VERBOSE_BUILD`` Global variable or environment variable. Turn the build step to verbose mode if set. #]===] function(LazyFetch_ConfigAndBuild) set(oneValueArgs DEP_NAME SRC_DIR BIN_DIR CACHE_FILE INSTALL_DIR) cmake_parse_arguments(BUILD "${__options}" "${oneValueArgs}" "${_multipleValueArgs}" ${ARGN}) message(STATUS "Configuring and building ${BUILD_DEP_NAME}") # Store config file in build dir, so it gets cleaned up set(CONFIGURED_CACHE_FILE ${CMAKE_BINARY_DIR}/${BUILD_DEP_NAME}-init-cache.cmake) configure_file(${BUILD_CACHE_FILE} ${CONFIGURED_CACHE_FILE} @ONLY) string(TOUPPER ${BUILD_DEP_NAME} UC_DEP_NAME) if (NOT DEFINED ${UC_DEP_NAME}_BUILD_TYPE) message(FATAL_ERROR "Build type for external component ${DEP_NAME} is not set. Please pass " "-D${UC_DEP_NAME}_BUILD_TYPE= to cmake. Supported build types are" "component specific. Pleas refer to the upstream documentation for more information.") endif() if (DEFINED ${UC_DEP_NAME}_VERBOSE_CONFIG OR DEFINED ENV{${UC_DEP_NAME}_VERBOSE_CONFIG}) set(_CMAKE_VERBOSE_CFG_FLAG "--trace-expand") endif() if(NOT DEFINED ${UC_DEP_NAME}_GENERATOR) if(DEFINED ENV{${UC_DEP_NAME}_GENERATOR}) set(${UC_DEP_NAME}_GENERATOR ENV{${UC_DEP_NAME}_GENERATOR} CACHE STRING "CMake generator used for ${UC_DEP_NAME}.") else() set(${UC_DEP_NAME}_GENERATOR ${CMAKE_GENERATOR} CACHE STRING "CMake generator used for ${UC_DEP_NAME}.") endif() endif() execute_process(COMMAND ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}" ${CMAKE_COMMAND} "-C${CONFIGURED_CACHE_FILE}" -DCMAKE_BUILD_TYPE=${${UC_DEP_NAME}_BUILD_TYPE} -G${${UC_DEP_NAME}_GENERATOR} -S ${BUILD_SRC_DIR} -B ${BUILD_BIN_DIR} ${_CMAKE_VERBOSE_CFG_FLAG} RESULT_VARIABLE _exec_error ) if (NOT _exec_error EQUAL 0) message(FATAL_ERROR "Configuring ${BUILD_DEP_NAME} build failed. `${_exec_error}`") endif() if (DEFINED ${UC_DEP_NAME}_VERBOSE_BUILD OR DEFINED ENV{${UC_DEP_NAME}_VERBOSE_BUILD}) set(_CMAKE_VERBOSE_CFG_FLAG "--verbose") endif() if (BUILD_INSTALL_DIR) execute_process(COMMAND ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}" ${CMAKE_COMMAND} --build ${BUILD_BIN_DIR} --parallel ${PROCESSOR_COUNT} --target install ${_CMAKE_VERBOSE_BLD_FLAG} RESULT_VARIABLE _exec_error ) else() execute_process(COMMAND ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}" ${CMAKE_COMMAND} --build ${BUILD_BIN_DIR} --parallel ${PROCESSOR_COUNT} ${_CMAKE_VERBOSE_BLD_FLAG} RESULT_VARIABLE _exec_error ) endif() if (NOT _exec_error EQUAL 0) message(FATAL_ERROR "Building ${BUILD_DEP_NAME} failed. ${_exec_error}") endif() endfunction() #[===[.rst: .. cmake:command:: LazyFetch_MakeAvailable .. code:: cmake LazyFetch_MakeAvailable(DEP_NAME INSTALL_DIR PACKAGE_DIR CACHE_FILE FETCH_OPTIONS ) INPUTS: ``DEP_NAME`` If set, this path overwrites the default base path for the FetchContent process ``SOURCE_DIR`` Location of source code. ``INSTALL_DIR`` Build install path ``PACKAGE_DIR`` If set find_package will search this directory for the config file ``CACHE_FILE`` Path to the cache init file, setting cache variables in this file can be used to augment the configure process. The file goes through the :cmake:function:`configure_file(... @ONLY)`, this can be used to pass variables to the cache file ``FETCH_OPTIONS`` Configure the dependency fetching process, this is passed to FetchContent_Declare, check the cmake documentation for more info ``SOURCE_SUBDIR`` A subdirectory relative to the top level directory of the fetched component, where the CMakeLists.txt file can be found. ``_VERBOSE_CONFIG`` Global variable or environment variable. Pass `--trace-expand` to cmake if set. ``_VERBOSE_BUILD`` Global variable or environment variable. Turn the build step to verbose mode if set. #]===] macro(LazyFetch_MakeAvailable) set(oneValueArgs DEP_NAME SOURCE_DIR BINARY_DIR INSTALL_DIR PACKAGE_DIR CACHE_FILE SOURCE_SUBDIR) set(multipleValueArgs FETCH_OPTIONS) cmake_parse_arguments(MY "${__options}" "${oneValueArgs}" "${multipleValueArgs}" ${ARGN}) message(STATUS "Looking for dependency ${MY_DEP_NAME}") if (NOT DEFINED MY_DEP_NAME) message(FATAL_ERROR "Mandatory parameter DEP_NAME is missing.") endif() # FetchContent* functions use this form string(TOLOWER ${MY_DEP_NAME} MY_LC_DEP_NAME) # We also need the upper case version string(TOUPPER ${MY_DEP_NAME} MY_UC_DEP_NAME) # Look for name collision. We can collide with project() commands, other external components defined with # LazyFetch, FetchCOntent or ExternalProject. if(DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR AND NOT DEFINED ${MY_LC_DEP_NAME}_BINARY_DIR_LZF) string(CONCAT _msg "External dependency name \"${MY_DEP_NAME}\" collides with a project or another external" " dependency name.") message(FATAL_ERROR ${_msg}) endif() # This variable is used to avoid false colision detection when re-configuring the project. set(${MY_LC_DEP_NAME}_BINARY_DIR_LZF On CACHE BOOL "") mark_as_advanced(${MY_LC_DEP_NAME}_BINARY_DIR_LZF) # These two variables are also set by the normal FetchContent process and users could depend on them, # so they are not unset at the end of the macro if (MY_BINARY_DIR) set(${MY_LC_DEP_NAME}_BINARY_DIR ${MY_BINARY_DIR}) else() set(${MY_LC_DEP_NAME}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-build) endif() set(${MY_LC_DEP_NAME}_BINARY_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR} CACHE PATH "Build directory for ${MY_LC_DEP_NAME}" FORCE) if (MY_SOURCE_DIR) set(${MY_LC_DEP_NAME}_SOURCE_DIR ${MY_SOURCE_DIR}) else() set(${MY_LC_DEP_NAME}_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-src) endif() set(${MY_LC_DEP_NAME}_SOURCE_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR} CACHE PATH "Source directory for ${MY_LC_DEP_NAME}" FORCE) set(${MY_LC_DEP_NAME}_SUBBUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/${MY_LC_DEP_NAME}-subbuild CACHE STRING "Sub-build directory for ${MY_LC_DEP_NAME}") list(APPEND MY_FETCH_OPTIONS SOURCE_DIR "${${MY_LC_DEP_NAME}_SOURCE_DIR}" BINARY_DIR "${${MY_LC_DEP_NAME}_BINARY_DIR}" SUBBUILD_DIR "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}") if (NOT DEFINED MY_INSTALL_DIR OR NOT EXISTS ${MY_INSTALL_DIR}) if (NOT EXISTS ${${MY_LC_DEP_NAME}_BINARY_DIR} OR NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR}) if (NOT EXISTS ${${MY_LC_DEP_NAME}_SOURCE_DIR}) LazyFetch_Fetch(${MY_LC_DEP_NAME} "${MY_FETCH_OPTIONS}") file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_BINARY_DIR}") file(REMOVE_RECURSE "${${MY_LC_DEP_NAME}_SUBBUILD_DIR}") endif() if (MY_CACHE_FILE) LazyFetch_ConfigAndBuild( DEP_NAME ${MY_LC_DEP_NAME} SRC_DIR ${${MY_LC_DEP_NAME}_SOURCE_DIR}/${MY_SOURCE_SUBDIR} BIN_DIR ${${MY_LC_DEP_NAME}_BINARY_DIR} CACHE_FILE ${MY_CACHE_FILE} INSTALL_DIR ${MY_INSTALL_DIR} ) endif() elseif(DEFINED MY_INSTALL_DIR) if(DEFINED ${MY_UC_DEP_NAME}_VERBOSE_BUILD OR DEFINED ENV{${MY_UC_DEP_NAME}_VERBOSE_BUILD}) set(_CMAKE_VERBOSE_BLD_FLAG "--verbose") endif() execute_process(COMMAND ${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}" ${CMAKE_COMMAND} --build ${${MY_LC_DEP_NAME}_BINARY_DIR} --parallel ${PROCESSOR_COUNT} --target install ${_CMAKE_VERBOSE_BLD_FLAG} RESULT_VARIABLE _exec_error ) if (NOT _exec_error EQUAL 0) message(FATAL_ERROR "Installing ${BUILD_DEP_NAME} failed. ${_exec_error}") endif() endif() endif() # Run find_package again if we just needed the build and install step if (MY_PACKAGE_DIR) unset(${MY_LC_DEP_NAME}_DIR) unset(${MY_LC_DEP_NAME}_DIR CACHE) unset(${MY_DEP_NAME}-FOUND CACHE) find_package(${MY_DEP_NAME} CONFIG REQUIRED NO_DEFAULT_PATH PATHS ${MY_PACKAGE_DIR}) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MY_DEP_NAME}_CONFIG) endif() unset(MY_DEP_NAME) unset(MY_SOURCE_DIR) unset(MY_BINARY_DIR) unset(MY_INSTALL_DIR) unset(MY_PACKAGE_DIR) unset(MY_CACHE_FILE) unset(MY_SOURCE_SUBDIR) unset(MY_FETCH_OPTIONS) unset(MY_LC_DEP_NAME) unset(oneValueArgs) unset(multipleValueArgs) endmacro()