File: ecbuild_add_option.cmake

package info (click to toggle)
magics%2B%2B 2.30.0-5
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 105,040 kB
  • ctags: 32,903
  • sloc: cpp: 185,631; xml: 18,565; ansic: 11,002; perl: 6,357; python: 4,065; sh: 802; f90: 278; asm: 271; makefile: 157
file content (317 lines) | stat: -rw-r--r-- 12,774 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# (C) Copyright 1996-2016 ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.

##############################################################################
#.rst:
#
# ecbuild_add_option
# ==================
#
# Add a CMake configuration option, which may depend on a list of packages. ::
#
#   ecbuild_add_option( FEATURE <name>
#                       [ DEFAULT ON|OFF ]
#                       [ DESCRIPTION <description> ]
#                       [ PURPOSE <purpose> ]
#                       [ REQUIRED_PACKAGES <package1> [<package2> ...] ]
#                       [ CONDITION <condition> ]
#                       [ ADVANCED ] [ NO_TPL ] )
#
# Options
# -------
#
# FEATURE : required
#   name of the feature / option
#
# DEFAULT : optional, defaults to ON
#   if set to ON, the feature is enabled even if not explicitly requested
#
# DESCRIPTION : optional
#   string describing the feature (shown in summary and stored in the cache)
#
# TYPE : optional, one of RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED
#   type of dependency of the project on this package (defaults to OPTIONAL)
#
# PURPOSE : optional
#   string describing which functionality this package enables in the project
#
# REQUIRED_PACKAGES : optional
#   list of packages required to be found for this feature to be enabled
#
#   The package specification can have one of two forms. Either ::
#
#     "<package> [ <version> ... ]"
#
#   to search for a given package using the CMake ``find_package`` mechanism.
#   The entire specification must be enclosed in quotes and is passed on
#   verbatim. Any options of ``find_package`` are supported.
#
#   The other specification must start with ``PROJECT`` like this ::
#
#     "PROJECT <name> [ VERSION <version> ... ]"
#
#   and is used to search for an ecBuild project via ``ecbuild_use_package``.
#   The entire specification must be enclosed in quotes and is passed on
#   verbatim. Any options of ``ecbuild_use_package`` are supported.
#
# CONDITION : optional
#   conditional expression which must evaluate to true for this option to be
#   enabled (must be valid in a CMake ``if`` statement)
#
# ADVANCED : optional
#   mark the feature as advanced
#
# NO_TPL : optional
#   do not add any ``REQUIRED_PACKAGES`` to the list of third party libraries
#
# Usage
# -----
#
# Features with ``DEFAULT OFF`` need to be explcitly enabled by the user with
# ``-DENABLE_<FEATURE>=ON``. If a feature is enabled, all ``REQUIRED_PACKAGES``
# are found and ``CONDITION`` is met, ecBuild sets the variable
# ``HAVE_<FEATURE>`` to ``ON``. This is the variable to use to check for the
# availability of the feature.
#
# If a feature is explicitly enabled but the required packages are not found,
# configuration fails. This only applies when configuring from *clean cache*.
# With an already populated cache, use ``-DENABLE_<FEATURE>=REQUIRE`` to make
# the feature a required feature (this cannot be done via the CMake GUI).
#
##############################################################################

macro( ecbuild_add_option )

  set( options ADVANCED NO_TPL )
  set( single_value_args FEATURE DEFAULT DESCRIPTION TYPE PURPOSE )
  set( multi_value_args  REQUIRED_PACKAGES CONDITION )

  cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}"  ${_FIRST_ARG} ${ARGN} )

  if( _p_UNPARSED_ARGUMENTS )
    ecbuild_critical("Unknown keywords given to ecbuild_add_option(): \"${_p_UNPARSED_ARGUMENTS}\"")
  endif()

  # check FEATURE parameter

  if( NOT _p_FEATURE  )
    ecbuild_critical("The call to ecbuild_add_option() doesn't specify the FEATURE.")
  endif()

  # check DEFAULT parameter

  if( NOT DEFINED _p_DEFAULT )
    set( _p_DEFAULT ON )
  else()
    if( NOT _p_DEFAULT MATCHES "[Oo][Nn]" AND NOT _p_DEFAULT MATCHES "[Oo][Ff][Ff]" )
      ecbuild_critical("In macro ecbuild_add_option(), DEFAULT is either ON or OFF: \"${_p_DEFAULT}\"")
    endif()
  endif()
  ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): defaults to ${_p_DEFAULT}")

  if( NOT _p_TYPE  )
    set( _p_TYPE OPTIONAL )
  endif()

  # check CONDITION parameter
  if( DEFINED _p_CONDITION )
    set(_feature_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_p_FEATURE}_condition.cmake")
    file( WRITE  ${_feature_condition_file} "  if( ")
    foreach( term ${_p_CONDITION} )
      file( APPEND ${_feature_condition_file} " ${term}")
    endforeach()
    file( APPEND ${_feature_condition_file} " )\n    set(_${_p_FEATURE}_condition TRUE)\n  else()\n    set(_${_p_FEATURE}_condition FALSE)\n  endif()\n")
    include( ${_feature_condition_file} )
    ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): checking condition ${_p_CONDITION} -> ${_${_p_FEATURE}_condition}")
  else()
    set( _${_p_FEATURE}_condition TRUE )
  endif()

  # Check if user explicitly enabled/disabled the feature in cache
  get_property( _in_cache CACHE ENABLE_${_p_FEATURE} PROPERTY VALUE SET )

  # A feature set to REQUIRE is always treated as explicitly enabled
  if( ENABLE_${_p_FEATURE} MATCHES "REQUIRE" )
    set( ENABLE_${_p_FEATURE} ON CACHE BOOL "" FORCE )
    ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} was required")
    set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" FORCE )
  elseif( NOT ENABLE_${_p_FEATURE} STREQUAL "" AND _in_cache )
    ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE}=${ENABLE_${_p_FEATURE}} was found in cache")
    set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" )
  else()
    ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} not found in cache")
    set( ${_p_FEATURE}_user_provided_input 0 CACHE BOOL "" )
  endif()

  mark_as_advanced( ${_p_FEATURE}_user_provided_input )


  # define the option -- for cmake GUI

  option( ENABLE_${_p_FEATURE} "${_p_DESCRIPTION}" ${_p_DEFAULT} )
  ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): defining option ENABLE_${_p_FEATURE} '${_p_DESCRIPTION}' ${_p_DEFAULT}")
  ecbuild_set_feature( ${_p_FEATURE} ENABLED ${_p_DEFAULT} )
  set_package_properties( ${_p_FEATURE} PROPERTIES
                          DESCRIPTION "${_p_DESCRIPTION}"
                          TYPE ${_p_TYPE}
                          PURPOSE "${_p_PURPOSE}" )

  ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE}=${ENABLE_${_p_FEATURE}}")

  if( ENABLE_${_p_FEATURE} )
    ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): feature enabled")

    set( HAVE_${_p_FEATURE} 1 )

    if( _${_p_FEATURE}_condition )

      ### search for dependent packages

      set( _failed_to_find_packages )  # clear variable
      foreach( pkg ${_p_REQUIRED_PACKAGES} )
        ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for dependent package ${pkg}")

        string(REPLACE " " ";" pkglist ${pkg}) # string to list

        list( GET pkglist 0 pkgname )

        if( pkgname STREQUAL "PROJECT" )  # if 1st entry is PROJECT, then we are looking for a ecbuild project
          set( pkgproject 1 )
          list( GET pkglist 1 pkgname )
        else()                            # else 1st entry is package name
          set( pkgproject 0 )
        endif()

        # ecbuild_debug_var( pkg )
        # ecbuild_debug_var( pkglist )
        # ecbuild_debug_var( pkgname )

        string( TOUPPER ${pkgname} pkgUPPER )
        string( TOLOWER ${pkgname} pkgLOWER )

        set( __help_msg "Provide ${pkgname} location with -D${pkgUPPER}_PATH=/..." )
        if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )

          ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ${pkgname} has already been found")
          set( ${pkgname}_already_found 1 )

        else()

          if( pkgproject )

            ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for ecbuild project ${pkgname} - ecbuild_use_package( ${pkglist} )")
            ecbuild_use_package( ${pkglist} )

          else()

            if( pkgname STREQUAL "MPI" )
              set( _find_args ${pkglist} )
              list( REMOVE_ITEM _find_args "MPI" )
              ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for MPI - ecbuild_find_mpi( ${_find_args} )")
              ecbuild_find_mpi( ${_find_args} )
            elseif( pkgname STREQUAL "OMP" )
              set( _find_args ${pkglist} )
              list( REMOVE_ITEM _find_args "OMP" )
              if( NOT ENABLE_${_p_FEATURE} )
                list( APPEND _find_args STUBS )
              endif()
              ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for OpenMP - ecbuild_find_omp( ${_find_args} )")
              ecbuild_find_omp( ${_find_args} )
            elseif( pkgname STREQUAL "Python" OR pkgname STREQUAL "PYTHON" )
              set( _find_args ${pkglist} )
              list( REMOVE_ITEM _find_args ${pkgname} )
              ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for Python - ecbuild_find_python( ${_find_args} )")
              ecbuild_find_python( ${_find_args} )
              set( __help_msg "Specify the location of the Python interpreter with -DPYTHON_EXECUTABLE=/..." )
            elseif( pkgname STREQUAL "LEXYACC" )
              set( _find_args ${pkglist} )
              list( REMOVE_ITEM _find_args ${pkgname} )
              ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for lex-yacc - ecbuild_find_lexyacc( ${_find_args} )")
              ecbuild_find_lexyacc( ${_find_args} )
            else()
              ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for package ${pkgname} - find_package( ${pkglist} )")
              find_package( ${pkglist} )
            endif()

          endif()

        endif()

        # ecbuild_debug_var( ${pkgname}_FOUND  )
        # ecbuild_debug_var( ${pkgLOWER}_FOUND )
        # ecbuild_debug_var( ${pkgUPPER}_FOUND )

        # we have feature if all required packages were FOUND

        if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
          ecbuild_info( "Found package ${pkgname} required for feature ${_p_FEATURE}" )

          # append to list of third-party libraries (to be forward to other packages )
          # unless the NO_TPL option was given
          if( NOT _p_NO_TPL )
            ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): appending ${pkgname} to ${PROJECT_NAME_CAPS}_TPLS")
            list( APPEND ${PROJECT_NAME_CAPS}_TPLS ${pkgname} )
            list( REMOVE_DUPLICATES ${PROJECT_NAME_CAPS}_TPLS )
          endif()

        else()
          ecbuild_info( "Could NOT find package ${pkgname} required for feature ${_p_FEATURE} -- ${__help_msg}" )
          set( HAVE_${_p_FEATURE} 0 )
          list( APPEND _failed_to_find_packages ${pkgname} )
        endif()

      endforeach()
    else( _${_p_FEATURE}_condition )
      set( HAVE_${_p_FEATURE} 0 )
    endif( _${_p_FEATURE}_condition )

    ecbuild_set_feature( ${_p_FEATURE} ENABLED ${HAVE_${_p_FEATURE}} )
    # FINAL CHECK

    if( HAVE_${_p_FEATURE} )

      ecbuild_info( "Feature ${_p_FEATURE} enabled" )

    else() # if user provided input and we cannot satisfy FAIL otherwise WARN

      if( ${_p_FEATURE}_user_provided_input )
        if( NOT _${_p_FEATURE}_condition )
          string(REPLACE ";" " " _condition_msg "${_p_CONDITION}")
          ecbuild_critical( "Feature ${_p_FEATURE} cannot be enabled -- following condition was not met: ${_condition_msg}" )
        else()
          ecbuild_critical( "Feature ${_p_FEATURE} cannot be enabled -- following required packages weren't found: ${_failed_to_find_packages}" )
        endif()
      else()
        if( NOT _${_p_FEATURE}_condition )
          string(REPLACE ";" " " _condition_msg "${_p_CONDITION}")
          ecbuild_info( "Feature ${_p_FEATURE} was not enabled (also not requested) -- following condition was not met: ${_condition_msg}" )
        else()
          ecbuild_info( "Feature ${_p_FEATURE} was not enabled (also not requested) -- following required packages weren't found: ${_failed_to_find_packages}" )
        endif()
        set( ENABLE_${_p_FEATURE} OFF )
        ecbuild_set_feature( ${_p_FEATURE} ENABLED OFF )
      endif()

    endif()

  else()

    ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): feature disabled")
    set( HAVE_${_p_FEATURE} 0 )
    ecbuild_set_feature( ${_p_FEATURE} ENABLED OFF )

  endif()


  if( ${_p_ADVANCED} )
    mark_as_advanced( ENABLE_${_p_FEATURE} )
  endif()

  set( ${PROJECT_NAME_CAPS}_HAVE_${_p_FEATURE} ${HAVE_${_p_FEATURE}} )

endmacro( ecbuild_add_option  )