1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5FeatureSummary
6--------------
7
8Functions for generating a summary of enabled/disabled features.
9
10These functions can be used to generate a summary of enabled and disabled
11packages and/or feature for a build tree such as::
12
13    -- The following OPTIONAL packages have been found:
14    LibXml2 (required version >= 2.4), XML processing lib, <http://xmlsoft.org>
15       * Enables HTML-import in MyWordProcessor
16       * Enables odt-export in MyWordProcessor
17    PNG, A PNG image library., <http://www.libpng.org/pub/png/>
18       * Enables saving screenshots
19    -- The following OPTIONAL packages have not been found:
20    Lua51, The Lua scripting language., <http://www.lua.org>
21       * Enables macros in MyWordProcessor
22    Foo, Foo provides cool stuff.
23
24Global Properties
25^^^^^^^^^^^^^^^^^
26
27.. variable:: FeatureSummary_PKG_TYPES
28
29The global property :variable:`FeatureSummary_PKG_TYPES` defines the type of
30packages used by `FeatureSummary`.
31
32The order in this list is important, the first package type in the list is the
33least important, the last is the most important. the of a package can only be
34changed to higher types.
35
36The default package types are , ``RUNTIME``, ``OPTIONAL``, ``RECOMMENDED`` and
37``REQUIRED``, and their importance is
38``RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED``.
39
40
41.. variable:: FeatureSummary_REQUIRED_PKG_TYPES
42
43The global property :variable:`FeatureSummary_REQUIRED_PKG_TYPES` defines which
44package types are required.
45
46If one or more package in this categories has not been found, CMake will abort
47when calling :command:`feature_summary` with the
48'FATAL_ON_MISSING_REQUIRED_PACKAGES' option enabled.
49
50The default value for this global property is ``REQUIRED``.
51
52
53.. variable:: FeatureSummary_DEFAULT_PKG_TYPE
54
55The global property :variable:`FeatureSummary_DEFAULT_PKG_TYPE` defines which
56package type is the default one.
57When calling :command:`feature_summary`, if the user did not set the package type
58explicitly, the package will be assigned to this category.
59
60This value must be one of the types defined in the
61:variable:`FeatureSummary_PKG_TYPES` global property unless the package type
62is set for all the packages.
63
64The default value for this global property is ``OPTIONAL``.
65
66
67.. variable:: FeatureSummary_<TYPE>_DESCRIPTION
68
69.. versionadded:: 3.9
70
71The global property :variable:`FeatureSummary_<TYPE>_DESCRIPTION` can be defined
72for each type to replace the type name with the specified string whenever the
73package type is used in an output string.
74
75If not set, the string "``<TYPE>`` packages" is used.
76
77
78#]=======================================================================]
79
80get_property(_fsPkgTypeIsSet GLOBAL PROPERTY FeatureSummary_PKG_TYPES SET)
81if(NOT _fsPkgTypeIsSet)
82  set_property(GLOBAL PROPERTY FeatureSummary_PKG_TYPES RUNTIME OPTIONAL RECOMMENDED REQUIRED)
83endif()
84
85get_property(_fsReqPkgTypesIsSet GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES SET)
86if(NOT _fsReqPkgTypesIsSet)
87  set_property(GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES REQUIRED)
88endif()
89
90get_property(_fsDefaultPkgTypeIsSet GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE SET)
91if(NOT _fsDefaultPkgTypeIsSet)
92  set_property(GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE OPTIONAL)
93endif()
94
95#[=======================================================================[.rst:
96
97Functions
98^^^^^^^^^
99
100#]=======================================================================]
101
102function(_FS_GET_FEATURE_SUMMARY _property _var _includeQuiet)
103
104  get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
105  get_property(_fsDefaultPkgType GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE)
106
107  set(_type "ANY")
108  foreach(_fsPkgType ${_fsPkgTypes})
109    if("${_property}" MATCHES "${_fsPkgType}_PACKAGES_(NOT_)?FOUND")
110      set(_type "${_fsPkgType}")
111      break()
112    endif()
113  endforeach()
114
115  if("${_property}" MATCHES "PACKAGES_FOUND")
116    set(_property "PACKAGES_FOUND")
117  elseif("${_property}" MATCHES "PACKAGES_NOT_FOUND")
118    set(_property "PACKAGES_NOT_FOUND")
119  endif()
120
121
122  set(_currentFeatureText "")
123  get_property(_EnabledFeatures  GLOBAL PROPERTY ${_property})
124  if(_EnabledFeatures)
125    list(REMOVE_DUPLICATES _EnabledFeatures)
126  endif(_EnabledFeatures)
127
128  foreach(_currentFeature ${_EnabledFeatures})
129
130    # does this package belong to the type we currently want to list ?
131    get_property(_currentType  GLOBAL PROPERTY _CMAKE_${_currentFeature}_TYPE)
132    if(NOT _currentType)
133      list(FIND _fsPkgTypes "${_fsDefaultPkgType}" _defaultInPkgTypes)
134      if("${_defaultInPkgTypes}" STREQUAL "-1")
135        string(REGEX REPLACE ";([^;]+)$" " and \\1" _fsPkgTypes_msg "${_fsPkgTypes}")
136        string(REPLACE ";" ", " _fsPkgTypes_msg "${_fsPkgTypes_msg}")
137        message(FATAL_ERROR "Bad package property type ${_fsDefaultPkgType} used in global property FeatureSummary_DEFAULT_PKG_TYPE. "
138                            "Valid types are ${_fsPkgTypes_msg}. "
139                            "Either update FeatureSummary_DEFAULT_PKG_TYPE or add ${_fsDefaultPkgType} to the FeatureSummary_PKG_TYPES global property.")
140      endif()
141      set(_currentType ${_fsDefaultPkgType})
142    endif()
143
144    if("${_type}" STREQUAL ANY  OR  "${_type}" STREQUAL "${_currentType}")
145      # check whether the current feature/package should be in the output depending on whether it was QUIET or not
146      set(includeThisOne TRUE)
147      set(_required FALSE)
148      # skip QUIET packages, except if they are REQUIRED or INCLUDE_QUIET_PACKAGES has been set
149      get_property(_fsReqPkgTypes GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES)
150      foreach(_fsReqPkgType ${_fsReqPkgTypes})
151        if("${_currentType}" STREQUAL "${_fsReqPkgType}")
152          set(_required TRUE)
153          break()
154        endif()
155      endforeach()
156      if(NOT _required AND NOT _includeQuiet)
157        get_property(_isQuiet  GLOBAL PROPERTY _CMAKE_${_currentFeature}_QUIET)
158        if(_isQuiet)
159          set(includeThisOne FALSE)
160        endif()
161      endif()
162      get_property(_isTransitiveDepend
163        GLOBAL PROPERTY _CMAKE_${_currentFeature}_TRANSITIVE_DEPENDENCY
164      )
165      if(_isTransitiveDepend)
166        set(includeThisOne FALSE)
167      endif()
168
169      if(includeThisOne)
170
171        string(APPEND _currentFeatureText "\n * ${_currentFeature}")
172        get_property(_info  GLOBAL PROPERTY _CMAKE_${_currentFeature}_REQUIRED_VERSION)
173        if(_info)
174          string(APPEND _currentFeatureText " (required version ${_info})")
175        endif()
176        get_property(_info  GLOBAL PROPERTY _CMAKE_${_currentFeature}_DESCRIPTION)
177        if(_info)
178          string(APPEND _currentFeatureText ", ${_info}")
179        endif()
180        get_property(_info  GLOBAL PROPERTY _CMAKE_${_currentFeature}_URL)
181        if(_info)
182          string(APPEND _currentFeatureText ", <${_info}>")
183        endif()
184
185        get_property(_info  GLOBAL PROPERTY _CMAKE_${_currentFeature}_PURPOSE)
186        foreach(_purpose ${_info})
187          string(APPEND _currentFeatureText "\n   ${_purpose}")
188        endforeach()
189
190      endif()
191
192    endif()
193
194  endforeach()
195  set(${_var} "${_currentFeatureText}" PARENT_SCOPE)
196endfunction()
197
198
199#[=======================================================================[.rst:
200.. command:: feature_summary
201
202  ::
203
204    feature_summary( [FILENAME <file>]
205                     [APPEND]
206                     [VAR <variable_name>]
207                     [INCLUDE_QUIET_PACKAGES]
208                     [FATAL_ON_MISSING_REQUIRED_PACKAGES]
209                     [DESCRIPTION "<description>" | DEFAULT_DESCRIPTION]
210                     [QUIET_ON_EMPTY]
211                     WHAT (ALL
212                          | PACKAGES_FOUND | PACKAGES_NOT_FOUND
213                          | <TYPE>_PACKAGES_FOUND | <TYPE>_PACKAGES_NOT_FOUND
214                          | ENABLED_FEATURES | DISABLED_FEATURES)
215                   )
216
217  The ``feature_summary()`` macro can be used to print information about
218  enabled or disabled packages or features of a project.  By default,
219  only the names of the features/packages will be printed and their
220  required version when one was specified.  Use ``set_package_properties()``
221  to add more useful information, like e.g.  a download URL for the
222  respective package or their purpose in the project.
223
224  The ``WHAT`` option is the only mandatory option.  Here you specify what
225  information will be printed:
226
227  ``ALL``
228   print everything
229  ``ENABLED_FEATURES``
230   the list of all features which are enabled
231  ``DISABLED_FEATURES``
232   the list of all features which are disabled
233  ``PACKAGES_FOUND``
234   the list of all packages which have been found
235  ``PACKAGES_NOT_FOUND``
236   the list of all packages which have not been found
237
238  For each package type ``<TYPE>`` defined by the
239  :variable:`FeatureSummary_PKG_TYPES` global property, the following
240  information can also be used:
241
242  ``<TYPE>_PACKAGES_FOUND``
243   only those packages which have been found which have the type <TYPE>
244  ``<TYPE>_PACKAGES_NOT_FOUND``
245   only those packages which have not been found which have the type <TYPE>
246
247  .. versionchanged:: 3.1
248    With the exception of the ``ALL`` value, these values can be combined
249    in order to customize the output. For example:
250
251    .. code-block:: cmake
252
253      feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)
254
255  If a ``FILENAME`` is given, the information is printed into this file.  If
256  ``APPEND`` is used, it is appended to this file, otherwise the file is
257  overwritten if it already existed.  If the VAR option is used, the
258  information is "printed" into the specified variable.  If ``FILENAME`` is
259  not used, the information is printed to the terminal.  Using the
260  ``DESCRIPTION`` option a description or headline can be set which will be
261  printed above the actual content.  If only one type of
262  package was requested, no title is printed, unless it is explicitly set using
263  either ``DESCRIPTION`` to use a custom string, or ``DEFAULT_DESCRIPTION`` to
264  use a default title for the requested type.
265  If ``INCLUDE_QUIET_PACKAGES`` is given, packages which have been searched with
266  ``find_package(... QUIET)`` will also be listed. By default they are skipped.
267  If ``FATAL_ON_MISSING_REQUIRED_PACKAGES`` is given, CMake will abort if a
268  package which is marked as one of the package types listed in the
269  :variable:`FeatureSummary_REQUIRED_PKG_TYPES` global property has not been
270  found.
271  The default value for the :variable:`FeatureSummary_REQUIRED_PKG_TYPES` global
272  property is ``REQUIRED``.
273
274  .. versionadded:: 3.9
275    The ``DEFAULT_DESCRIPTION`` option.
276
277  The :variable:`FeatureSummary_DEFAULT_PKG_TYPE` global property can be
278  modified to change the default package type assigned when not explicitly
279  assigned by the user.
280
281  .. versionadded:: 3.8
282    If the ``QUIET_ON_EMPTY`` option is used, if only one type of package was
283    requested, and no packages belonging to that category were found, then no
284    output (including the ``DESCRIPTION``) is printed or added to the ``VAR``
285    variable.
286
287  Example 1, append everything to a file:
288
289  .. code-block:: cmake
290
291   include(FeatureSummary)
292   feature_summary(WHAT ALL
293                   FILENAME ${CMAKE_BINARY_DIR}/all.log APPEND)
294
295  Example 2, print the enabled features into the variable
296  enabledFeaturesText, including QUIET packages:
297
298  .. code-block:: cmake
299
300   include(FeatureSummary)
301   feature_summary(WHAT ENABLED_FEATURES
302                   INCLUDE_QUIET_PACKAGES
303                   DESCRIPTION "Enabled Features:"
304                   VAR enabledFeaturesText)
305   message(STATUS "${enabledFeaturesText}")
306
307  Example 3, change default package types and print only the categories that
308  are not empty:
309
310  .. code-block:: cmake
311
312   include(FeatureSummary)
313   set_property(GLOBAL APPEND PROPERTY FeatureSummary_PKG_TYPES BUILD)
314   find_package(FOO)
315   set_package_properties(FOO PROPERTIES TYPE BUILD)
316   feature_summary(WHAT BUILD_PACKAGES_FOUND
317                   Description "Build tools found:"
318                   QUIET_ON_EMPTY)
319   feature_summary(WHAT BUILD_PACKAGES_NOT_FOUND
320                   Description "Build tools not found:"
321                   QUIET_ON_EMPTY)
322
323#]=======================================================================]
324
325function(FEATURE_SUMMARY)
326# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
327  set(options APPEND
328              INCLUDE_QUIET_PACKAGES
329              FATAL_ON_MISSING_REQUIRED_PACKAGES
330              QUIET_ON_EMPTY
331              DEFAULT_DESCRIPTION)
332  set(oneValueArgs FILENAME
333                   VAR
334                   DESCRIPTION)
335  set(multiValueArgs WHAT)
336
337  CMAKE_PARSE_ARGUMENTS(_FS "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${_FIRST_ARG} ${ARGN})
338
339  if(_FS_UNPARSED_ARGUMENTS)
340    message(FATAL_ERROR "Unknown keywords given to FEATURE_SUMMARY(): \"${_FS_UNPARSED_ARGUMENTS}\"")
341  endif()
342
343  if(NOT _FS_WHAT)
344    message(FATAL_ERROR "The call to FEATURE_SUMMARY() doesn't set the required WHAT argument.")
345  endif()
346
347  if(_FS_DEFAULT_DESCRIPTION AND DEFINED _FS_DESCRIPTION)
348    message(WARNING "DEFAULT_DESCRIPTION option discarded since DESCRIPTION is set.")
349    set(_FS_DEFAULT_DESCRIPTION 0)
350  endif()
351
352  set(validWhatParts "ENABLED_FEATURES"
353                     "DISABLED_FEATURES"
354                     "PACKAGES_FOUND"
355                     "PACKAGES_NOT_FOUND")
356
357  get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
358  get_property(_fsReqPkgTypes GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES)
359  foreach(_fsPkgType ${_fsPkgTypes})
360    list(APPEND validWhatParts "${_fsPkgType}_PACKAGES_FOUND"
361                               "${_fsPkgType}_PACKAGES_NOT_FOUND")
362  endforeach()
363
364  set(title_ENABLED_FEATURES               "The following features have been enabled:")
365  set(title_DISABLED_FEATURES              "The following features have been disabled:")
366  set(title_PACKAGES_FOUND                 "The following packages have been found:")
367  set(title_PACKAGES_NOT_FOUND             "The following packages have not been found:")
368  foreach(_fsPkgType ${_fsPkgTypes})
369    set(_fsPkgTypeDescription "${_fsPkgType} packages")
370    get_property(_fsPkgTypeDescriptionIsSet GLOBAL PROPERTY FeatureSummary_${_fsPkgType}_DESCRIPTION SET)
371    if(_fsPkgTypeDescriptionIsSet)
372      get_property(_fsPkgTypeDescription GLOBAL PROPERTY FeatureSummary_${_fsPkgType}_DESCRIPTION )
373    endif()
374    set(title_${_fsPkgType}_PACKAGES_FOUND     "The following ${_fsPkgTypeDescription} have been found:")
375    set(title_${_fsPkgType}_PACKAGES_NOT_FOUND "The following ${_fsPkgTypeDescription} have not been found:")
376  endforeach()
377
378  list(FIND validWhatParts "${_FS_WHAT}" indexInList)
379  if(NOT "${indexInList}" STREQUAL "-1")
380    _FS_GET_FEATURE_SUMMARY( ${_FS_WHAT} _featureSummary ${_FS_INCLUDE_QUIET_PACKAGES} )
381    if(_featureSummary OR NOT _FS_QUIET_ON_EMPTY)
382      if(_FS_DEFAULT_DESCRIPTION)
383        set(_fullText "${title_${_FS_WHAT}}\n${_featureSummary}\n")
384      else()
385        set(_fullText "${_FS_DESCRIPTION}${_featureSummary}\n")
386      endif()
387    endif()
388
389    if(_featureSummary)
390      foreach(_fsReqPkgType ${_fsReqPkgTypes})
391        if("${_FS_WHAT}" STREQUAL "${_fsReqPkgType}_PACKAGES_NOT_FOUND")
392          set(requiredPackagesNotFound TRUE)
393          break()
394        endif()
395      endforeach()
396    endif()
397
398  else()
399    if("${_FS_WHAT}" STREQUAL "ALL")
400
401      set(allWhatParts "ENABLED_FEATURES")
402      foreach(_fsPkgType ${_fsPkgTypes})
403        list(APPEND allWhatParts "${_fsPkgType}_PACKAGES_FOUND")
404      endforeach()
405      list(APPEND allWhatParts "DISABLED_FEATURES")
406      foreach(_fsPkgType ${_fsPkgTypes})
407        list(APPEND allWhatParts "${_fsPkgType}_PACKAGES_NOT_FOUND")
408      endforeach()
409    else()
410      set(allWhatParts)
411      foreach(part ${_FS_WHAT})
412        list(FIND validWhatParts "${part}" indexInList)
413        if(NOT "${indexInList}" STREQUAL "-1")
414          list(APPEND allWhatParts "${part}")
415        else()
416          if("${part}" STREQUAL "ALL")
417            message(FATAL_ERROR "The WHAT argument of FEATURE_SUMMARY() contains ALL, which cannot be combined with other values.")
418          else()
419            message(FATAL_ERROR "The WHAT argument of FEATURE_SUMMARY() contains ${part}, which is not a valid value.")
420          endif()
421        endif()
422      endforeach()
423    endif()
424
425    set(_fullText "${_FS_DESCRIPTION}")
426    foreach(part ${allWhatParts})
427      set(_tmp)
428      _FS_GET_FEATURE_SUMMARY( ${part} _tmp ${_FS_INCLUDE_QUIET_PACKAGES})
429      if(_tmp)
430        if(_fullText)
431          string(APPEND _fullText "\n-- ")
432        endif()
433        string(APPEND _fullText "${title_${part}}\n${_tmp}\n")
434        foreach(_fsReqPkgType ${_fsReqPkgTypes})
435          if("${part}" STREQUAL "${_fsReqPkgType}_PACKAGES_NOT_FOUND")
436            set(requiredPackagesNotFound TRUE)
437            break()
438          endif()
439        endforeach()
440      endif()
441    endforeach()
442  endif()
443
444  if(_fullText OR NOT _FS_QUIET_ON_EMPTY)
445    if(_FS_FILENAME)
446      if(_FS_APPEND)
447        file(APPEND "${_FS_FILENAME}" "${_fullText}")
448      else()
449        file(WRITE  "${_FS_FILENAME}" "${_fullText}")
450      endif()
451
452    else()
453      if(NOT _FS_VAR)
454        message(STATUS "${_fullText}")
455      endif()
456    endif()
457
458    if(_FS_VAR)
459      set(${_FS_VAR} "${_fullText}" PARENT_SCOPE)
460    endif()
461  endif()
462
463  if(requiredPackagesNotFound  AND  _FS_FATAL_ON_MISSING_REQUIRED_PACKAGES)
464    message(FATAL_ERROR "feature_summary() Error: REQUIRED package(s) are missing, aborting CMake run.")
465  endif()
466
467endfunction()
468
469#[=======================================================================[.rst:
470.. command:: set_package_properties
471
472  ::
473
474    set_package_properties(<name> PROPERTIES
475                           [ URL <url> ]
476                           [ DESCRIPTION <description> ]
477                           [ TYPE (RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED) ]
478                           [ PURPOSE <purpose> ]
479                          )
480
481  Use this macro to set up information about the named package, which
482  can then be displayed via FEATURE_SUMMARY().  This can be done either
483  directly in the Find-module or in the project which uses the module
484  after the find_package() call.  The features for which information can
485  be set are added automatically by the find_package() command.
486
487  ``URL <url>``
488    This should be the homepage of the package, or something similar.
489    Ideally this is set already directly in the Find-module.
490
491  ``DESCRIPTION <description>``
492    A short description what that package is, at most one sentence.
493    Ideally this is set already directly in the Find-module.
494
495  ``TYPE <type>``
496    What type of dependency has the using project on that package.
497    Default is ``OPTIONAL``.  In this case it is a package which can be used
498    by the project when available at buildtime, but it also work without.
499    ``RECOMMENDED`` is similar to ``OPTIONAL``, i.e.  the project will build if
500    the package is not present, but the functionality of the resulting
501    binaries will be severely limited.  If a ``REQUIRED`` package is not
502    available at buildtime, the project may not even build.  This can be
503    combined with the ``FATAL_ON_MISSING_REQUIRED_PACKAGES`` argument for
504    ``feature_summary()``.  Last, a ``RUNTIME`` package is a package which is
505    actually not used at all during the build, but which is required for
506    actually running the resulting binaries.  So if such a package is
507    missing, the project can still be built, but it may not work later on.
508    If ``set_package_properties()`` is called multiple times for the same
509    package with different TYPEs, the ``TYPE`` is only changed to higher
510    TYPEs (``RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED``), lower TYPEs are
511    ignored.  The ``TYPE`` property is project-specific, so it cannot be set
512    by the Find-module, but must be set in the project.
513    Type accepted can be changed by setting the
514    :variable:`FeatureSummary_PKG_TYPES` global property.
515
516  ``PURPOSE <purpose>``
517    This describes which features this package enables in the
518    project, i.e.  it tells the user what functionality he gets in the
519    resulting binaries.  If set_package_properties() is called multiple
520    times for a package, all PURPOSE properties are appended to a list of
521    purposes of the package in the project.  As the TYPE property, also
522    the PURPOSE property is project-specific, so it cannot be set by the
523    Find-module, but must be set in the project.
524
525  Example for setting the info for a package:
526
527  .. code-block:: cmake
528
529    find_package(LibXml2)
530    set_package_properties(LibXml2 PROPERTIES
531                           DESCRIPTION "A XML processing library."
532                           URL "http://xmlsoft.org/")
533    # or
534    set_package_properties(LibXml2 PROPERTIES
535                           TYPE RECOMMENDED
536                           PURPOSE "Enables HTML-import in MyWordProcessor")
537    # or
538    set_package_properties(LibXml2 PROPERTIES
539                           TYPE OPTIONAL
540                           PURPOSE "Enables odt-export in MyWordProcessor")
541
542    find_package(DBUS)
543    set_package_properties(DBUS PROPERTIES
544      TYPE RUNTIME
545      PURPOSE "Necessary to disable the screensaver during a presentation")
546#]=======================================================================]
547function(SET_PACKAGE_PROPERTIES _name _props)
548  if(NOT "${_props}" STREQUAL "PROPERTIES")
549    message(FATAL_ERROR "PROPERTIES keyword is missing in SET_PACKAGE_PROPERTIES() call.")
550  endif()
551
552  set(options ) # none
553  set(oneValueArgs DESCRIPTION URL TYPE PURPOSE )
554  set(multiValueArgs ) # none
555
556  CMAKE_PARSE_ARGUMENTS(_SPP "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${ARGN})
557
558  if(_SPP_UNPARSED_ARGUMENTS)
559    message(FATAL_ERROR "Unknown keywords given to SET_PACKAGE_PROPERTIES(): \"${_SPP_UNPARSED_ARGUMENTS}\"")
560  endif()
561
562  if(_SPP_DESCRIPTION)
563    get_property(_info  GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION)
564    if(_info AND NOT "${_info}" STREQUAL "${_SPP_DESCRIPTION}")
565      message(STATUS "Warning: Property DESCRIPTION for package ${_name} already set to \"${_info}\", overriding it with \"${_SPP_DESCRIPTION}\"")
566    endif()
567
568    set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_SPP_DESCRIPTION}" )
569  endif()
570
571
572  if(_SPP_URL)
573    get_property(_info  GLOBAL PROPERTY _CMAKE_${_name}_URL)
574    if(_info AND NOT "${_info}" STREQUAL "${_SPP_URL}")
575      message(STATUS "Warning: Property URL already set to \"${_info}\", overriding it with \"${_SPP_URL}\"")
576    endif()
577
578    set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_SPP_URL}" )
579  endif()
580
581
582  # handle the PURPOSE: use APPEND, since there can be multiple purposes for one package inside a project
583  if(_SPP_PURPOSE)
584    set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_SPP_PURPOSE}" )
585  endif()
586
587  get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
588  get_property(_fsDefaultPkgType GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE)
589
590  # handle the TYPE
591  if(DEFINED _SPP_TYPE)
592    # Supported types are listed in FeatureSummary_PKG_TYPES according to their priority
593    get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
594    list(FIND _fsPkgTypes ${_SPP_TYPE} _typeIndexInList)
595    if("${_typeIndexInList}" STREQUAL "-1" )
596      string(REGEX REPLACE ";([^;]+)$" " and \\1" _fsPkgTypes_msg "${_fsPkgTypes}")
597      string(REPLACE ";" ", " _fsPkgTypes_msg "${_fsPkgTypes_msg}")
598      message(FATAL_ERROR "Bad package property type ${_SPP_TYPE} used in SET_PACKAGE_PROPERTIES(). "
599                          "Valid types are ${_fsPkgTypes_msg}." )
600    endif()
601
602    get_property(_previousType  GLOBAL PROPERTY _CMAKE_${_name}_TYPE)
603    list(FIND _fsPkgTypes "${_previousType}" _prevTypeIndexInList)
604
605    # make sure a previously set TYPE is not overridden with a lower new TYPE:
606    if("${_typeIndexInList}" GREATER "${_prevTypeIndexInList}")
607      set_property(GLOBAL PROPERTY _CMAKE_${_name}_TYPE "${_SPP_TYPE}" )
608    endif()
609  endif()
610
611endfunction()
612
613#[=======================================================================[.rst:
614.. command:: add_feature_info
615
616  ::
617
618    add_feature_info(<name> <enabled> <description>)
619
620  Use this macro to add information about a feature with the given ``<name>``.
621  ``<enabled>`` contains whether this feature is enabled or not. It can be a
622  variable or a list of conditions.
623  ``<description>`` is a text describing the feature.  The information can
624  be displayed using ``feature_summary()`` for ``ENABLED_FEATURES`` and
625  ``DISABLED_FEATURES`` respectively.
626
627  .. versionchanged:: 3.8
628    ``<enabled>`` can be a list of conditions.
629
630  Example for setting the info for a feature:
631
632  .. code-block:: cmake
633
634     option(WITH_FOO "Help for foo" ON)
635     add_feature_info(Foo WITH_FOO "The Foo feature provides very cool stuff.")
636#]=======================================================================]
637function(ADD_FEATURE_INFO _name _depends _desc)
638  set(_enabled 1)
639  foreach(_d ${_depends})
640    string(REGEX REPLACE " +" ";" _d "${_d}")
641    if(${_d})
642    else()
643      set(_enabled 0)
644      break()
645    endif()
646  endforeach()
647  if (${_enabled})
648    set_property(GLOBAL APPEND PROPERTY ENABLED_FEATURES "${_name}")
649  else ()
650    set_property(GLOBAL APPEND PROPERTY DISABLED_FEATURES "${_name}")
651  endif ()
652
653  set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" )
654endfunction()
655
656
657# The stuff below is only kept for compatibility
658
659#[=======================================================================[.rst:
660Legacy Macros
661^^^^^^^^^^^^^
662
663The following macros are provided for compatibility with previous
664CMake versions:
665
666.. command:: set_package_info
667
668  ::
669
670    set_package_info(<name> <description> [ <url> [<purpose>] ])
671
672  Use this macro to set up information about the named package, which
673  can then be displayed via ``feature_summary()``.  This can be done either
674  directly in the Find-module or in the project which uses the module
675  after the :command:`find_package` call.  The features for which information
676  can be set are added automatically by the ``find_package()`` command.
677#]=======================================================================]
678function(SET_PACKAGE_INFO _name _desc)
679  message(DEPRECATION "SET_PACKAGE_INFO is deprecated. Use SET_PACKAGE_PROPERTIES instead.")
680  unset(_url)
681  unset(_purpose)
682  if(ARGC GREATER 2)
683    set(_url "${ARGV2}")
684  endif()
685  if(ARGC GREATER 3)
686    set(_purpose "${ARGV3}")
687  endif()
688  set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" )
689  if(NOT _url STREQUAL "")
690    set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_url}" )
691  endif()
692  if(NOT _purpose STREQUAL "")
693    set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_purpose}" )
694  endif()
695endfunction()
696
697#[=======================================================================[.rst:
698.. command:: set_feature_info
699
700  ::
701
702    set_feature_info(<name> <description> [<url>])
703
704  Does the same as::
705
706    set_package_info(<name> <description> <url>)
707#]=======================================================================]
708function(SET_FEATURE_INFO)
709  message(DEPRECATION "SET_FEATURE_INFO is deprecated. Use ADD_FEATURE_INFO instead.")
710  SET_PACKAGE_INFO(${ARGN})
711endfunction()
712
713#[=======================================================================[.rst:
714.. command:: print_enabled_features
715
716  ::
717
718    print_enabled_features()
719
720  Does the same as
721
722  .. code-block:: cmake
723
724    feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
725#]=======================================================================]
726function(PRINT_ENABLED_FEATURES)
727  message(DEPRECATION "PRINT_ENABLED_FEATURES is deprecated. Use
728    feature_summary(WHAT ENABLED_FEATURES DESCRIPTION \"Enabled features:\")")
729  FEATURE_SUMMARY(WHAT ENABLED_FEATURES  DESCRIPTION "Enabled features:")
730endfunction()
731
732#[=======================================================================[.rst:
733.. command:: print_disabled_features
734
735  ::
736
737    print_disabled_features()
738
739  Does the same as
740
741  .. code-block:: cmake
742
743    feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
744#]=======================================================================]
745function(PRINT_DISABLED_FEATURES)
746  message(DEPRECATION "PRINT_DISABLED_FEATURES is deprecated. Use
747    feature_summary(WHAT DISABLED_FEATURES DESCRIPTION \"Disabled features:\")")
748  FEATURE_SUMMARY(WHAT DISABLED_FEATURES  DESCRIPTION "Disabled features:")
749endfunction()
750