# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# Author: Alex Turbov
if(CMAKE_BINARY_DIR)
message(FATAL_ERROR "CPackNuGet.cmake may only be used by CPack internally.")
endif()
function(_cpack_nuget_debug)
if(CPACK_NUGET_PACKAGE_DEBUG)
message("CPackNuGet:Debug: " ${ARGN})
endif()
endfunction()
function(_cpack_nuget_debug_var NAME)
if(CPACK_NUGET_PACKAGE_DEBUG)
message("CPackNuGet:Debug: ${NAME}=`${${NAME}}`")
endif()
endfunction()
function(_cpack_nuget_variable_fallback OUTPUT_VAR_NAME NUGET_VAR_NAME)
if(ARGN)
list(JOIN ARGN "`, `" _va_args)
set(_va_args ", ARGN: `${_va_args}`")
endif()
_cpack_nuget_debug(
"_cpack_nuget_variable_fallback: "
"OUTPUT_VAR_NAME=`${OUTPUT_VAR_NAME}`, "
"NUGET_VAR_NAME=`${NUGET_VAR_NAME}`"
"${_va_args}"
)
set(_options USE_CDATA)
set(_one_value_args LIST_GLUE)
set(_multi_value_args FALLBACK_VARS)
cmake_parse_arguments(PARSE_ARGV 0 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
if(CPACK_NUGET_PACKAGE_COMPONENT)
string(
TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}"
CPACK_NUGET_PACKAGE_COMPONENT_UPPER
)
endif()
if(CPACK_NUGET_PACKAGE_COMPONENT
AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}
)
set(
_result
"${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}}"
)
_cpack_nuget_debug(
" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}: "
"OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
)
elseif(CPACK_NUGET_PACKAGE_COMPONENT_UPPER
AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}
)
set(
_result
"${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}}"
)
_cpack_nuget_debug(
" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}: "
"OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
)
elseif(CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME})
set(_result "${CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}}")
_cpack_nuget_debug(
" CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}: "
"OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
)
else()
foreach(_var IN LISTS _args_FALLBACK_VARS)
_cpack_nuget_debug(" Fallback: ${_var} ...")
if(${_var})
_cpack_nuget_debug(" ${_var}=`${${_var}}`")
set(_result "${${_var}}")
_cpack_nuget_debug(
" ${_var}: OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
)
break()
endif()
endforeach()
endif()
if(_result)
if(_args_USE_CDATA)
set(_value_before "")
endif()
list(LENGTH _result _result_len)
if(_result_len GREATER 1 AND _args_LIST_GLUE)
list(JOIN _result "${_args_LIST_GLUE}" _result)
endif()
set(${OUTPUT_VAR_NAME} "${_value_before}${_result}${_value_after}" PARENT_SCOPE)
endif()
endfunction()
function(_cpack_nuget_variable_fallback_and_wrap_into_element ELEMENT NUGET_VAR_NAME)
set(_options)
set(_one_value_args)
set(_multi_value_args FALLBACK_VARS ATTRIBUTES)
cmake_parse_arguments(PARSE_ARGV 2 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
if(_args_ATTRIBUTES)
list(JOIN _args_ATTRIBUTES " " _attributes)
string(PREPEND _attributes " ")
endif()
_cpack_nuget_variable_fallback(_value ${NUGET_VAR_NAME} ${ARGN} USE_CDATA)
string(TOUPPER "${ELEMENT}" _ELEMENT_UP)
if(_value)
set(
_CPACK_NUGET_${_ELEMENT_UP}_TAG
"<${ELEMENT}${_attributes}>${_value}${ELEMENT}>"
PARENT_SCOPE
)
elseif(_attributes)
set(
_CPACK_NUGET_${_ELEMENT_UP}_TAG
"<${ELEMENT}${_attributes} />"
PARENT_SCOPE
)
endif()
endfunction()
# Warn of obsolete nuspec fields, referencing CMake variables and suggested
# replacement, if any
function(_cpack_nuget_deprecation_warning NUGET_ELEMENT VARNAME REPLACEMENT)
if(${VARNAME})
if(REPLACEMENT)
message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider replacing `${VARNAME}` with `${REPLACEMENT}`")
else()
message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider removing `${VARNAME}`")
endif()
endif()
endfunction()
# Print some debug info
_cpack_nuget_debug("---[CPack NuGet Input Variables]---")
_cpack_nuget_debug_var(CPACK_PACKAGE_NAME)
_cpack_nuget_debug_var(CPACK_PACKAGE_VERSION)
_cpack_nuget_debug_var(CPACK_TOPLEVEL_TAG)
_cpack_nuget_debug_var(CPACK_TOPLEVEL_DIRECTORY)
_cpack_nuget_debug_var(CPACK_TEMPORARY_DIRECTORY)
_cpack_nuget_debug_var(CPACK_NUGET_GROUPS)
if(CPACK_NUGET_GROUPS)
foreach(_group IN LISTS CPACK_NUGET_GROUPS)
string(MAKE_C_IDENTIFIER "${_group}" _group_up)
string(TOUPPER "${_group_up}" _group_up)
_cpack_nuget_debug_var(CPACK_NUGET_${_group_up}_GROUP_COMPONENTS)
endforeach()
endif()
_cpack_nuget_debug_var(CPACK_NUGET_COMPONENTS)
_cpack_nuget_debug_var(CPACK_NUGET_ALL_IN_ONE)
_cpack_nuget_debug_var(CPACK_NUGET_ORDINAL_MONOLITIC)
_cpack_nuget_debug("-----------------------------------")
function(_cpack_nuget_render_spec)
# Make a variable w/ upper-cased component name
if(CPACK_NUGET_PACKAGE_COMPONENT)
string(TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}" CPACK_NUGET_PACKAGE_COMPONENT_UPPER)
endif()
# Set mandatory variables (not wrapped into XML elements)
# https://docs.microsoft.com/en-us/nuget/reference/nuspec#required-metadata-elements
if(CPACK_NUGET_PACKAGE_COMPONENT)
if(CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME)
set(
CPACK_NUGET_PACKAGE_NAME
"${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME}"
)
elseif(NOT CPACK_NUGET_PACKAGE_COMPONENT STREQUAL "Unspecified")
set(
CPACK_NUGET_PACKAGE_NAME
"${CPACK_PACKAGE_NAME}.${CPACK_NUGET_PACKAGE_COMPONENT}"
)
else()
set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
endif()
elseif(NOT CPACK_NUGET_PACKAGE_NAME)
set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
endif()
# Warn about deprecated nuspec elements; warnings only display if
# variable is set
# Note that while nuspec's "summary" element is deprecated, there
# is no suggested replacement so (for now) no deprecation warning
# is shown for `CPACK_NUGET_*_DESCRIPTION_SUMMARY`
_cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_PACKAGE_LICENSEURL
"CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME or CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION")
_cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSEURL
"CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_FILE_NAME or CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_EXPRESSION")
_cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_PACKAGE_ICONURL
"CPACK_NUGET_PACKAGE_ICON")
_cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICONURL
"CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICON")
# Set nuspec fields
_cpack_nuget_variable_fallback(
CPACK_NUGET_PACKAGE_VERSION VERSION
FALLBACK_VARS
CPACK_PACKAGE_VERSION
)
_cpack_nuget_variable_fallback(
CPACK_NUGET_PACKAGE_DESCRIPTION DESCRIPTION
FALLBACK_VARS
CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DESCRIPTION
CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
CPACK_PACKAGE_DESCRIPTION
USE_CDATA
)
_cpack_nuget_variable_fallback(
CPACK_NUGET_PACKAGE_AUTHORS AUTHORS
FALLBACK_VARS
CPACK_PACKAGE_VENDOR
USE_CDATA
LIST_GLUE ","
)
# Set optional variables (wrapped into XML elements)
# https://docs.microsoft.com/en-us/nuget/reference/nuspec#optional-metadata-elements
_cpack_nuget_variable_fallback_and_wrap_into_element(
title
TITLE
FALLBACK_VARS
CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DISPLAY_NAME
CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
)
_cpack_nuget_variable_fallback_and_wrap_into_element(owners OWNERS LIST_GLUE ",")
_cpack_nuget_variable_fallback_and_wrap_into_element(
projectUrl
HOMEPAGE_URL
FALLBACK_VARS
CPACK_PACKAGE_HOMEPAGE_URL
)
# "licenseUrl" is deprecated in favor of "license"
_cpack_nuget_variable_fallback_and_wrap_into_element(licenseUrl LICENSEURL)
# "iconUrl" is deprecated in favor of "icon"
_cpack_nuget_variable_fallback_and_wrap_into_element(iconUrl ICONURL)
# "license" takes a "type" attribute of either "file" or "expression"
# "file" refers to a file path of a .txt or .md file relative to the installation root
# "expression" refers to simple or compound expression of license identifiers
# listed at https://spdx.org/licenses/
# Note that only one of CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME and
# CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION may be specified. If both are specified,
# CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME takes precedence and CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION is ignored.
if(CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME)
_cpack_nuget_variable_fallback_and_wrap_into_element(
license LICENSE_FILE_NAME
ATTRIBUTES [[type="file"]]
)
elseif(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION)
_cpack_nuget_variable_fallback_and_wrap_into_element(
license LICENSE_EXPRESSION
ATTRIBUTES [[type="expression"]]
)
endif()
# "icon" refers to a file path relative to the installation root
_cpack_nuget_variable_fallback_and_wrap_into_element(icon ICON)
# "summary" is deprecated in favor of "description"
_cpack_nuget_variable_fallback_and_wrap_into_element(
summary DESCRIPTION_SUMMARY
FALLBACK_VARS
CPACK_PACKAGE_DESCRIPTION_SUMMARY
)
if(CPACK_NUGET_PACKAGE_REQUIRE_LICENSE_ACCEPTANCE)
set(
_CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG
"true"
)
endif()
_cpack_nuget_variable_fallback_and_wrap_into_element(releaseNotes RELEASE_NOTES)
_cpack_nuget_variable_fallback_and_wrap_into_element(copyright COPYRIGHT)
# "language" is a locale identifier such as "en_CA"
_cpack_nuget_variable_fallback_and_wrap_into_element(language LANGUAGE)
_cpack_nuget_variable_fallback_and_wrap_into_element(tags TAGS LIST_GLUE " ")
# "repository" holds repository metadata consisting of four optional
# attributes: "type", "url", "branch", and "commit". While all fields are
# considered optional, they are not independent. Currently unsupported.
# Handle dependencies
_cpack_nuget_variable_fallback(_deps DEPENDENCIES)
set(_collected_deps)
foreach(_dep IN LISTS _deps)
_cpack_nuget_debug(" checking dependency `${_dep}`")
_cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep}_VERSION)
if(NOT _ver)
string(TOUPPER "${_dep}" _dep_upper)
_cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_upper}_VERSION)
endif()
if(_ver)
_cpack_nuget_debug(" got `${_dep}` dependency version ${_ver}")
string(CONCAT _collected_deps "${_collected_deps}" " \n")
endif()
endforeach()
# Render deps into the variable
if(_collected_deps)
string(CONCAT _CPACK_NUGET_DEPENDENCIES_TAG "\n" "${_collected_deps}" " ")
endif()
# Render the spec file
# NOTE The spec filename doesn't matter. Being included into a package,
# NuGet will name it properly.
_cpack_nuget_debug("Rendering `${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec` file...")
configure_file(
"${CMAKE_ROOT}/Modules/Internal/CPack/CPack.NuGet.nuspec.in"
"${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec"
@ONLY
)
endfunction()
function(_cpack_nuget_make_files_tag)
set(_files)
foreach(_comp IN LISTS ARGN)
string(APPEND _files " \n")
endforeach()
set(_CPACK_NUGET_FILES_TAG "\n${_files} " PARENT_SCOPE)
endfunction()
find_program(NUGET_EXECUTABLE nuget)
_cpack_nuget_debug_var(NUGET_EXECUTABLE)
if(NOT NUGET_EXECUTABLE)
message(FATAL_ERROR "NuGet executable not found")
endif()
# Add details for debug run
if(CPACK_NUGET_PACKAGE_DEBUG)
list(APPEND CPACK_NUGET_PACK_ADDITIONAL_OPTIONS "-Verbosity" "detailed")
endif()
# Case one: ordinal all-in-one package
if(CPACK_NUGET_ORDINAL_MONOLITIC)
# This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
# Meaning to pack all installed files into a single package
_cpack_nuget_debug("---[Making an ordinal monolitic package]---")
_cpack_nuget_render_spec()
execute_process(
COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
RESULT_VARIABLE _nuget_result
)
if(NOT _nuget_result EQUAL 0)
message(FATAL_ERROR "Nuget pack failed")
endif()
elseif(CPACK_NUGET_ALL_IN_ONE)
# This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
# Meaning to pack all installed components into a single package
_cpack_nuget_debug("---[Making a monolitic package from installed components]---")
# Prepare the `files` element which include files from several components
_cpack_nuget_make_files_tag(${CPACK_NUGET_COMPONENTS})
_cpack_nuget_render_spec()
execute_process(
COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
RESULT_VARIABLE _nuget_result
)
if(NOT _nuget_result EQUAL 0)
message(FATAL_ERROR "Nuget pack failed")
endif()
else()
# Is there any grouped component?
if(CPACK_NUGET_GROUPS)
_cpack_nuget_debug("---[Making grouped component(s) package(s)]---")
foreach(_group IN LISTS CPACK_NUGET_GROUPS)
_cpack_nuget_debug("Starting to make the package for group `${_group}`")
string(MAKE_C_IDENTIFIER "${_group}" _group_up)
string(TOUPPER "${_group_up}" _group_up)
# Render a spec file which includes all components in the current group
unset(_CPACK_NUGET_FILES_TAG)
_cpack_nuget_make_files_tag(${CPACK_NUGET_${_group_up}_GROUP_COMPONENTS})
# Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the group name
# to properly collect various per group settings
set(CPACK_NUGET_PACKAGE_COMPONENT ${_group})
_cpack_nuget_render_spec()
unset(CPACK_NUGET_PACKAGE_COMPONENT)
execute_process(
COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
RESULT_VARIABLE _nuget_result
)
if(NOT _nuget_result EQUAL 0)
message(FATAL_ERROR "Nuget pack failed")
endif()
endforeach()
endif()
# Is there any single component package needed?
if(CPACK_NUGET_COMPONENTS)
_cpack_nuget_debug("---[Making single-component(s) package(s)]---")
foreach(_comp IN LISTS CPACK_NUGET_COMPONENTS)
_cpack_nuget_debug("Starting to make the package for component `${_comp}`")
# Render a spec file which includes only given component
unset(_CPACK_NUGET_FILES_TAG)
_cpack_nuget_make_files_tag(${_comp})
# Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the current
# component name to properly collect various per group settings
set(CPACK_NUGET_PACKAGE_COMPONENT ${_comp})
_cpack_nuget_render_spec()
unset(CPACK_NUGET_PACKAGE_COMPONENT)
execute_process(
COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
RESULT_VARIABLE _nuget_result
)
if(NOT _nuget_result EQUAL 0)
message(FATAL_ERROR "Nuget pack failed")
endif()
endforeach()
endif()
endif()
file(GLOB_RECURSE GEN_CPACK_OUTPUT_FILES "${CPACK_TEMPORARY_DIRECTORY}/*.nupkg")
if(NOT GEN_CPACK_OUTPUT_FILES)
message(FATAL_ERROR "NuGet package was not generated at `${CPACK_TEMPORARY_DIRECTORY}`!")
endif()
_cpack_nuget_debug("Generated files: ${GEN_CPACK_OUTPUT_FILES}")