|
| 1 | +# TheLartians/CPM - A simple Git dependency manager |
| 2 | +# ================================================= |
| 3 | +# See https://github.com/TheLartians/CPM for usage and update instructions. |
| 4 | +# |
| 5 | +# MIT License |
| 6 | +# ----------- |
| 7 | +#[[ |
| 8 | + Copyright (c) 2019 Lars Melchior |
| 9 | +
|
| 10 | + Permission is hereby granted, free of charge, to any person obtaining a copy |
| 11 | + of this software and associated documentation files (the "Software"), to deal |
| 12 | + in the Software without restriction, including without limitation the rights |
| 13 | + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 14 | + copies of the Software, and to permit persons to whom the Software is |
| 15 | + furnished to do so, subject to the following conditions: |
| 16 | +
|
| 17 | + The above copyright notice and this permission notice shall be included in all |
| 18 | + copies or substantial portions of the Software. |
| 19 | +
|
| 20 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 21 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 22 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 23 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 24 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 25 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 26 | + SOFTWARE. |
| 27 | +]] |
| 28 | + |
| 29 | +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) |
| 30 | + |
| 31 | +set(CURRENT_CPM_VERSION 0.14) |
| 32 | + |
| 33 | +if(CPM_DIRECTORY) |
| 34 | + if(NOT ${CPM_DIRECTORY} MATCHES ${CMAKE_CURRENT_LIST_DIR}) |
| 35 | + if (${CPM_VERSION} VERSION_LESS ${CURRENT_CPM_VERSION}) |
| 36 | + CPM_HANDLE_OLD_VERSION(${CURRENT_CPM_VERSION}) |
| 37 | + endif() |
| 38 | + return() |
| 39 | + endif() |
| 40 | +endif() |
| 41 | + |
| 42 | +set(CPM_VERSION ${CURRENT_CPM_VERSION} CACHE INTERNAL "") |
| 43 | +set(CPM_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "") |
| 44 | +set(CPM_PACKAGES "" CACHE INTERNAL "") |
| 45 | +set(CPM_DRY_RUN OFF CACHE INTERNAL "Don't download or configure dependencies (for testing)") |
| 46 | + |
| 47 | +option(CPM_USE_LOCAL_PACKAGES "Use locally installed packages (find_package)" OFF) |
| 48 | +option(CPM_LOCAL_PACKAGES_ONLY "Use only locally installed packages" OFF) |
| 49 | + |
| 50 | +if(DEFINED ENV{CPM_SOURCE_CACHE}) |
| 51 | + set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE}) |
| 52 | +else() |
| 53 | + set(CPM_SOURCE_CACHE_DEFAULT OFF) |
| 54 | +endif() |
| 55 | + |
| 56 | +set(CPM_SOURCE_CACHE ${CPM_SOURCE_CACHE_DEFAULT} CACHE PATH "Directory to downlaod CPM dependencies") |
| 57 | + |
| 58 | +include(FetchContent) |
| 59 | +include(CMakeParseArguments) |
| 60 | + |
| 61 | +# Initialize logging prefix |
| 62 | +if(NOT CPM_INDENT) |
| 63 | + set(CPM_INDENT "CPM:") |
| 64 | +endif() |
| 65 | + |
| 66 | +# The main workhorse of CPM |
| 67 | +function(CPMAddPackage) |
| 68 | + |
| 69 | + set(oneValueArgs |
| 70 | + NAME |
| 71 | + VERSION |
| 72 | + GIT_TAG |
| 73 | + DOWNLOAD_ONLY |
| 74 | + GITHUB_REPOSITORY |
| 75 | + GITLAB_REPOSITORY |
| 76 | + SOURCE_DIR |
| 77 | + DOWNLOAD_COMMAND |
| 78 | + ) |
| 79 | + |
| 80 | + set(multiValueArgs |
| 81 | + OPTIONS |
| 82 | + ) |
| 83 | + |
| 84 | + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) |
| 85 | + |
| 86 | + if(${CPM_USE_LOCAL_PACKAGES} OR ${CPM_LOCAL_PACKAGES_ONLY}) |
| 87 | + find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} QUIET) |
| 88 | + |
| 89 | + if(${CPM_PACKAGE_FOUND}) |
| 90 | + message(STATUS "CPM: adding local package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION}") |
| 91 | + set_target_properties(${CPM_ARGS_NAME} |
| 92 | + PROPERTIES |
| 93 | + IMPORTED_GLOBAL True |
| 94 | + ) |
| 95 | + return() |
| 96 | + endif() |
| 97 | + |
| 98 | + if(${CPM_LOCAL_PACKAGES_ONLY}) |
| 99 | + message(SEND_ERROR "CPM: ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})") |
| 100 | + endif() |
| 101 | + endif() |
| 102 | + |
| 103 | + if (NOT DEFINED CPM_ARGS_VERSION) |
| 104 | + if (DEFINED CPM_ARGS_GIT_TAG) |
| 105 | + CPM_GET_VERSION_FROM_GIT_TAG("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) |
| 106 | + endif() |
| 107 | + if (NOT DEFINED CPM_ARGS_VERSION) |
| 108 | + set(CPM_ARGS_VERSION 0) |
| 109 | + endif() |
| 110 | + endif() |
| 111 | + |
| 112 | + if (NOT DEFINED CPM_ARGS_GIT_TAG) |
| 113 | + set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION}) |
| 114 | + endif() |
| 115 | + |
| 116 | + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG}) |
| 117 | + |
| 118 | + if(CPM_ARGS_DOWNLOAD_ONLY) |
| 119 | + set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY}) |
| 120 | + else() |
| 121 | + set(DOWNLOAD_ONLY NO) |
| 122 | + endif() |
| 123 | + |
| 124 | + if (CPM_ARGS_GITHUB_REPOSITORY) |
| 125 | + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY "https://github.com/${CPM_ARGS_GITHUB_REPOSITORY}.git") |
| 126 | + endif() |
| 127 | + |
| 128 | + if (CPM_ARGS_GITLAB_REPOSITORY) |
| 129 | + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY "https://gitlab.com/${CPM_ARGS_GITLAB_REPOSITORY}.git") |
| 130 | + endif() |
| 131 | + |
| 132 | + if (${CPM_ARGS_NAME} IN_LIST CPM_PACKAGES) |
| 133 | + CPM_GET_PACKAGE_VERSION(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION) |
| 134 | + if(${CPM_PACKAGE_VERSION} VERSION_LESS ${CPM_ARGS_VERSION}) |
| 135 | + message(WARNING "${CPM_INDENT} requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION}).") |
| 136 | + endif() |
| 137 | + if (CPM_ARGS_OPTIONS) |
| 138 | + foreach(OPTION ${CPM_ARGS_OPTIONS}) |
| 139 | + CPM_PARSE_OPTION(${OPTION}) |
| 140 | + if(NOT "${${OPTION_KEY}}" STREQUAL ${OPTION_VALUE}) |
| 141 | + message(WARNING "${CPM_INDENT} ignoring package option for ${CPM_ARGS_NAME}: ${OPTION_KEY} = ${OPTION_VALUE} (${${OPTION_KEY}})") |
| 142 | + endif() |
| 143 | + endforeach() |
| 144 | + endif() |
| 145 | + CPM_FETCH_PACKAGE(${CPM_ARGS_NAME} ${DOWNLOAD_ONLY}) |
| 146 | + CPMGetProperties(${CPM_ARGS_NAME}) |
| 147 | + SET(${CPM_ARGS_NAME}_SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}" PARENT_SCOPE) |
| 148 | + SET(${CPM_ARGS_NAME}_BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}" PARENT_SCOPE) |
| 149 | + SET(${CPM_ARGS_NAME}_ADDED NO PARENT_SCOPE) |
| 150 | + return() |
| 151 | + endif() |
| 152 | + |
| 153 | + CPMRegisterPackage(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION}) |
| 154 | + |
| 155 | + if (CPM_ARGS_OPTIONS) |
| 156 | + foreach(OPTION ${CPM_ARGS_OPTIONS}) |
| 157 | + CPM_PARSE_OPTION(${OPTION}) |
| 158 | + set(${OPTION_KEY} ${OPTION_VALUE} CACHE INTERNAL "") |
| 159 | + endforeach() |
| 160 | + endif() |
| 161 | + |
| 162 | + set(FETCH_CONTENT_DECLARE_EXTRA_OPTS "") |
| 163 | + |
| 164 | + if (DEFINED CPM_ARGS_GIT_TAG) |
| 165 | + set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}") |
| 166 | + else() |
| 167 | + set(PACKAGE_INFO "${CPM_ARGS_VERSION}") |
| 168 | + endif() |
| 169 | + |
| 170 | + if (DEFINED CPM_ARGS_DOWNLOAD_COMMAND) |
| 171 | + set(FETCH_CONTENT_DECLARE_EXTRA_OPTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND}) |
| 172 | + else() |
| 173 | + if (CPM_SOURCE_CACHE AND NOT DEFINED CPM_ARGS_SOURCE_DIR) |
| 174 | + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) |
| 175 | + set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS}) |
| 176 | + list(SORT origin_parameters) |
| 177 | + string(SHA1 origin_hash "${origin_parameters}") |
| 178 | + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) |
| 179 | + list(APPEND FETCH_CONTENT_DECLARE_EXTRA_OPTS SOURCE_DIR ${download_directory}) |
| 180 | + if (EXISTS ${download_directory}) |
| 181 | + list(APPEND FETCH_CONTENT_DECLARE_EXTRA_OPTS DOWNLOAD_COMMAND ":") |
| 182 | + set(PACKAGE_INFO "${download_directory}") |
| 183 | + else() |
| 184 | + # remove timestamps so CMake will re-download the dependency |
| 185 | + file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/_deps/${lower_case_name}-subbuild) |
| 186 | + set(PACKAGE_INFO "${PACKAGE_INFO} -> ${download_directory}") |
| 187 | + endif() |
| 188 | + endif() |
| 189 | + endif() |
| 190 | + |
| 191 | + CPM_DECLARE_PACKAGE(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} ${PACKAGE_INFO} "${CPM_ARGS_UNPARSED_ARGUMENTS}" ${FETCH_CONTENT_DECLARE_EXTRA_OPTS}) |
| 192 | + CPM_FETCH_PACKAGE(${CPM_ARGS_NAME} ${DOWNLOAD_ONLY}) |
| 193 | + CPMGetProperties(${CPM_ARGS_NAME}) |
| 194 | + SET(${CPM_ARGS_NAME}_SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}" PARENT_SCOPE) |
| 195 | + SET(${CPM_ARGS_NAME}_BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}" PARENT_SCOPE) |
| 196 | + SET(${CPM_ARGS_NAME}_ADDED YES PARENT_SCOPE) |
| 197 | +endfunction() |
| 198 | + |
| 199 | +function (CPM_DECLARE_PACKAGE PACKAGE VERSION INFO) |
| 200 | + message(STATUS "${CPM_INDENT} adding package ${PACKAGE}@${VERSION} (${INFO})") |
| 201 | + |
| 202 | + if (${CPM_DRY_RUN}) |
| 203 | + message(STATUS "${CPM_INDENT} package not declared (dry run)") |
| 204 | + return() |
| 205 | + endif() |
| 206 | + |
| 207 | + FetchContent_Declare( |
| 208 | + ${PACKAGE} |
| 209 | + ${ARGN} |
| 210 | + ) |
| 211 | +endfunction() |
| 212 | + |
| 213 | +function (CPM_FETCH_PACKAGE PACKAGE DOWNLOAD_ONLY) |
| 214 | + |
| 215 | + if (${CPM_DRY_RUN}) |
| 216 | + message(STATUS "${CPM_INDENT} package ${PACKAGE} not fetched (dry run)") |
| 217 | + return() |
| 218 | + endif() |
| 219 | + |
| 220 | + set(CPM_OLD_INDENT "${CPM_INDENT}") |
| 221 | + set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:") |
| 222 | + if(${DOWNLOAD_ONLY}) |
| 223 | + if(NOT "${PACKAGE}_POPULATED") |
| 224 | + FetchContent_Populate(${PACKAGE}) |
| 225 | + endif() |
| 226 | + else() |
| 227 | + FetchContent_MakeAvailable(${PACKAGE}) |
| 228 | + endif() |
| 229 | + set(CPM_INDENT "${CPM_OLD_INDENT}") |
| 230 | +endfunction() |
| 231 | + |
| 232 | +function (CPMGetProperties PACKAGE) |
| 233 | + if (${CPM_DRY_RUN}) |
| 234 | + return() |
| 235 | + endif() |
| 236 | + FetchContent_GetProperties(${PACKAGE}) |
| 237 | + string(TOLOWER ${PACKAGE} lpackage) |
| 238 | + SET(${PACKAGE}_SOURCE_DIR "${${lpackage}_SOURCE_DIR}" PARENT_SCOPE) |
| 239 | + SET(${PACKAGE}_BINARY_DIR "${${lpackage}_BINARY_DIR}" PARENT_SCOPE) |
| 240 | +endfunction() |
| 241 | + |
| 242 | +function(CPMRegisterPackage PACKAGE VERSION) |
| 243 | + list(APPEND CPM_PACKAGES ${PACKAGE}) |
| 244 | + set(CPM_PACKAGES ${CPM_PACKAGES} CACHE INTERNAL "") |
| 245 | + set("CPM_PACKAGE_${PACKAGE}_VERSION" ${VERSION} CACHE INTERNAL "") |
| 246 | +endfunction() |
| 247 | + |
| 248 | +function(CPM_GET_PACKAGE_VERSION PACKAGE OUTPUT) |
| 249 | + set(${OUTPUT} "${CPM_PACKAGE_${PACKAGE}_VERSION}" PARENT_SCOPE) |
| 250 | +endfunction() |
| 251 | + |
| 252 | +function(CPM_PARSE_OPTION OPTION) |
| 253 | + string(REGEX MATCH "^[^ ]+" OPTION_KEY ${OPTION}) |
| 254 | + string(LENGTH ${OPTION_KEY} OPTION_KEY_LENGTH) |
| 255 | + math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1") |
| 256 | + string(SUBSTRING ${OPTION} "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE) |
| 257 | + set(OPTION_KEY "${OPTION_KEY}" PARENT_SCOPE) |
| 258 | + set(OPTION_VALUE "${OPTION_VALUE}" PARENT_SCOPE) |
| 259 | +endfunction() |
| 260 | + |
| 261 | +function(CPM_GET_VERSION_FROM_GIT_TAG GIT_TAG RESULT) |
| 262 | + string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG}) |
| 263 | + SET(${RESULT} ${CMAKE_MATCH_1} PARENT_SCOPE) |
| 264 | +endfunction() |
| 265 | + |
| 266 | +function (CPM_HANDLE_OLD_VERSION NEW_CPM_VERSION) |
| 267 | + |
| 268 | + message(AUTHOR_WARNING "${CPM_INDENT} \ |
| 269 | +A dependency is using a more recent CPM (${NEW_CPM_VERSION}) than the current project (${CPM_VERSION}). \ |
| 270 | +It is recommended to upgrade CPM to the most recent version. \ |
| 271 | +See https://github.com/TheLartians/CPM for more information." |
| 272 | + ) |
| 273 | + |
| 274 | +endfunction() |
0 commit comments