CPackNuGet.cmake 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. # Author: Alex Turbov
  4. if(CMAKE_BINARY_DIR)
  5. message(FATAL_ERROR "CPackNuGet.cmake may only be used by CPack internally.")
  6. endif()
  7. function(_cpack_nuget_debug)
  8. if(CPACK_NUGET_PACKAGE_DEBUG)
  9. message("CPackNuGet:Debug: " ${ARGN})
  10. endif()
  11. endfunction()
  12. function(_cpack_nuget_debug_var NAME)
  13. if(CPACK_NUGET_PACKAGE_DEBUG)
  14. message("CPackNuGet:Debug: ${NAME}=`${${NAME}}`")
  15. endif()
  16. endfunction()
  17. function(_cpack_nuget_variable_fallback OUTPUT_VAR_NAME NUGET_VAR_NAME)
  18. if(ARGN)
  19. list(JOIN ARGN "`, `" _va_args)
  20. set(_va_args ", ARGN: `${_va_args}`")
  21. endif()
  22. _cpack_nuget_debug(
  23. "_cpack_nuget_variable_fallback: "
  24. "OUTPUT_VAR_NAME=`${OUTPUT_VAR_NAME}`, "
  25. "NUGET_VAR_NAME=`${NUGET_VAR_NAME}`"
  26. "${_va_args}"
  27. )
  28. set(_options USE_CDATA)
  29. set(_one_value_args LIST_GLUE)
  30. set(_multi_value_args FALLBACK_VARS)
  31. cmake_parse_arguments(PARSE_ARGV 0 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
  32. if(CPACK_NUGET_PACKAGE_COMPONENT)
  33. string(
  34. TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}"
  35. CPACK_NUGET_PACKAGE_COMPONENT_UPPER
  36. )
  37. endif()
  38. if(CPACK_NUGET_PACKAGE_COMPONENT
  39. AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}
  40. )
  41. set(
  42. _result
  43. "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}}"
  44. )
  45. _cpack_nuget_debug(
  46. " CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}: "
  47. "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
  48. )
  49. elseif(CPACK_NUGET_PACKAGE_COMPONENT_UPPER
  50. AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}
  51. )
  52. set(
  53. _result
  54. "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}}"
  55. )
  56. _cpack_nuget_debug(
  57. " CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}: "
  58. "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
  59. )
  60. elseif(CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME})
  61. set(_result "${CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}}")
  62. _cpack_nuget_debug(
  63. " CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}: "
  64. "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
  65. )
  66. else()
  67. foreach(_var IN LISTS _args_FALLBACK_VARS)
  68. _cpack_nuget_debug(" Fallback: ${_var} ...")
  69. if(${_var})
  70. _cpack_nuget_debug(" ${_var}=`${${_var}}`")
  71. set(_result "${${_var}}")
  72. _cpack_nuget_debug(
  73. " ${_var}: OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
  74. )
  75. break()
  76. endif()
  77. endforeach()
  78. endif()
  79. if(_result)
  80. if(_args_USE_CDATA)
  81. set(_value_before "<![CDATA[")
  82. set(_value_after "]]>")
  83. endif()
  84. list(LENGTH _result _result_len)
  85. if(_result_len GREATER 1 AND _args_LIST_GLUE)
  86. list(JOIN _result "${_args_LIST_GLUE}" _result)
  87. endif()
  88. set(${OUTPUT_VAR_NAME} "${_value_before}${_result}${_value_after}" PARENT_SCOPE)
  89. endif()
  90. endfunction()
  91. function(_cpack_nuget_variable_fallback_and_wrap_into_element ELEMENT NUGET_VAR_NAME)
  92. set(_options)
  93. set(_one_value_args)
  94. set(_multi_value_args FALLBACK_VARS)
  95. cmake_parse_arguments(PARSE_ARGV 0 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
  96. _cpack_nuget_variable_fallback(_value ${NUGET_VAR_NAME} ${ARGN} USE_CDATA)
  97. if(_value)
  98. string(TOUPPER "${ELEMENT}" _ELEMENT_UP)
  99. set(
  100. _CPACK_NUGET_${_ELEMENT_UP}_TAG
  101. "<${ELEMENT}>${_value}</${ELEMENT}>"
  102. PARENT_SCOPE
  103. )
  104. endif()
  105. endfunction()
  106. # Print some debug info
  107. _cpack_nuget_debug("---[CPack NuGet Input Variables]---")
  108. _cpack_nuget_debug_var(CPACK_PACKAGE_NAME)
  109. _cpack_nuget_debug_var(CPACK_PACKAGE_VERSION)
  110. _cpack_nuget_debug_var(CPACK_TOPLEVEL_TAG)
  111. _cpack_nuget_debug_var(CPACK_TOPLEVEL_DIRECTORY)
  112. _cpack_nuget_debug_var(CPACK_TEMPORARY_DIRECTORY)
  113. _cpack_nuget_debug_var(CPACK_NUGET_GROUPS)
  114. if(CPACK_NUGET_GROUPS)
  115. foreach(_group IN LISTS CPACK_NUGET_GROUPS)
  116. string(MAKE_C_IDENTIFIER "${_group}" _group_up)
  117. string(TOUPPER "${_group_up}" _group_up)
  118. _cpack_nuget_debug_var(CPACK_NUGET_${_group_up}_GROUP_COMPONENTS)
  119. endforeach()
  120. endif()
  121. _cpack_nuget_debug_var(CPACK_NUGET_COMPONENTS)
  122. _cpack_nuget_debug_var(CPACK_NUGET_ALL_IN_ONE)
  123. _cpack_nuget_debug_var(CPACK_NUGET_ORDINAL_MONOLITIC)
  124. _cpack_nuget_debug("-----------------------------------")
  125. function(_cpack_nuget_render_spec)
  126. # Make a variable w/ upper-cased component name
  127. if(CPACK_NUGET_PACKAGE_COMPONENT)
  128. string(TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}" CPACK_NUGET_PACKAGE_COMPONENT_UPPER)
  129. endif()
  130. # Set mandatory variables (not wrapped into XML elements)
  131. # https://docs.microsoft.com/en-us/nuget/reference/nuspec#required-metadata-elements
  132. if(CPACK_NUGET_PACKAGE_COMPONENT)
  133. if(CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME)
  134. set(
  135. CPACK_NUGET_PACKAGE_NAME
  136. "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME}"
  137. )
  138. elseif(NOT CPACK_NUGET_PACKAGE_COMPONENT STREQUAL "Unspecified")
  139. set(
  140. CPACK_NUGET_PACKAGE_NAME
  141. "${CPACK_PACKAGE_NAME}.${CPACK_NUGET_PACKAGE_COMPONENT}"
  142. )
  143. else()
  144. set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
  145. endif()
  146. elseif(NOT CPACK_NUGET_PACKAGE_NAME)
  147. set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
  148. endif()
  149. _cpack_nuget_variable_fallback(
  150. CPACK_NUGET_PACKAGE_VERSION VERSION
  151. FALLBACK_VARS
  152. CPACK_PACKAGE_VERSION
  153. )
  154. _cpack_nuget_variable_fallback(
  155. CPACK_NUGET_PACKAGE_DESCRIPTION DESCRIPTION
  156. FALLBACK_VARS
  157. CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DESCRIPTION
  158. CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
  159. CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
  160. CPACK_PACKAGE_DESCRIPTION
  161. USE_CDATA
  162. )
  163. _cpack_nuget_variable_fallback(
  164. CPACK_NUGET_PACKAGE_AUTHORS AUTHORS
  165. FALLBACK_VARS
  166. CPACK_PACKAGE_VENDOR
  167. USE_CDATA
  168. LIST_GLUE ","
  169. )
  170. # Set optional variables (wrapped into XML elements)
  171. # https://docs.microsoft.com/en-us/nuget/reference/nuspec#optional-metadata-elements
  172. _cpack_nuget_variable_fallback_and_wrap_into_element(
  173. title
  174. TITLE
  175. FALLBACK_VARS
  176. CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DISPLAY_NAME
  177. CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
  178. CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
  179. )
  180. _cpack_nuget_variable_fallback_and_wrap_into_element(owners OWNERS LIST_GLUE ",")
  181. _cpack_nuget_variable_fallback_and_wrap_into_element(
  182. projectUrl
  183. HOMEPAGE_URL
  184. FALLBACK_VARS
  185. CPACK_PACKAGE_HOMEPAGE_URL
  186. )
  187. _cpack_nuget_variable_fallback_and_wrap_into_element(licenseUrl LICENSEURL)
  188. _cpack_nuget_variable_fallback_and_wrap_into_element(iconUrl ICONURL)
  189. _cpack_nuget_variable_fallback_and_wrap_into_element(
  190. summary DESCRIPTION_SUMMARY
  191. FALLBACK_VARS
  192. CPACK_PACKAGE_DESCRIPTION_SUMMARY
  193. )
  194. if(CPACK_NUGET_PACKAGE_REQUIRE_LICENSE_ACCEPTANCE)
  195. set(
  196. _CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG
  197. "<requireLicenseAcceptance>true</requireLicenseAcceptance>"
  198. )
  199. endif()
  200. _cpack_nuget_variable_fallback_and_wrap_into_element(releaseNotes RELEASE_NOTES)
  201. _cpack_nuget_variable_fallback_and_wrap_into_element(copyright COPYRIGHT)
  202. _cpack_nuget_variable_fallback_and_wrap_into_element(tags TAGS LIST_GLUE " ")
  203. # Handle dependencies
  204. _cpack_nuget_variable_fallback(_deps DEPENDENCIES)
  205. set(_collected_deps)
  206. foreach(_dep IN LISTS _deps)
  207. _cpack_nuget_debug(" checking dependency `${_dep}`")
  208. string(MAKE_C_IDENTIFIER "${_dep}" _dep_id)
  209. _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_id}_VERSION)
  210. if(NOT _ver)
  211. string(TOUPPER "${_dep_id}" _dep_id)
  212. _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_id}_VERSION)
  213. endif()
  214. if(_ver)
  215. _cpack_nuget_debug(" got `${_dep}` dependency version ${_ver}")
  216. list(APPEND _collected_deps "<dependency id=\"${_dep}\" version=\"${_ver}\" />")
  217. endif()
  218. endforeach()
  219. # Render deps into the variable
  220. if(_collected_deps)
  221. set(_CPACK_NUGET_DEPENDENCIES_TAG "<dependencies>\n")
  222. foreach(_line IN LISTS _collected_deps)
  223. string(
  224. APPEND _CPACK_NUGET_DEPENDENCIES_TAG
  225. " ${_line}\n"
  226. )
  227. endforeach()
  228. string(APPEND _CPACK_NUGET_DEPENDENCIES_TAG " </dependencies>")
  229. endif()
  230. # Render the spec file
  231. # NOTE The spec filename doesn't matter. Being included into a package,
  232. # NuGet will name it properly.
  233. _cpack_nuget_debug("Rendering `${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec` file...")
  234. configure_file(
  235. "${CMAKE_ROOT}/Modules/Internal/CPack/CPack.NuGet.nuspec.in"
  236. "${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec"
  237. @ONLY
  238. )
  239. endfunction()
  240. function(_cpack_nuget_make_files_tag)
  241. set(_files)
  242. foreach(_comp IN LISTS ARGN)
  243. string(APPEND _files " <file src=\"${_comp}\\**\" target=\".\" />\n")
  244. endforeach()
  245. set(_CPACK_NUGET_FILES_TAG "<files>\n${_files} </files>" PARENT_SCOPE)
  246. endfunction()
  247. find_program(NUGET_EXECUTABLE nuget)
  248. _cpack_nuget_debug_var(NUGET_EXECUTABLE)
  249. if(NOT NUGET_EXECUTABLE)
  250. message(FATAL_ERROR "NuGet executable not found")
  251. endif()
  252. # Add details for debug run
  253. if(CPACK_NUGET_PACKAGE_DEBUG)
  254. list(APPEND CPACK_NUGET_PACK_ADDITIONAL_OPTIONS "-Verbosity" "detailed")
  255. endif()
  256. # Case one: ordinal all-in-one package
  257. if(CPACK_NUGET_ORDINAL_MONOLITIC)
  258. # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
  259. # Meaning to pack all installed files into a single package
  260. _cpack_nuget_debug("---[Making an ordinal monolitic package]---")
  261. _cpack_nuget_render_spec()
  262. execute_process(
  263. COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
  264. WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
  265. )
  266. elseif(CPACK_NUGET_ALL_IN_ONE)
  267. # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
  268. # Meaning to pack all installed components into a single package
  269. _cpack_nuget_debug("---[Making a monolitic package from installed components]---")
  270. # Prepare the `files` element which include files from several components
  271. _cpack_nuget_make_files_tag(${CPACK_NUGET_COMPONENTS})
  272. _cpack_nuget_render_spec()
  273. execute_process(
  274. COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
  275. WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
  276. )
  277. else()
  278. # Is there any grouped component?
  279. if(CPACK_NUGET_GROUPS)
  280. _cpack_nuget_debug("---[Making grouped component(s) package(s)]---")
  281. foreach(_group IN LISTS CPACK_NUGET_GROUPS)
  282. _cpack_nuget_debug("Starting to make the package for group `${_group}`")
  283. string(MAKE_C_IDENTIFIER "${_group}" _group_up)
  284. string(TOUPPER "${_group_up}" _group_up)
  285. # Render a spec file which includes all components in the current group
  286. unset(_CPACK_NUGET_FILES_TAG)
  287. _cpack_nuget_make_files_tag(${CPACK_NUGET_${_group_up}_GROUP_COMPONENTS})
  288. # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the group name
  289. # to properly collect various per group settings
  290. set(CPACK_NUGET_PACKAGE_COMPONENT ${_group})
  291. _cpack_nuget_render_spec()
  292. unset(CPACK_NUGET_PACKAGE_COMPONENT)
  293. execute_process(
  294. COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
  295. WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
  296. )
  297. endforeach()
  298. endif()
  299. # Is there any single component package needed?
  300. if(CPACK_NUGET_COMPONENTS)
  301. _cpack_nuget_debug("---[Making single-component(s) package(s)]---")
  302. foreach(_comp IN LISTS CPACK_NUGET_COMPONENTS)
  303. _cpack_nuget_debug("Starting to make the package for component `${_comp}`")
  304. # Render a spec file which includes only given component
  305. unset(_CPACK_NUGET_FILES_TAG)
  306. _cpack_nuget_make_files_tag(${_comp})
  307. # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the current
  308. # component name to properly collect various per group settings
  309. set(CPACK_NUGET_PACKAGE_COMPONENT ${_comp})
  310. _cpack_nuget_render_spec()
  311. unset(CPACK_NUGET_PACKAGE_COMPONENT)
  312. execute_process(
  313. COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
  314. WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
  315. )
  316. endforeach()
  317. endif()
  318. endif()
  319. file(GLOB_RECURSE GEN_CPACK_OUTPUT_FILES "${CPACK_TEMPORARY_DIRECTORY}/*.nupkg")
  320. if(NOT GEN_CPACK_OUTPUT_FILES)
  321. message(FATAL_ERROR "NuGet package was not generated at `${CPACK_TEMPORARY_DIRECTORY}`!")
  322. endif()
  323. _cpack_nuget_debug("Generated files: ${GEN_CPACK_OUTPUT_FILES}")