diff --git a/CMakeLists.txt b/CMakeLists.txt index e71f1c889..c0a800750 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -606,6 +606,7 @@ install( "CMakeModules/CalamaresAddTest.cmake" "CMakeModules/CalamaresAddTranslations.cmake" "CMakeModules/CalamaresAutomoc.cmake" + "CMakeModules/CalamaresCheckModuleSelection.cmake" "CMakeModules/CMakeColors.cmake" "CMakeModules/FindYAMLCPP.cmake" DESTINATION diff --git a/CMakeModules/CalamaresAddModuleSubdirectory.cmake b/CMakeModules/CalamaresAddModuleSubdirectory.cmake index 9435021c1..a08f1162e 100644 --- a/CMakeModules/CalamaresAddModuleSubdirectory.cmake +++ b/CMakeModules/CalamaresAddModuleSubdirectory.cmake @@ -12,67 +12,38 @@ # Function and support code for adding a Calamares module (either a Qt / C++ plugin, # or a Python module, or whatever) to the build. # +# # Usage +# +# The public API is one single function: +# +# - calamares_add_module_subdirectory(subdirectory [skiplistvar]) +# Adds a given *subdirectory* to the modules list, building the +# module that is there. The *subdirectory* must contain a `module.desc` +# (generally non-C++ modules) or a `CMakeLists.txt` (for C++ modules, +# or special cases). The module is assumed to be named after the +# (last component of) the subdirectory. +# +# If the module would be skipped (by the global SKIP_MODULES setting +# or a USE_* setting) or the module itself sets a reason to skip +# via the calamares_skip_module() function, the module is added to +# the list of skipped-modules in *skiplistvar*. If no variable is +# given, the reason is set in the parent scope variable +# SKIPPED_MODULES . Do **not** use SKIPPED_MODULES as the name of +# *skiplistvar*, things will get weird. +# + include( CalamaresAddTranslations ) +include( CalamaresCheckModuleSelection ) set( MODULE_DATA_DESTINATION share/calamares/modules ) -# Convenience function to indicate that a module has been skipped -# (optionally also why). Call this in the module's CMakeLists.txt -macro( calamares_skip_module ) - set( SKIPPED_MODULES ${SKIPPED_MODULES} ${ARGV} PARENT_SCOPE ) -endmacro() - -function( calamares_explain_skipped_modules ) - if ( ARGN ) - message( "${ColorReset}-- Skipped modules:" ) - foreach( SUBDIRECTORY ${ARGN} ) - message( "${ColorReset}-- Skipped ${BoldRed}${SUBDIRECTORY}${ColorReset}." ) - endforeach() - message( "" ) - endif() -endfunction() - -# Globally, SKIP_MODULES and USE_* affect what modules are built. -# Check if *modulename* should be skipped, and if so, set *outvar* to -# a human-readable reason for skipping it. -function( calamares_check_skip modulename outvar ) - # Globally-defined SKIP_MODULES may be space- or semicolon- separated - # so convert it to a list-variable. - string( REPLACE " " ";" SKIP_LIST "${SKIP_MODULES}" ) - - list( FIND SKIP_LIST "${modulename}" DO_SKIP ) - if( NOT DO_SKIP EQUAL -1 ) - set( ${outvar} "user request" PARENT_SCOPE ) - return() - endif() - - # Not skipped by the global check, see if it has an applicable USE_* - if( "${modulename}" MATCHES "^[a-zA-Z0-9_]+-" ) - # Split the name into - - string( REGEX REPLACE "-.*" "" _category "${modulename}" ) - string( REGEX REPLACE "^[^-]+-" "" _implementation "${modulename}" ) - else() - # Not a module to which USE_* applies - return() - endif() - - if( NOT "${UsE_${_category}}" ) - # Category not set at all or nonexistent - return() - elseif( "${USE_${_category}}" STREQUAL "none" ) - set( ${outvar} "category ${_category} disabled" PARENT_SCOPE ) - elseif( NOT "${USE_${_category}}" STREQUAL "${modulename}" ) - set( ${outvar} "category ${_category} selects ${USE_${_category}}" PARENT_SCOPE ) - endif() -endfunction() - -function( calamares_add_module_subdirectory ) +function( _calamares_add_module_subdirectory_impl ) set( SUBDIRECTORY ${ARGV0} ) # Set SKIPPED_MODULES here, so CMake-based modules have a # parent scope to set it in; this function, in turn sets it # in **its** parent scope. - set( SKIPPED_MODULES ) + set( SKIPPED_MODULES "" ) set( MODULE_CONFIG_FILES "" ) set( _mod_dir "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" ) @@ -85,6 +56,16 @@ function( calamares_add_module_subdirectory ) if ( SKIPPED_MODULES ) set( SKIPPED_MODULES ${SKIPPED_MODULES} PARENT_SCOPE ) set( MODULE_CONFIG_FILES "" ) + else() + # The SKIPPED_MODULES may be set in the directory itself + get_directory_property( _skip DIRECTORY ${SUBDIRECTORY} DEFINITION SKIPPED_MODULES ) + if ( _skip ) + set( SKIPPED_MODULES ${_skip} PARENT_SCOPE ) + set( MODULE_CONFIG_FILES "" ) + endif() + endif() + if ( SKIPPED_MODULES ) + return() endif() # ...otherwise, we look for a module.desc. elseif( EXISTS "${_mod_dir}/module.desc" ) @@ -110,9 +91,10 @@ function( calamares_add_module_subdirectory ) # _mod_testing boolean if the module should be added to the loadmodule tests file(STRINGS "${_mod_dir}/module.desc" MODULE_INTERFACE REGEX "^interface") if ( SKIPPED_MODULES ) - set( _mod_enabled OFF ) - set( _mod_reason "${SKIPPED_MODULES}" ) - set( _mod_testing OFF ) + # If it's skipped by infrastucture, the message already includes the module + # name. We don't need to do any further checking. + set( SKIPPED_MODULES "${SKIPPED_MODULES}" PARENT_SCOPE ) + return() elseif ( MODULE_INTERFACE MATCHES "pythonqt" ) set( _mod_enabled ${Calamares_WITH_PYTHONQT} ) set( _mod_reason "No PythonQt support" ) @@ -248,3 +230,19 @@ function( calamares_add_module_subdirectory ) endif() endif() endfunction() + +function( calamares_add_module_subdirectory ) + set( SUBDIRECTORY ${ARGV0} ) + set( _ams_SKIP_LIST ${ARGV1} ) + + set( SKIPPED_MODULES "" ) + _calamares_add_module_subdirectory_impl( ${SUBDIRECTORY} ) + if ( SKIPPED_MODULES ) + if ( _ams_SKIP_LIST ) + list( APPEND ${_ams_SKIP_LIST} "${SKIPPED_MODULES}" ) + set( ${_ams_SKIP_LIST} "${${_ams_SKIP_LIST}}" PARENT_SCOPE ) + else() + set( SKIPPED_MODULES "${SKIPPED_MODULES}" PARENT_SCOPE ) + endif() + endif() +endfunction() diff --git a/CMakeModules/CalamaresAddPlugin.cmake b/CMakeModules/CalamaresAddPlugin.cmake index 55865999c..5186bc54b 100644 --- a/CMakeModules/CalamaresAddPlugin.cmake +++ b/CMakeModules/CalamaresAddPlugin.cmake @@ -59,9 +59,17 @@ # If this is set, writes an explicit weight into the module.desc; # module weights are used in progress reporting. # +# +# This function follows the global SKIP_MODULES and USE_* settings, so +# a plugin may be skipped -- then nothing will be built. In that case, +# SKIPPED_MODULES is set in the parent (i.e. caller's) scope with the +# reason why. This should rarely be a concern as AddModuleSubdirectory +# already handles skip-reasons and collects them for reporting. include( CMakeParseArguments ) + include( CalamaresAddLibrary ) +include( CalamaresCheckModuleSelection ) include( CMakeColors ) function( calamares_add_plugin ) @@ -80,6 +88,12 @@ function( calamares_add_plugin ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) + calamares_check_skip( ${NAME} _skip) + if ( _skip ) + set( SKIPPED_MODULES "${_skip}" PARENT_SCOPE ) + return() + endif() + message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} module: ${BoldRed}${PLUGIN_NAME}${ColorReset}" ) message( " ${Green}TYPE:${ColorReset} ${PLUGIN_TYPE}" ) message( " ${Green}LINK_LIBRARIES:${ColorReset} ${PLUGIN_LINK_LIBRARIES}" ) diff --git a/CMakeModules/CalamaresCheckModuleSelection.cmake b/CMakeModules/CalamaresCheckModuleSelection.cmake new file mode 100644 index 000000000..5eeb0e970 --- /dev/null +++ b/CMakeModules/CalamaresCheckModuleSelection.cmake @@ -0,0 +1,116 @@ +# === This file is part of Calamares - === +# +# SPDX-FileCopyrightText: 2014 Teo Mrnjavac +# SPDX-FileCopyrightText: 2017 Adriaan de Groot +# SPDX-License-Identifier: BSD-2-Clause +# +# Calamares is Free Software: see the License-Identifier above. +# +### +# +# This module implements the "skip modules" part of configuring +# the Calamares repository or an external-modules repository. +# +# It should not be necessary to include() this module explicitly, +# since both AddPlugin and AddModuleSubdirectory do so implicitly. +# +# +# # Usage +# +# The public API is two functions: +# +# - calamares_skip_module(reason) +# A C++ module (or any that uses CMake) can call this macro to +# add *reason* to the list of skipped modules. Typically a module +# will pass in "modulename (why)" so that it is clear **which** +# module is skipped. This macro should be called at the top-level +# of a module's CMakeLists.txt and the module should then **not** +# call calamares_add_plugin(). +# - calamares_explain_skipped_modules(list...) +# This will print out all the module reasons (see above) that have +# been added to the given *listvar*. When AddModuleSubdirectory is +# used as the mechanism to add all the subdirectories in the repository +# that contain modules, with a consistent *listvar* setting, +# this will show all the modules that have been skipped. +# +# The internal API is one function: +# +# - calamares_check_skip(modulename outvar) +# Checks if the *modulename* has been listed in the global SKIP_MODULES +# variable (to skip specifically-named modules) or if there is a USE_* +# setting applicable to the module. If the module is skipped for this +# reason, a suitable entry is added to *outvar* as if +# calamares_skip_module() had been called. +# +# Best practice is to pick a variable to collect all of the skipped +# modules, and to pass the name of that variable to AddModuleSubdirectory +# in each call. After all subdirectories have been added, call +# calamares_explain_skipped_modules() with the value of that variable. + + +# Convenience function to indicate that a module has been skipped +# (optionally also why). Call this in the module's CMakeLists.txt +macro( calamares_skip_module ) + set( SKIPPED_MODULES ${SKIPPED_MODULES} ${ARGV} PARENT_SCOPE ) +endmacro() + +function( calamares_explain_skipped_modules ) + if ( ARGN ) + message( "${ColorReset}-- Skipped modules:" ) + foreach( SUBDIRECTORY ${ARGN} ) + message( "${ColorReset}-- Skipped ${BoldRed}${SUBDIRECTORY}${ColorReset}." ) + endforeach() + message( "" ) + endif() +endfunction() + +# Globally, SKIP_MODULES and USE_* affect what modules are built. +# Check if *modulename* should be skipped, and if so, set *outvar* to +# a human-readable reason for skipping it. +function( _calamares_check_skip_impl modulename outvar ) + # Globally-defined SKIP_MODULES may be space- or semicolon- separated + # so convert it to a list-variable. + string( REPLACE " " ";" SKIP_LIST "${SKIP_MODULES}" ) + + list( FIND SKIP_LIST "${modulename}" DO_SKIP ) + if( NOT DO_SKIP EQUAL -1 ) + set( ${outvar} "user request" PARENT_SCOPE ) + return() + endif() + + # Not skipped by the global check, see if it has an applicable USE_* + if( "${modulename}" MATCHES "^[a-zA-Z0-9_]+-" ) + # Split the name into - + string( REGEX REPLACE "-.*" "" _category "${modulename}" ) + string( REGEX REPLACE "^[^-]+-" "" _implementation "${modulename}" ) + else() + # Not a module to which USE_* applies + return() + endif() + + if( "${USE_${_category}}" STREQUAL "none" ) + set( ${outvar} "category ${_category} disabled" PARENT_SCOPE ) + return() + elseif( "${USE_${_category}}" STREQUAL "" ) + # Category not set at all or nonexistent + return() + endif() + + if ( "${USE_${_category}}" STREQUAL "${_implementation}" ) + # Matches, so accept this module + else() + set( ${outvar} "category ${_category} selects ${USE_${_category}}" PARENT_SCOPE ) + endif() +endfunction() + +# This is the public API;it calls the _impl version so that there +# is an extra intermediate scope for the subdirectory to write results into. +function( calamares_check_skip modulename outvar ) + set( _skip "" ) + _calamares_check_skip_impl( "${modulename}" _skip ) + if ( _skip ) + message( "${ColorReset}-- Skipping module ${BoldRed}${modulename} (${_skip})${ColorReset}." ) + message( "" ) + set( ${outvar} "${modulename} (${_skip})" PARENT_SCOPE ) + endif() +endfunction() diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 8e8c67848..03384105e 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -21,56 +21,8 @@ string( REPLACE " " ";" SKIP_LIST "${SKIP_MODULES}" ) file( GLOB SUBDIRECTORIES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*" ) list( SORT SUBDIRECTORIES ) -set( _use_categories "" ) -set( _found_categories "" ) - foreach( SUBDIRECTORY ${SUBDIRECTORIES} ) - list( FIND SKIP_LIST ${SUBDIRECTORY} DO_SKIP ) - - set( _skip_reason "user request" ) - # Handle the USE_ variables by looking for subdirectories - # with a - kind of name. - if( SUBDIRECTORY MATCHES "^[a-zA-Z0-9_]+-" ) - string( REGEX REPLACE "^[^-]+-" "" _implementation ${SUBDIRECTORY} ) - string( REGEX REPLACE "-.*" "" _category ${SUBDIRECTORY} ) - if( USE_${_category} ) - list( APPEND _use_categories ${_category} ) - if( "${_implementation}" STREQUAL "${USE_${_category}}" ) - list( APPEND _found_categories ${_category} ) - else() - list( APPEND SKIP_LIST ${SUBDIRECTORY} ) - set( _skip_reason "USE_${_category}=${USE_${_category}}" ) - set( DO_SKIP 1 ) - endif() - endif() - endif() - - if( NOT DO_SKIP EQUAL -1 ) - message( "${ColorReset}-- Skipping module ${BoldRed}${SUBDIRECTORY}${ColorReset}." ) - message( "" ) - list( APPEND LIST_SKIPPED_MODULES "${SUBDIRECTORY} (${_skip_reason})" ) - elseif( ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" ) AND - ( DO_SKIP EQUAL -1 ) ) - set( SKIPPED_MODULES ) - calamares_add_module_subdirectory( ${SUBDIRECTORY} ) - if ( SKIPPED_MODULES ) - list( APPEND LIST_SKIPPED_MODULES "${SKIPPED_MODULES}" ) - endif() - endif() -endforeach() - -# This is *also* done in top-level, so list is displayed -# both before and after the feature summary. -calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} ) - -foreach( _category ${_use_categories} ) - list( FIND _found_categories ${_category} _found ) - if ( ${USE_${_category}} STREQUAL "none" ) - set( _found 0 ) - endif() - if ( _found EQUAL -1 ) - message( FATAL_ERROR "USE_${_category} is set to ${USE_${_category}} and no module matches." ) - endif() + calamares_add_module_subdirectory( ${SUBDIRECTORY} LIST_SKIPPED_MODULES ) endforeach() # TODO:3.3: Use FindPython3