From e6c862713c19db755da5a4204873a537e8d249ec Mon Sep 17 00:00:00 2001 From: Silvio Traversaro Date: Wed, 20 Apr 2022 15:55:26 +0200 Subject: [PATCH] Create YCMBootstrapFetch to permit projects to bootstrap YCM using FetchContent (#403) --- CHANGELOG.md | 6 +- help/manual/ycm-superbuild-example.7.rst | 6 +- help/manual/ycm-using.7.rst | 9 +- modules/YCMEPHelper.cmake | 6 +- tools/UseYCMFromSource.cmake | 18 ++++ tools/YCMBootstrapFetch.cmake | 100 +++++++++++++++++++++++ 6 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 tools/UseYCMFromSource.cmake create mode 100644 tools/YCMBootstrapFetch.cmake diff --git a/CHANGELOG.md b/CHANGELOG.md index 9879d865..1011ff9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased Minor] ### Added -* Added new find module `FindSOXR.cmake` for libsoxr (https://github.com/robotology/ycm/pull/385) +* Added new find module `FindSOXR.cmake` for libsoxr (https://github.com/robotology/ycm/pull/385). +* Add new `YCMBootstrapFetch.cmake` module that substitutes the `YCMBootstrap.cmake` module (https://github.com/robotology/ycm/pull/403). The new `YCMBootstrapFetch.cmake` script to permit projects to bootstrap YCM by just using `FetchContent` module. A different file is created as the semantics of this new bootstrap script is a bit different, as it just make YCM available in the project, but it does not also adds it as a subproject in the superbuild sense. Superbuilds that want to switch from `YCMBootstrap.cmake` to `YCMBootstrapFetch.cmake` need to create `BuildYCM.cmake` script, and appropriately call `find_or_build_package(YCM)`, as done for example in the robotology-superbuild in https://github.com/robotology/robotology-superbuild/pull/1078 . ### Changed * CMake 3.16 or later is now required (https://github.com/robotology/ycm/pull/386). @@ -15,6 +16,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Avoid to download files from online repositories as part of the build process (https://github.com/robotology/ycm/pull/402). * FindOrBuildPackage: Do not call find_package if YCM_DISABLE_SYSTEM_PACKAGES is ON (https://github.com/robotology/ycm/pull/404). This change speeds up the CMake configuration time for superbuild that have many packages and `YCM_DISABLE_SYSTEM_PACKAGES` set to `ON`. +### Deprecated +* The `YCMBootstrap.cmake` module is now deprecated (https://github.com/robotology/ycm/pull/403). + ### Removed * Removed `FindEigen3.cmake` module (https://github.com/robotology/ycm/pull/399). * Removed `FindGSL.cmake`, `FindGLUT.cmake`, `FindOpenGL.cmake` and `YCMDefaultDirs.cmake`. The first three are available in CMake, while the last one has been deprecated for a long time (https://github.com/robotology/ycm/pull/401). diff --git a/help/manual/ycm-superbuild-example.7.rst b/help/manual/ycm-superbuild-example.7.rst index e5b0abbb..91796250 100644 --- a/help/manual/ycm-superbuild-example.7.rst +++ b/help/manual/ycm-superbuild-example.7.rst @@ -107,7 +107,7 @@ Create a ``CMakeLists.txt`` with this content: # Choose whether you want YCM to be a soft or a hard dependency and uncomment # the appropriate line: - include(YCMBootstrap) # This will make it a soft dependency + include(YCMBootstrapFetch) # This will make it a soft dependency # find_package(YCM 0.1 REQUIRED) # This will make it a hard dependency include(FindOrBuildPackage) @@ -125,12 +125,12 @@ Create a ``cmake`` folder that will contain all required CMake modules mkdir cmake If you want YCM as a soft dependency you will need to get the files -``tools/YCMBootstrap.cmake`` and ``modules/IncludeUrl.cmake`` from the YCM +``tools/YCMBootstrapFetch.cmake`` from the YCM sources. If you want to make it a hard dependency you don't have to add these files, but the user will have to install YCM before he can build the superbuild. .. note: - If the user has YCM installed, ``YCMBootstrap`` will find it and will + If the user has YCM installed, ``YCMBootstrapFetch`` will find it and will not download it again, but it will use the user's installation. Create the files ``cmake/BuildTemplatePkg.cmake`` and diff --git a/help/manual/ycm-using.7.rst b/help/manual/ycm-using.7.rst index 8ce03761..ff9a5b7c 100644 --- a/help/manual/ycm-using.7.rst +++ b/help/manual/ycm-using.7.rst @@ -123,7 +123,7 @@ Using YCM as Soft Dependency ---------------------------- In order to make it a soft dependency, you will need to get the files -``tools/YCMBootstrap.cmake`` and ``modules/IncludeUrl.cmake`` from the YCM +``tools/YCMBootstrapFetch.cmake`` from the YCM sources (see :manual:`ycm-installing(7)` for instructions on how to download YCM) and copy them inside your project tree: @@ -131,8 +131,7 @@ YCM) and copy them inside your project tree: cd mkdir cmake - cp /tools/YCMBootstrap.cmake cmake - cp modules/IncludeUrl.cmake cmake + cp /tools/YCMBootstrapFetch.cmake cmake These files must be in a folder included in :cmake:variable:`CMAKE_MODULE_PATH` for your project: @@ -141,7 +140,7 @@ for your project: list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -Now you can include ``YCMBootstrap.cmake``: +Now you can include ``YCMBootstrapFetch.cmake``: .. code-block:: cmake @@ -149,7 +148,7 @@ Now you can include ``YCMBootstrap.cmake``: # set(YCM_TAG [tag, branch, or commit hash]) # Bootstrap YCM - include(YCMBootstrap) + include(YCMBootstrapFetch) This is the suggested method when you build a superbuild. Downloading all your project would require a network connection anyway, therefore you will need to diff --git a/modules/YCMEPHelper.cmake b/modules/YCMEPHelper.cmake index 58e1e003..e747a2c7 100644 --- a/modules/YCMEPHelper.cmake +++ b/modules/YCMEPHelper.cmake @@ -92,7 +92,7 @@ set(_ycm_YCMBootstrap_sha1sum 59c6dfc84ec36518c5be5aef13af252a8250bad7) # new scope the variables added by the included files. macro(_YCM_INCLUDE _module) - if(YCM_FOUND) + if(YCM_FOUND OR DEFINED __USEYCMFROMSOURCE_INCLUDED) include(${_module}) else() # We assume that YCMEPHelper was included using include_url, or that at @@ -215,7 +215,7 @@ macro(_YCM_SETUP) set(_print-directories-all print-directories-all) endif() - if(NOT YCM_FOUND) # Useless if we don't need to bootstrap + if(NOT (YCM_FOUND OR DEFINED __USEYCMFROMSOURCE_INCLUDED)) # Useless if we don't need to bootstrap set(YCM_BOOTSTRAP_BASE_ADDRESS "https://raw.github.com/robotology/ycm/HEAD/" CACHE STRING "Base address of YCM repository") mark_as_advanced(YCM_BOOTSTRAP_BASE_ADDRESS) endif() @@ -1327,7 +1327,7 @@ endfunction() unset(__YCM_BOOTSTRAPPED_CALLED CACHE) macro(YCM_BOOTSTRAP) - if(YCM_FOUND OR DEFINED __YCM_BOOTSTRAPPED_CALLED) + if(YCM_FOUND OR DEFINED __YCM_BOOTSTRAPPED_CALLED OR DEFINED __USEYCMFROMSOURCE_INCLUDED) return() endif() set(__YCM_BOOTSTRAPPED_CALLED TRUE CACHE INTERNAL "") diff --git a/tools/UseYCMFromSource.cmake b/tools/UseYCMFromSource.cmake new file mode 100644 index 00000000..1829a77b --- /dev/null +++ b/tools/UseYCMFromSource.cmake @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT) +# SPDX-License-Identifier: BSD-3-Clause + +# This module can be used to use YCM modules directly from the source repo, +# to just use them in the build without installing them. + +if(DEFINED __USEYCMFROMSOURCE_INCLUDED) + return() +endif() +set(__USEYCMFROMSOURCE_INCLUDED TRUE) + +get_filename_component(_YCM_SRC_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY) + +list(APPEND CMAKE_MODULE_PATH ${_YCM_SRC_DIR}/modules) +list(APPEND CMAKE_MODULE_PATH ${_YCM_SRC_DIR}/find-modules) +list(APPEND CMAKE_MODULE_PATH ${_YCM_SRC_DIR}/build-modules) +list(APPEND CMAKE_MODULE_PATH ${_YCM_SRC_DIR}/style-modules) +list(APPEND CMAKE_MODULE_PATH ${_YCM_SRC_DIR}/cmake-next/proposed) diff --git a/tools/YCMBootstrapFetch.cmake b/tools/YCMBootstrapFetch.cmake new file mode 100644 index 00000000..8762880f --- /dev/null +++ b/tools/YCMBootstrapFetch.cmake @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT) +# SPDX-License-Identifier: BSD-3-Clause + +# This module is intentionally kept as small as possible in order to +# avoid the spreading of different modules. +# + +# CMake variables read as input by this module: +# YCM_MINIMUM_VERSION : minimum version of YCM requested to use a system YCM +# YCM_TAG : if no suitable system YCM was found, bootstrap from this +# : TAG (either branch, commit or tag) of YCM repository +# USE_SYSTEM_YCM : if defined and set FALSE, skip searching for a system +# YCM and always bootstrap + + +if(DEFINED __YCMBOOTSTRAP_INCLUDED) + return() +endif() +set(__YCMBOOTSTRAP_INCLUDED TRUE) + + +######################################################################## +# _YCM_CLEAN_PATH +# +# Internal function that removes a directory and its subfolder from an +# environment variable. +# This is useful because will stop CMake from finding the external +# projects built in the main project on the second CMake run. +# +# _path: path that should be removed +# _envvar: environment variable to clean + +function(_YCM_CLEAN_PATH _path _envvar) + get_filename_component(_path ${_path} REALPATH) + set(_var_new "") + if(NOT "$ENV{${_envvar}}" MATCHES "^$") + file(TO_CMAKE_PATH "$ENV{${_envvar}}" _var_old) + if(NOT WIN32) + # CMake handles correctly ":" except for the first character + string(REPLACE ":" ";" _var_old "${_var_old}") + endif() + foreach(_dir ${_var_old}) + get_filename_component(_dir ${_dir} REALPATH) + if(NOT "${_dir}" MATCHES "^${_path}") + list(APPEND _var_new ${_dir}) + endif() + endforeach() + endif() + list(REMOVE_DUPLICATES _var_new) + file(TO_NATIVE_PATH "${_var_new}" _var_new) + if(NOT WIN32) + string(REPLACE ";" ":" _var_new "${_var_new}") + endif() + set(ENV{${_envvar}} "${_var_new}") +endfunction() + + +# Remove binary dir from CMAKE_PREFIX_PATH and PATH before searching for +# YCM, in order to avoid to find the YCM version bootstrapped by YCM +# itself. +_ycm_clean_path("${CMAKE_BINARY_DIR}/install" CMAKE_PREFIX_PATH) +_ycm_clean_path("${CMAKE_BINARY_DIR}/install" PATH) + + +# If the USE_SYSTEM_YCM is explicitly set to false, we just skip to bootstrap. +if(NOT DEFINED USE_SYSTEM_YCM OR USE_SYSTEM_YCM) + find_package(YCM ${YCM_MINIMUM_VERSION} QUIET) + if(COMMAND set_package_properties) + set_package_properties(YCM PROPERTIES TYPE RECOMMENDED + PURPOSE "Used by the build system") + endif() + if(YCM_FOUND) + message(STATUS "YCM found in ${YCM_MODULE_DIR}.") + set_property(GLOBAL APPEND PROPERTY YCM_PROJECTS YCM) + return() + endif() +endif() + +message(STATUS "YCM not found. Bootstrapping it.") + +# Download and use a copy of the YCM library for bootstrapping +# This is different from the YCM that will be downloaded as part of the superbuild +include(FetchContent) +if(DEFINED YCM_TAG) + set(YCM_FETCHCONTENT_TAG ${YCM_TAG}) +else() + set(YCM_FETCHCONTENT_TAG master) +endif() +FetchContent_Declare(YCM + GIT_REPOSITORY https://github.com/robotology/ycm + GIT_TAG ${YCM_FETCHCONTENT_TAG}) + +FetchContent_GetProperties(YCM) +if(NOT YCM_POPULATED) + message(STATUS "Fetching YCM.") + FetchContent_Populate(YCM) + # Add YCM modules in CMAKE_MODULE_PATH + include(${ycm_SOURCE_DIR}/tools/UseYCMFromSource.cmake) +endif() +