| ####################### |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| # agreements. See the NOTICE file distributed with this work for additional information regarding |
| # copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with the License. You may obtain |
| # a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software distributed under the License |
| # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| # or implied. See the License for the specific language governing permissions and limitations under |
| # the License. |
| # |
| ####################### |
| |
| include(CheckIncludeFile) |
| |
| set(GLOBAL_AUTO_OPTION_VARS "") |
| |
| function(_REGISTER_AUTO_OPTION _NAME _FEATURE_VAR _DESCRIPTION _DEFAULT) |
| add_custom_target(${_NAME}_target) |
| set_target_properties(${_NAME}_target PROPERTIES AUTO_OPTION_FEATURE_VAR ${_FEATURE_VAR}) |
| |
| set(${_NAME} |
| ${_DEFAULT} |
| CACHE STRING "${_DESCRIPTION}" |
| ) |
| set_property(CACHE ${_NAME} PROPERTY STRINGS AUTO ON OFF) |
| |
| set(LOCAL_AUTO_OPTION_VARS ${GLOBAL_AUTO_OPTION_VARS}) |
| list(APPEND LOCAL_AUTO_OPTION_VARS "${_NAME}") |
| set(GLOBAL_AUTO_OPTION_VARS |
| ${LOCAL_AUTO_OPTION_VARS} |
| PARENT_SCOPE |
| ) |
| endfunction() |
| |
| macro(_CHECK_PACKAGE_DEPENDS _OPTION_VAR _PACKAGE_DEPENDS _FEATURE_VAR) |
| if(${${_OPTION_VAR}} STREQUAL AUTO) |
| set(STRICTNESS) |
| else() |
| set(STRICTNESS REQUIRED) |
| endif() |
| |
| foreach(PACKAGE_NAME ${_PACKAGE_DEPENDS}) |
| find_package(${PACKAGE_NAME} ${STRICTNESS}) |
| if(NOT ${PACKAGE_NAME}_FOUND) |
| set(${_FEATURE_VAR} FALSE) |
| break() |
| endif() |
| endforeach() |
| endmacro() |
| |
| macro(_CHECK_PACKAGE_DEPENDS_COMPONENTS _OPTION_VAR PACKAGE_NAME _FEATURE_VAR) |
| if(${${_OPTION_VAR}} STREQUAL AUTO) |
| set(STRICTNESS) |
| else() |
| set(STRICTNESS REQUIRED) |
| endif() |
| |
| foreach(C ${ARGN}) |
| list(APPEND FCOMPONENTS ${C}) |
| endforeach() |
| |
| find_package(${PACKAGE_NAME} COMPONENTS ${FCOMPONENTS} ${STRICTNESS}) |
| foreach(COMPONENT ${FCOMPONENTS}) |
| if(NOT ${PACKAGE_NAME}_${COMPONENT}_FOUND) |
| set(${_FEATURE_VAR} FALSE) |
| break() |
| endif() |
| endforeach() |
| endmacro() |
| |
| macro(_CHECK_HEADER_DEPENDS _OPTION_VAR _HEADER_DEPENDS _FEATURE_VAR) |
| foreach(HEADER_NAME ${_HEADER_DEPENDS}) |
| check_include_file(${HEADER_NAME} HEADER_FOUND) |
| if(NOT HEADER_FOUND) |
| set(${_FEATURE_VAR} FALSE) |
| break() |
| endif() |
| endforeach() |
| endmacro() |
| |
| macro(_CHECK_VAR_DEPENDS _OPTION_VAR _VAR_DEPENDS _FEATURE_VAR) |
| foreach(VAR_NAME ${_VAR_DEPENDS}) |
| if(${${VAR_NAME}}) |
| message(STATUS "${_FEATURE_VAR} requires ${VAR_NAME} -- found") |
| else() |
| if(NOT ${${_OPTION_VAR}} STREQUAL AUTO AND ${${_OPTION_VAR}}) |
| message( |
| FATAL_ERROR |
| "${_FEATURE_VAR} requires ${VAR_NAME} (hint: add -D${_OPTION_VAR}=OFF to disable this feature, or enable the missing dependency)" |
| ) |
| else() |
| message(STATUS "${_FEATURE_VAR} requires ${VAR_NAME} -- not found") |
| endif() |
| set(${_FEATURE_VAR} FALSE) |
| break() |
| endif() |
| endforeach() |
| endmacro() |
| |
| # auto_option(<feature_name> |
| # [DESCRIPTION <description>] |
| # [DEFAULT <default>] |
| # [FEATURE_VAR <feature_var>] |
| # [COMPONENT <component>] |
| # [PACKAGE_DEPENDS <package_one> ...] |
| # [HEADER_DEPENDS <header_one> ...] |
| # [VAR_DEPENDS <variable_one> ...] |
| # ) |
| # |
| # This macro registers a new auto option and sets its corresponding feature |
| # variable based on the requirements. The option it creates will be named |
| # ENABLE_<feature_name>, and the default feature variable will be |
| # USE_<feature_name>. |
| # |
| # It is necessary to have separate variables for the option and the feature |
| # because the option may be AUTO, but the feature must be enabled or not. |
| # It is expected that the option will have one of the values ON, OFF, or AUTO, |
| # and the feature will have one of the values TRUE, or FALSE. |
| # |
| # Behavior of the option is as follows: |
| # - The option is falsey: the feature variable will be FALSE. |
| # - The option is AUTO: if all requirements are satisfied, the |
| # feature variable will be TRUE, otherwise FALSE. |
| # - The option is truthy: if all requirements are satisfied, the |
| # feature variable will be TRUE, otherwise a fatal error is produced. |
| # |
| # DESCRIPTION is the description that will go with the cache entry for the |
| # option. If not provided, it will be empty. |
| # |
| # DEFAULT is the default value of the option. Permitted values are OFF, FALSE, 0 |
| # ON, TRUE, 1, AUTO. If no default is provided, AUTO is the default. |
| # |
| # FEATURE_VAR is the variable that will represent whether the feature should be |
| # used, given the value of the option and whether the requirements for the |
| # feature are satisfied. By default, it is USE_<feature_name>. |
| # |
| # COMPONENT check for a component of the package. Currently this only works if |
| # specifying a single package in PACKAGE_DEPENDS |
| # |
| # PACKAGE_DEPENDS is a list of packages that are required for the feature. |
| # |
| # HEADER_DEPENDS is a list of headers that are required for the feature. |
| # |
| # VAR_DEPENDS is a list of variables that must be truthy. |
| # |
| macro(auto_option _FEATURE_NAME) |
| cmake_parse_arguments( |
| ARG "" "DESCRIPTION;DEFAULT;FEATURE_VAR" "PACKAGE_DEPENDS;HEADER_DEPENDS;VAR_DEPENDS;COMPONENTS" ${ARGN} |
| ) |
| |
| set(OPTION_VAR "ENABLE_${_FEATURE_NAME}") |
| if(ARG_FEATURE_VAR) |
| set(FEATURE_VAR ${ARG_FEATURE_VAR}) |
| else() |
| set(FEATURE_VAR "USE_${_FEATURE_NAME}") |
| endif() |
| |
| if(ARG_DEFAULT STREQUAL OFF) |
| set(DEFAULT OFF) |
| elseif(NOT ARG_DEFAULT) |
| set(DEFAULT AUTO) |
| elseif(ARG_DEFAULT MATCHES "(ON)|(AUTO)|(TRUE)|(1)") |
| set(DEFAULT ${ARG_DEFAULT}) |
| else() |
| message(FATAL_ERROR "Invalid auto_option default ${ARG_DEFAULT}") |
| endif() |
| |
| _register_auto_option(${OPTION_VAR} ${FEATURE_VAR} "${ARG_DESCRIPTION}" "${DEFAULT}") |
| |
| if(${${OPTION_VAR}} MATCHES "(ON)|(AUTO)|(TRUE)|(1)") |
| set(${FEATURE_VAR} TRUE) |
| if(ARG_COMPONENTS) |
| _check_package_depends_components(${OPTION_VAR} ${ARG_PACKAGE_DEPENDS} ${FEATURE_VAR} ${ARG_COMPONENTS}) |
| else() |
| _check_package_depends(${OPTION_VAR} "${ARG_PACKAGE_DEPENDS}" ${FEATURE_VAR}) |
| endif() |
| _check_header_depends(${OPTION_VAR} "${ARG_HEADER_DEPENDS}" ${FEATURE_VAR}) |
| _check_var_depends(${OPTION_VAR} "${ARG_VAR_DEPENDS}" ${FEATURE_VAR}) |
| else() |
| set(${FEATURE_VAR} FALSE) |
| endif() |
| endmacro() |
| |
| # Prints a colorized summary of one auto option. |
| function(PRINT_AUTO_OPTION _NAME) |
| string(ASCII 27 ESC) |
| set(COLOR_RED "${ESC}[31m") |
| set(COLOR_GREEN "${ESC}[32m") |
| set(COLOR_RESET "${ESC}[m") |
| |
| set(OPTION_VALUE ${${_NAME}}) |
| |
| get_target_property(FEATURE "${_NAME}_target" AUTO_OPTION_FEATURE_VAR) |
| set(FEATURE_VALUE ${${FEATURE}}) |
| |
| set(RESET ${COLOR_RESET}) |
| if(FEATURE_VALUE) |
| # This accounts for both the ON and AUTO cases. |
| if(OPTION_VALUE) |
| set(COLOR ${COLOR_GREEN}) |
| set(HINT "(hint: add -D${_NAME}=OFF to disable)") |
| else() |
| message(WARNING "${FEATURE} truthy but ${_NAME} isn't!") |
| set(COLOR ${COLOR_RED}) |
| # There is no sensible hint for this case - things are |
| # on fire. |
| set(HINT "") |
| endif() |
| else() |
| # This should account only for the AUTO case. |
| # If the option is set to ON but dependencies were |
| # missing, then we should have errored out already. |
| if(OPTION_VALUE) |
| set(COLOR ${COLOR_RED}) |
| set(HINT "(hint: add -D${_NAME}=ON to require)") |
| else() |
| set(RESET "") |
| set(HINT "(hint: add -D${_NAME}=ON to enable)") |
| endif() |
| endif() |
| |
| message(STATUS "${FEATURE}: ${COLOR}${FEATURE_VALUE}${RESET} (${OPTION_VALUE}) ${HINT}") |
| endfunction() |
| |
| # Prints out a colorized summary of all auto options. |
| function(PRINT_AUTO_OPTIONS_SUMMARY) |
| message(STATUS "") |
| message(STATUS "-------- AUTO OPTIONS SUMMARY --------") |
| foreach(OPTION_NAME ${GLOBAL_AUTO_OPTION_VARS}) |
| print_auto_option(${OPTION_NAME}) |
| endforeach() |
| message(STATUS "") |
| endfunction() |