CPack disregards CPACK_COMPONENT_*_DEPENDS variables when restricting CPACK_COMPONENT_ALL
Use case:
We would like to create a subset of packages for a very big project consisting of hundreds of components. A use case is to install only tests and their dependencies for continuous integration. We have all dependencies among components specified thanks to CPACK_COMPONENTS_<component-name>_DEPENDS
variables in CPackConfig.cmake
.
Currently there is no way to say: I want only a subset of packages created, starting from one node in the DAG, and including its dependencies. We can't set CPACK_COMPONENT_ALL
to just one/two components, and have them packaged with their dependencies.
Listing hundreds of dependencies by hand is of course rather vexing. And we would like to reuse the same CPackConfig.cmake
files multiple times.
It would be very helpful if CPack could provide a boolean setting, i.e. CPACK_ALWAYS_INCLUDE_DEPENDENCIES
, to trigger this behavior internally.
Workaround:
At the moment, we have thought to roughly do the following as a workaround:
- We create a custom target "
package-subset
". Inside the target, we call the following custom script and then CPack. - The script reads CPackConfig.cmake. Inside the script, we compute the final set of real dependencies with something like:
cmake_minimum_required(VERSION 3.6)
if(NOT "$ENV{CPACK_OUTPUT_CONFIG_FILE}" STREQUAL "")
# allow override of default input file
set(INPUT_CONFIG "$ENV{CPACK_OUTPUT_CONFIG_FILE}")
endif()
if(NOT INPUT_CONFIG)
message(FATAL_ERROR "Missing INPUT_CONFIG variable, don't know where to read my input.")
elseif(NOT OUTPUT_CONFIG)
message(FATAL_ERROR "Missing OUTPUT_CONFIG variable, don't know where to write my output.")
elseif("$ENV{PACKAGE_SUBSET}" STREQUAL "")
message(FATAL_ERROR
"Expecting an environment variable PACKAGE_SUBSET with the list of components to package.")
endif()
# ------------------------------------------------------------------------------
function(recurse_on_components VAR)
list(APPEND ${VAR} ${ARGN})
foreach(c IN LISTS ARGN)
string(TOUPPER "CPACK_COMPONENT_${c}_PACKAGE_DEPENDS" c_depends)
recurse_on_components(${VAR} ${${c_depends}})
endforeach()
set(${VAR} ${${VAR}} PARENT_SCOPE)
endfunction()
# ------------------------------------------------------------------------------
# iterate over variables read from input
include(${INPUT_CONFIG})
get_cmake_property(vars VARIABLES)
list(FILTER vars INCLUDE REGEX "^CPACK_")
# add environment variables on top
execute_process(COMMAND ${CMAKE_COMMAND} -E environment
RESULT_VARIABLE result
OUTPUT_VARIABLE envvars
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT result EQUAL 0)
message(FATAL_ERROR "Cannot call ${CMAKE_COMMAND} to print environment variables")
endif()
string(REPLACE ";" "\;" envvars "${envvars}")
string(REPLACE "\n" ";" envvars "${envvars}")
foreach(envvar IN LISTS envvars)
string(REGEX MATCH "^[^=]+" varname "${envvar}")
if(NOT varname MATCHES "^CPACK_")
continue()
endif()
string(REGEX REPLACE "^[^=]+=" "" envvar "${envvar}")
set(${varname} "${envvar}")
list(APPEND vars ${varname})
endforeach()
# ------------------------------------------------------------------------------
unset(CPACK_COMPONENTS_ALL)
recurse_on_components(CPACK_COMPONENTS_ALL $ENV{PACKAGE_SUBSET})
list(REMOVE_DUPLICATES CPACK_COMPONENTS_ALL)
# ------------------------------------------------------------------------------
unset(output)
foreach(var IN LISTS vars)
string(REPLACE ";" "\;" ${var} "${${var}}")
string(REPLACE "\"" "\\\"" "${var}" "${${var}}")
list(APPEND output "set(${var} \"${${var}}\")\n")
endforeach()
string(CONCAT output ${output})
file(WRITE ${OUTPUT_CONFIG} "${output}")
# ------------------------------------------------------------------------------
- we save the output of the previous script in a
CPackConfig-restricted.cmake
. - we finally invoke CPack with the
--config
option on it.