1 # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
7 message(FATAL_ERROR "CPackNuGet.cmake may only be used by CPack internally.")
10 function(_cpack_nuget_debug)
11 if(CPACK_NUGET_PACKAGE_DEBUG)
12 message("CPackNuGet:Debug: " ${ARGN})
16 function(_cpack_nuget_debug_var NAME)
17 if(CPACK_NUGET_PACKAGE_DEBUG)
18 message("CPackNuGet:Debug: ${NAME}=`${${NAME}}`")
22 function(_cpack_nuget_variable_fallback OUTPUT_VAR_NAME NUGET_VAR_NAME)
24 list(JOIN ARGN "`, `" _va_args)
25 set(_va_args ", ARGN: `${_va_args}`")
28 "_cpack_nuget_variable_fallback: "
29 "OUTPUT_VAR_NAME=`${OUTPUT_VAR_NAME}`, "
30 "NUGET_VAR_NAME=`${NUGET_VAR_NAME}`"
34 set(_options USE_CDATA)
35 set(_one_value_args LIST_GLUE)
36 set(_multi_value_args FALLBACK_VARS)
37 cmake_parse_arguments(PARSE_ARGV 0 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
39 if(CPACK_NUGET_PACKAGE_COMPONENT)
41 TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}"
42 CPACK_NUGET_PACKAGE_COMPONENT_UPPER
46 if(CPACK_NUGET_PACKAGE_COMPONENT
47 AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}
51 "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}}"
54 " CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}: "
55 "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
58 elseif(CPACK_NUGET_PACKAGE_COMPONENT_UPPER
59 AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}
63 "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}}"
66 " CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}: "
67 "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
70 elseif(CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME})
71 set(_result "${CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}}")
73 " CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}: "
74 "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
78 foreach(_var IN LISTS _args_FALLBACK_VARS)
79 _cpack_nuget_debug(" Fallback: ${_var} ...")
81 _cpack_nuget_debug(" ${_var}=`${${_var}}`")
82 set(_result "${${_var}}")
84 " ${_var}: OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
93 set(_value_before "<![CDATA[")
94 set(_value_after "]]>")
97 list(LENGTH _result _result_len)
98 if(_result_len GREATER 1 AND _args_LIST_GLUE)
99 list(JOIN _result "${_args_LIST_GLUE}" _result)
102 set(${OUTPUT_VAR_NAME} "${_value_before}${_result}${_value_after}" PARENT_SCOPE)
107 function(_cpack_nuget_variable_fallback_and_wrap_into_element ELEMENT NUGET_VAR_NAME)
110 set(_multi_value_args FALLBACK_VARS ATTRIBUTES)
111 cmake_parse_arguments(PARSE_ARGV 2 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
114 list(JOIN _args_ATTRIBUTES " " _attributes)
115 string(PREPEND _attributes " ")
118 _cpack_nuget_variable_fallback(_value ${NUGET_VAR_NAME} ${ARGN} USE_CDATA)
120 string(TOUPPER "${ELEMENT}" _ELEMENT_UP)
123 _CPACK_NUGET_${_ELEMENT_UP}_TAG
124 "<${ELEMENT}${_attributes}>${_value}</${ELEMENT}>"
129 _CPACK_NUGET_${_ELEMENT_UP}_TAG
130 "<${ELEMENT}${_attributes} />"
136 # Warn of obsolete nuspec fields, referencing CMake variables and suggested
137 # replacement, if any
138 function(_cpack_nuget_deprecation_warning NUGET_ELEMENT VARNAME REPLACEMENT)
141 message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider replacing `${VARNAME}` with `${REPLACEMENT}`")
143 message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider removing `${VARNAME}`")
148 # Print some debug info
149 _cpack_nuget_debug("---[CPack NuGet Input Variables]---")
150 _cpack_nuget_debug_var(CPACK_PACKAGE_NAME)
151 _cpack_nuget_debug_var(CPACK_PACKAGE_VERSION)
152 _cpack_nuget_debug_var(CPACK_TOPLEVEL_TAG)
153 _cpack_nuget_debug_var(CPACK_TOPLEVEL_DIRECTORY)
154 _cpack_nuget_debug_var(CPACK_TEMPORARY_DIRECTORY)
155 _cpack_nuget_debug_var(CPACK_NUGET_GROUPS)
156 if(CPACK_NUGET_GROUPS)
157 foreach(_group IN LISTS CPACK_NUGET_GROUPS)
158 string(MAKE_C_IDENTIFIER "${_group}" _group_up)
159 string(TOUPPER "${_group_up}" _group_up)
160 _cpack_nuget_debug_var(CPACK_NUGET_${_group_up}_GROUP_COMPONENTS)
163 _cpack_nuget_debug_var(CPACK_NUGET_COMPONENTS)
164 _cpack_nuget_debug_var(CPACK_NUGET_ALL_IN_ONE)
165 _cpack_nuget_debug_var(CPACK_NUGET_ORDINAL_MONOLITIC)
166 _cpack_nuget_debug("-----------------------------------")
168 function(_cpack_nuget_render_spec)
169 # Make a variable w/ upper-cased component name
170 if(CPACK_NUGET_PACKAGE_COMPONENT)
171 string(TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}" CPACK_NUGET_PACKAGE_COMPONENT_UPPER)
174 # Set mandatory variables (not wrapped into XML elements)
175 # https://docs.microsoft.com/en-us/nuget/reference/nuspec#required-metadata-elements
176 if(CPACK_NUGET_PACKAGE_COMPONENT)
177 if(CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME)
179 CPACK_NUGET_PACKAGE_NAME
180 "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME}"
182 elseif(NOT CPACK_NUGET_PACKAGE_COMPONENT STREQUAL "Unspecified")
184 CPACK_NUGET_PACKAGE_NAME
185 "${CPACK_PACKAGE_NAME}.${CPACK_NUGET_PACKAGE_COMPONENT}"
188 set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
190 elseif(NOT CPACK_NUGET_PACKAGE_NAME)
191 set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
194 # Warn about deprecated nuspec elements; warnings only display if
196 # Note that while nuspec's "summary" element is deprecated, there
197 # is no suggested replacement so (for now) no deprecation warning
198 # is shown for `CPACK_NUGET_*_DESCRIPTION_SUMMARY`
199 _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_PACKAGE_LICENSEURL
200 "CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME or CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION")
201 _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSEURL
202 "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_FILE_NAME or CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_EXPRESSION")
203 _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_PACKAGE_ICONURL
204 "CPACK_NUGET_PACKAGE_ICON")
205 _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICONURL
206 "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICON")
209 _cpack_nuget_variable_fallback(
210 CPACK_NUGET_PACKAGE_VERSION VERSION
212 CPACK_PACKAGE_VERSION
214 _cpack_nuget_variable_fallback(
215 CPACK_NUGET_PACKAGE_DESCRIPTION DESCRIPTION
217 CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DESCRIPTION
218 CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
219 CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
220 CPACK_PACKAGE_DESCRIPTION
223 _cpack_nuget_variable_fallback(
224 CPACK_NUGET_PACKAGE_AUTHORS AUTHORS
231 # Set optional variables (wrapped into XML elements)
232 # https://docs.microsoft.com/en-us/nuget/reference/nuspec#optional-metadata-elements
233 _cpack_nuget_variable_fallback_and_wrap_into_element(
237 CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DISPLAY_NAME
238 CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
239 CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
241 _cpack_nuget_variable_fallback_and_wrap_into_element(owners OWNERS LIST_GLUE ",")
242 _cpack_nuget_variable_fallback_and_wrap_into_element(
246 CPACK_PACKAGE_HOMEPAGE_URL
249 # "licenseUrl" is deprecated in favor of "license"
250 _cpack_nuget_variable_fallback_and_wrap_into_element(licenseUrl LICENSEURL)
252 # "iconUrl" is deprecated in favor of "icon"
253 _cpack_nuget_variable_fallback_and_wrap_into_element(iconUrl ICONURL)
255 # "license" takes a "type" attribute of either "file" or "expression"
256 # "file" refers to a file path of a .txt or .md file relative to the installation root
257 # "expression" refers to simple or compound expression of license identifiers
258 # listed at https://spdx.org/licenses/
259 # Note that only one of CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME and
260 # CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION may be specified. If both are specified,
261 # CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME takes precedence and CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION is ignored.
262 if(CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME)
263 _cpack_nuget_variable_fallback_and_wrap_into_element(
264 license LICENSE_FILE_NAME
265 ATTRIBUTES [[type="file"]]
267 elseif(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION)
268 _cpack_nuget_variable_fallback_and_wrap_into_element(
269 license LICENSE_EXPRESSION
270 ATTRIBUTES [[type="expression"]]
274 # "icon" refers to a file path relative to the installation root
275 _cpack_nuget_variable_fallback_and_wrap_into_element(icon ICON)
276 # "summary" is deprecated in favor of "description"
277 _cpack_nuget_variable_fallback_and_wrap_into_element(
278 summary DESCRIPTION_SUMMARY
280 CPACK_PACKAGE_DESCRIPTION_SUMMARY
282 if(CPACK_NUGET_PACKAGE_REQUIRE_LICENSE_ACCEPTANCE)
284 _CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG
285 "<requireLicenseAcceptance>true</requireLicenseAcceptance>"
288 _cpack_nuget_variable_fallback_and_wrap_into_element(releaseNotes RELEASE_NOTES)
289 _cpack_nuget_variable_fallback_and_wrap_into_element(copyright COPYRIGHT)
290 # "language" is a locale identifier such as "en_CA"
291 _cpack_nuget_variable_fallback_and_wrap_into_element(language LANGUAGE)
292 _cpack_nuget_variable_fallback_and_wrap_into_element(tags TAGS LIST_GLUE " ")
293 # "repository" holds repository metadata consisting of four optional
294 # attributes: "type", "url", "branch", and "commit". While all fields are
295 # considered optional, they are not independent. Currently unsupported.
297 # Handle dependencies
298 _cpack_nuget_variable_fallback(_deps DEPENDENCIES)
300 foreach(_dep IN LISTS _deps)
301 _cpack_nuget_debug(" checking dependency `${_dep}`")
303 _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep}_VERSION)
306 string(TOUPPER "${_dep}" _dep_upper)
307 _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_upper}_VERSION)
311 _cpack_nuget_debug(" got `${_dep}` dependency version ${_ver}")
312 string(CONCAT _collected_deps "${_collected_deps}" " <dependency id=\"${_dep}\" version=\"${_ver}\" />\n")
316 # Render deps into the variable
318 string(CONCAT _CPACK_NUGET_DEPENDENCIES_TAG "<dependencies>\n" "${_collected_deps}" " </dependencies>")
321 # Render the spec file
322 # NOTE The spec filename doesn't matter. Being included into a package,
323 # NuGet will name it properly.
324 _cpack_nuget_debug("Rendering `${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec` file...")
326 "${CMAKE_ROOT}/Modules/Internal/CPack/CPack.NuGet.nuspec.in"
327 "${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec"
332 function(_cpack_nuget_make_files_tag)
334 foreach(_comp IN LISTS ARGN)
335 cmake_path(APPEND _comp "**")
336 cmake_path(NATIVE_PATH _comp _comp)
337 string(APPEND _files " <file src=\"${_comp}\" target=\".\" />\n")
339 set(_CPACK_NUGET_FILES_TAG "<files>\n${_files} </files>" PARENT_SCOPE)
342 find_program(NUGET_EXECUTABLE nuget)
343 _cpack_nuget_debug_var(NUGET_EXECUTABLE)
344 if(NOT NUGET_EXECUTABLE)
345 message(FATAL_ERROR "NuGet executable not found")
348 # Add details for debug run
349 if(CPACK_NUGET_PACKAGE_DEBUG)
350 list(APPEND CPACK_NUGET_PACK_ADDITIONAL_OPTIONS "-Verbosity" "detailed")
353 # Case one: ordinal all-in-one package
354 if(CPACK_NUGET_ORDINAL_MONOLITIC)
355 # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
356 # Meaning to pack all installed files into a single package
357 _cpack_nuget_debug("---[Making an ordinal monolitic package]---")
358 _cpack_nuget_render_spec()
360 COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
361 WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
362 RESULT_VARIABLE _nuget_result
364 if(NOT _nuget_result EQUAL 0)
365 message(FATAL_ERROR "Nuget pack failed")
368 elseif(CPACK_NUGET_ALL_IN_ONE)
369 # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
370 # Meaning to pack all installed components into a single package
371 _cpack_nuget_debug("---[Making a monolitic package from installed components]---")
373 # Prepare the `files` element which include files from several components
374 _cpack_nuget_make_files_tag(${CPACK_NUGET_COMPONENTS})
375 _cpack_nuget_render_spec()
377 COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
378 WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
379 RESULT_VARIABLE _nuget_result
381 if(NOT _nuget_result EQUAL 0)
382 message(FATAL_ERROR "Nuget pack failed")
386 # Is there any grouped component?
387 if(CPACK_NUGET_GROUPS)
388 _cpack_nuget_debug("---[Making grouped component(s) package(s)]---")
389 foreach(_group IN LISTS CPACK_NUGET_GROUPS)
390 _cpack_nuget_debug("Starting to make the package for group `${_group}`")
391 string(MAKE_C_IDENTIFIER "${_group}" _group_up)
392 string(TOUPPER "${_group_up}" _group_up)
394 # Render a spec file which includes all components in the current group
395 unset(_CPACK_NUGET_FILES_TAG)
396 _cpack_nuget_make_files_tag(${CPACK_NUGET_${_group_up}_GROUP_COMPONENTS})
397 # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the group name
398 # to properly collect various per group settings
399 set(CPACK_NUGET_PACKAGE_COMPONENT ${_group})
400 _cpack_nuget_render_spec()
401 unset(CPACK_NUGET_PACKAGE_COMPONENT)
403 COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
404 WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
405 RESULT_VARIABLE _nuget_result
407 if(NOT _nuget_result EQUAL 0)
408 message(FATAL_ERROR "Nuget pack failed")
412 # Is there any single component package needed?
413 if(CPACK_NUGET_COMPONENTS)
414 _cpack_nuget_debug("---[Making single-component(s) package(s)]---")
415 foreach(_comp IN LISTS CPACK_NUGET_COMPONENTS)
416 _cpack_nuget_debug("Starting to make the package for component `${_comp}`")
417 # Render a spec file which includes only given component
418 unset(_CPACK_NUGET_FILES_TAG)
419 _cpack_nuget_make_files_tag(${_comp})
420 # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the current
421 # component name to properly collect various per group settings
422 set(CPACK_NUGET_PACKAGE_COMPONENT ${_comp})
423 _cpack_nuget_render_spec()
424 unset(CPACK_NUGET_PACKAGE_COMPONENT)
426 COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
427 WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
428 RESULT_VARIABLE _nuget_result
430 if(NOT _nuget_result EQUAL 0)
431 message(FATAL_ERROR "Nuget pack failed")
437 file(GLOB_RECURSE GEN_CPACK_OUTPUT_FILES "${CPACK_TEMPORARY_DIRECTORY}/*.nupkg")
438 if(NOT GEN_CPACK_OUTPUT_FILES)
439 message(FATAL_ERROR "NuGet package was not generated at `${CPACK_TEMPORARY_DIRECTORY}`!")
442 _cpack_nuget_debug("Generated files: ${GEN_CPACK_OUTPUT_FILES}")