1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# Created-By: crueter
# Docs will come at a later date, mostly this is to just reduce boilerplate
# and some cmake magic to allow for runtime viewing of dependency versions
include(CMakeDependentOption)
if (MSVC OR ANDROID)
set(SYSTEM_DEFAULT OFF)
else()
set(SYSTEM_DEFAULT ON)
endif()
CMAKE_DEPENDENT_OPTION(CPMUTIL_DEFAULT_SYSTEM
"Allow usage of system packages for CPM dependencies" ${SYSTEM_DEFAULT}
"NOT ANDROID" OFF)
cmake_minimum_required(VERSION 3.22)
include(CPM)
function(cpm_utils_message level name message)
message(${level} "[CPMUtil] ${name}: ${message}")
endfunction()
function(AddPackage)
cpm_set_policies()
# TODO(crueter): docs, git clone
#[[
URL configurations, descending order of precedence:
- URL [+ GIT_URL] -> bare URL fetch
- REPO + TAG + ARTIFACT -> github release artifact
- REPO + TAG -> github release archive
- REPO + SHA -> github commit archive
- REPO + BRANCH -> github branch
Hash configurations, descending order of precedence:
- HASH -> bare sha512sum
- HASH_SUFFIX -> hash grabbed from the URL + this suffix
- HASH_URL -> hash grabbed from a URL
* technically this is unsafe since a hacker can attack that url
NOTE: hash algo defaults to sha512
#]]
set(oneValueArgs
NAME
VERSION
GIT_VERSION
REPO
TAG
ARTIFACT
SHA
BRANCH
HASH
HASH_SUFFIX
HASH_URL
HASH_ALGO
URL
GIT_URL
KEY
DOWNLOAD_ONLY
FIND_PACKAGE_ARGUMENTS
SYSTEM_PACKAGE
BUNDLED_PACKAGE
)
set(multiValueArgs OPTIONS PATCHES)
cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "${multiValueArgs}"
"${ARGN}")
if (NOT DEFINED PKG_ARGS_NAME)
cpm_utils_message(FATAL_ERROR "package" "No package name defined")
endif()
if (DEFINED PKG_ARGS_URL)
set(pkg_url ${PKG_ARGS_URL})
if (DEFINED PKG_ARGS_REPO)
set(pkg_git_url https://github.com/${PKG_ARGS_REPO})
else()
if (DEFINED PKG_ARGS_GIT_URL)
set(pkg_git_url ${PKG_ARGS_GIT_URL})
else()
set(pkg_git_url ${pkg_url})
endif()
endif()
elseif (DEFINED PKG_ARGS_REPO)
set(pkg_git_url https://github.com/${PKG_ARGS_REPO})
if (DEFINED PKG_ARGS_TAG)
set(pkg_key ${PKG_ARGS_TAG})
if(DEFINED PKG_ARGS_ARTIFACT)
set(pkg_url
${pkg_git_url}/releases/download/${PKG_ARGS_TAG}/${PKG_ARGS_ARTIFACT})
else()
set(pkg_url
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
endif()
elseif (DEFINED PKG_ARGS_SHA)
set(pkg_url "${pkg_git_url}/archive/${PKG_ARGS_SHA}.zip")
else()
if (DEFINED PKG_ARGS_BRANCH)
set(PKG_BRANCH ${PKG_ARGS_BRANCH})
else()
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
"REPO defined but no TAG, SHA, BRANCH, or URL specified, defaulting to master")
set(PKG_BRANCH master)
endif()
set(pkg_url ${pkg_git_url}/archive/refs/heads/${PKG_BRANCH}.zip)
endif()
else()
cpm_utils_message(FATAL_ERROR ${PKG_ARGS_NAME} "No URL or repository defined")
endif()
cpm_utils_message(STATUS ${PKG_ARGS_NAME} "Download URL is ${pkg_url}")
if (DEFINED PKG_ARGS_GIT_VERSION)
set(git_version ${PKG_ARGS_VERSION})
elseif(DEFINED PKG_ARGS_VERSION)
set(git_version ${PKG_ARGS_GIT_VERSION})
endif()
if (NOT DEFINED PKG_ARGS_KEY)
if (DEFINED PKG_ARGS_SHA)
string(SUBSTRING ${PKG_ARGS_SHA} 0 4 pkg_key)
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
"No custom key defined, using ${pkg_key} from sha")
elseif (DEFINED git_version)
set(pkg_key ${git_version})
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
"No custom key defined, using ${pkg_key}")
elseif (DEFINED PKG_ARGS_TAG)
set(pkg_key ${PKG_ARGS_TAG})
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
"No custom key defined, using ${pkg_key}")
else()
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
"Could not determine cache key, using CPM defaults")
endif()
else()
set(pkg_key ${PKG_ARGS_KEY})
endif()
if (DEFINED PKG_ARGS_HASH_ALGO)
set(hash_algo ${PKG_ARGS_HASH_ALGO})
else()
set(hash_algo SHA512)
endif()
if (DEFINED PKG_ARGS_HASH)
set(pkg_hash "${hash_algo}=${PKG_ARGS_HASH}")
elseif (DEFINED PKG_ARGS_HASH_SUFFIX)
# funny sanity check
string(TOLOWER ${hash_algo} hash_algo_lower)
string(TOLOWER ${PKG_ARGS_HASH_SUFFIX} suffix_lower)
if (NOT ${suffix_lower} MATCHES ${hash_algo_lower})
cpm_utils_message(WARNING
"Hash algorithm and hash suffix do not match, errors may occur")
endif()
set(hash_url ${pkg_url}.${PKG_ARGS_HASH_SUFFIX})
elseif (DEFINED PKG_ARGS_HASH_URL)
set(hash_url ${PKG_ARGS_HASH_URL})
else()
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
"No hash or hash URL found")
endif()
if (DEFINED hash_url)
set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${PKG_ARGS_NAME}.hash)
file(DOWNLOAD ${hash_url} ${outfile})
file(READ ${outfile} pkg_hash_tmp)
file(REMOVE ${outfile})
set(pkg_hash "${hash_algo}=${pkg_hash_tmp}")
endif()
if (NOT CPMUTIL_DEFAULT_SYSTEM)
set(CPM_USE_LOCAL_PACKAGES OFF)
elseif (DEFINED PKG_ARGS_SYSTEM_PACKAGE)
set(CPM_USE_LOCAL_PACKAGES ${PKG_ARGS_SYSTEM_PACKAGE})
elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE)
if (PKG_ARGS_BUNDLED_PACKAGE)
set(CPM_USE_LOCAL_PACKAGES OFF)
else()
set(CPM_USE_LOCAL_PACKAGES ON)
endif()
else()
set(CPM_USE_LOCAL_PACKAGES ON)
endif()
CPMAddPackage(
NAME ${PKG_ARGS_NAME}
VERSION ${PKG_ARGS_VERSION}
URL ${pkg_url}
URL_HASH ${pkg_hash}
CUSTOM_CACHE_KEY ${pkg_key}
DOWNLOAD_ONLY ${PKG_ARGS_DOWNLOAD_ONLY}
FIND_PACKAGE_ARGUMENTS ${PKG_ARGS_FIND_PACKAGE_ARGUMENTS}
OPTIONS ${PKG_ARGS_OPTIONS}
PATCHES ${PKG_ARGS_PATCHES}
${PKG_ARGS_UNPARSED_ARGUMENTS}
)
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${PKG_ARGS_NAME})
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS ${pkg_git_url})
if (${PKG_ARGS_NAME}_ADDED)
if (DEFINED PKG_ARGS_SHA)
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
${PKG_ARGS_SHA})
elseif(DEFINED git_version)
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
${git_version})
elseif (DEFINED PKG_ARGS_TAG)
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
${PKG_ARGS_TAG})
else()
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
"Package has no specified sha, tag, or version")
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS "unknown")
endif()
else()
if (DEFINED CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION AND NOT
"${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION}" STREQUAL "")
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
"${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION} (system)")
else()
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
"unknown (system)")
endif()
endif()
# pass stuff to parent scope
set(${PKG_ARGS_NAME}_ADDED "${${PKG_ARGS_NAME}_ADDED}"
PARENT_SCOPE)
set(${PKG_ARGS_NAME}_SOURCE_DIR "${${PKG_ARGS_NAME}_SOURCE_DIR}"
PARENT_SCOPE)
set(${PKG_ARGS_NAME}_BINARY_DIR "${${PKG_ARGS_NAME}_BINARY_DIR}"
PARENT_SCOPE)
endfunction()
|