File: MongoSettings.cmake

package info (click to toggle)
mongo-c-driver 2.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 47,088 kB
  • sloc: ansic: 193,670; python: 7,780; cpp: 1,493; sh: 659; makefile: 78
file content (381 lines) | stat: -rw-r--r-- 14,241 bytes parent folder | download | duplicates (2)
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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
include_guard(DIRECTORY)

#[[ Bool: Set to TRUE if the environment variable MONGODB_DEVELOPER is a true value ]]
set(MONGODB_DEVELOPER FALSE)

# Detect developer mode:
set(_is_dev "$ENV{MONGODB_DEVELOPER}")
if(_is_dev)
    message(STATUS "Enabling MONGODB_DEVELOPER πŸƒ")
    set(MONGODB_DEVELOPER TRUE)
endif()

#[==[
Define a new configure-time build setting::
    mongo_setting(
        <name> <doc>
        [TYPE <BOOL|PATH|FILEPATH|STRING>]
        [DEFAULT [[DEVEL] [VALUE <value> | EVAL <code>]] ...]
        [OPTIONS [<opts> ...]]
        [VALIDATE [CODE <code>]]
        [VISIBLE_IF <cond>]
        [ADVANCED]
    )

The `<name>` will be the name of the setting, while `<doc>` will be the
documentation string shown to the user. Newlines in the doc string will be
replaced with single spaces. If no other arguments are provided, the default
`TYPE` will be `STRING`, and the DEFAULT value will be an empty string. If the
previous cached value is AUTO, and AUTO is not listed in OPTIONS, then the cache
value will be cleared and reset to the default value.

Package maintainers Note: Setting a variable `<name>-FORCE` to TRUE will make
this function a no-op.

TYPE <BOOL|PATH|FILEPATH|STRING>
    - Sets the type for the generated cache variable. If the type is BOOL, this
      call will validate that the setting is a valid boolean value.

OPTIONS [<opts> [...]]
    - Specify the valid set of values available for this setting. This will set
      the STRINGS property on the cache variable and add an information message
      to the doc string. This call will also validate that the setting's value
      is one of these options, failing with an error if it is not.

DEFAULT [[DEVEL] [VALUE <value> | EVAL <code>]]
        [...]
    - Specify the default value(s) of the generated variable. If given VALUE,
      then `<value>` will be used as the default, otherwise if given EVAL,
      `<code>` will be executed and is expected to define a variable DEFAULT
      that will contain the default value. An optional DEVEL qualifier may be
      given before a default value specifier. If both qualified and unqualified
      defaults are given, the unqualified default must appear first in the
      argument list.
    - If MONGODB_DEVELOPER is not true, then the non-qualified default will be
      used. (If no non-qualified defaults are provided, then the default value
      is an empty string.)
    - Otherwise, If DEVEL defaults are provided and MONGODB_DEVELOPER is true,
      then the DEVEL defaults will be used.

VALIDATE [CODE <code>]
    - If specified, then `<code>` will be evaluated after the setting value is
      defined. `<code>` may issue warnings and errors about the value of the
      setting.

ADVANCED
    - If specified, the cache variable will be marked as an advanced setting

VISIBLE_IF <cond>
    - If specified, then `<cond>` should be a quoted CMake condition (e.g.
      [[FOO AND NOT BAR]]). If the condition evaluates to a false value, then
      the setting will be hidden from the user. NOTE that the setting will still
      retain its original value and be available as a variable in the CMake
      code!

]==]
function(mongo_setting setting_NAME setting_DOC)
    list(APPEND CMAKE_MESSAGE_CONTEXT mongo setting "${setting_NAME}")
    # Allow bypassing this code:
    set(force "${${setting_NAME}-FORCE}")
    if(force)
        return()
    endif()

    cmake_parse_arguments(
        PARSE_ARGV 2 setting
        "ADVANCED"
        "TYPE;VISIBLE_IF"
        "OPTIONS;DEFAULT;VALIDATE")
    # Check for unknown arguments:
    foreach(arg IN LISTS setting_UNPARSED_ARGUMENTS)
        message(SEND_ERROR "Unrecognized argument: β€œ${arg}”")
    endforeach()
    if(setting_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unrecognized arguments (see above)")
    endif()

    # By default, settings are strings:
    if(NOT DEFINED setting_TYPE)
        set(setting_TYPE STRING)
    endif()

    # More arg validation:
    if(setting_TYPE STREQUAL "BOOL")
        if(DEFINED setting_OPTIONS)
            message(FATAL_ERROR [["OPTIONS" cannot be specified with type "BOOL"]])
        endif()
    endif()

    # Normalize the doc string for easier writing of doc strings at call sites:
    string(REGEX REPLACE "\n[ ]*" " " doc "${setting_DOC}")
    # Update the doc string with options:
    if(DEFINED setting_OPTIONS)
        string(REPLACE ";" ", " opts "${setting_OPTIONS}")
        string(APPEND doc " (Options: ${opts})")
    endif()

    # Get the default option value:
    unset(DEFAULT)
    if(DEFINED setting_DEFAULT)
        _mongo_compute_default(DEFAULT "${setting_DEFAULT}")
    endif()

    if(DEFINED DEFAULT)
        # Add that to the doc message:
        string(APPEND doc " (Default is β€œ${DEFAULT}”)")
        # Check that the default is actually a valid option:
        if(DEFINED setting_OPTIONS AND NOT DEFAULT IN_LIST setting_OPTIONS)
            message(AUTHOR_WARNING "${setting_NAME}: Setting's default value is β€œ${DEFAULT}”, which is not one of the provided setting options (${opts})")
        endif()

        # Reset "AUTO" values to the default
        if(NOT "AUTO" IN_LIST setting_OPTIONS AND "$CACHE{${setting_NAME}}" STREQUAL "AUTO")
            message(WARNING "Replacing old ${setting_NAME}=β€œAUTO” with the new default value ${setting_NAME}=β€œ${DEFAULT}”")
            unset("${setting_NAME}" CACHE)
        endif()
    endif()

    # Detect the previous value
    unset(prev_val)
    if(DEFINED "CACHE{${setting_NAME}-PREV}")
        set(prev_val "$CACHE{${setting_NAME}-PREV}")
        message(DEBUG "Detected previous value was β€œ${prev_val}”")
    elseif(DEFINED "CACHE{${setting_NAME}}")
        message(DEBUG "Externally defined to be β€œ${${setting_NAME}}”")
    else()
        message(DEBUG "No previous value detected")
    endif()

    # Actually define it now:
    set("${setting_NAME}" "${DEFAULT}" CACHE "${setting_TYPE}" "${doc}")
    # Variable properties:
    set_property(CACHE "${setting_NAME}" PROPERTY HELPSTRING "${doc}")
    set_property(CACHE "${setting_NAME}" PROPERTY TYPE "${setting_TYPE}")
    set_property(CACHE "${setting_NAME}" PROPERTY ADVANCED "${setting_ADVANCED}")
    if(setting_OPTIONS)
        set_property(CACHE "${setting_NAME}" PROPERTY STRINGS "${setting_OPTIONS}")
    endif()

    # Report what we set:
    if(NOT DEFINED prev_val)
        message(VERBOSE "Setting: ${setting_NAME} := β€œ${${setting_NAME}}”")
    elseif("${${setting_NAME}}" STREQUAL prev_val)
        message(DEBUG "Setting: ${setting_NAME} := β€œ${${setting_NAME}}” (Unchanged)")
    else()
        message(VERBOSE "Setting: ${setting_NAME} := β€œ${${setting_NAME}}” (Old value was β€œ${prev_val}”)")
    endif()
    set("${setting_NAME}-PREV" "${${setting_NAME}}" CACHE INTERNAL "Prior value of ${setting_NAME}")

    # Validation of options:
    if((DEFINED setting_OPTIONS) AND (NOT ("${${setting_NAME}}" IN_LIST setting_OPTIONS)))
        message(FATAL_ERROR "The value of β€œ${setting_NAME}” must be one of [${opts}] (Got ${setting_NAME}=β€œ${${setting_NAME}}”)")
    endif()
    string(TOUPPER "${${setting_NAME}}" curval)
    if(setting_TYPE STREQUAL "BOOL"
        AND NOT curval MATCHES "^(1|0|ON|OFF|YES|NO|TRUE|FALSE|Y|N|IGNORE)$")
        message(WARNING "The value of ${setting_NAME}=β€œ${${setting_NAME}}” is not a regular boolean value")
    endif()

    # Custom validation:
    if(DEFINED setting_VALIDATE)
        cmake_parse_arguments(validate "" "CODE" "" ${setting_VALIDATE})
        if(DEFINED validate_CODE)
            _mongo_eval_cmake("" "${validate_CODE}")
        endif()
        if(validate_UNPARSED_ARGUMENTS)
            message(FATAL_ERROR "Unrecognized VALIDATE options: ${validate_UNPARSED_ARGUMENTS}")
        endif()
    endif()

    if(DEFINED setting_VISIBLE_IF)
        string(JOIN "\n" code
            "set(avail FALSE)"
            "if(${setting_VISIBLE_IF})"
            "  set(avail TRUE)"
            "endif()")
        _mongo_eval_cmake(avail "${code}")
        if(NOT avail)
            # Hide the option by making it INTERNAL
            set_property(CACHE "${setting_NAME}" PROPERTY TYPE INTERNAL)
        endif()
    endif()
endfunction()

#[[ Implements DEFAULT setting value logic ]]
function(_mongo_compute_default outvar arglist)
    list(APPEND CMAKE_MESSAGE_CONTEXT default)
    # Clear the value in the caller:
    unset("${outvar}" PARENT_SCOPE)

    # Parse arguments:
    cmake_parse_arguments(dflt "" "" "DEVEL" ${arglist})

    # Developer-mode options:
    if(DEFINED dflt_DEVEL AND MONGODB_DEVELOPER)
        list(APPEND CMAKE_MESSAGE_CONTEXT "devel")
        _mongo_compute_default(tmp "${dflt_DEVEL}")
        message(DEBUG "Detected MONGODB_DEVELOPER: Default of ${setting_NAME} is β€œ${tmp}”")
        set("${outvar}" "${tmp}" PARENT_SCOPE)
        return()
    endif()

    # Parse everything else:
    set(other_args "${dflt_UNPARSED_ARGUMENTS}")
    cmake_parse_arguments(dflt "" "VALUE;EVAL" "" ${other_args})

    if(DEFINED dflt_VALUE)
        # Simple value for the default
        if(DEFINED dflt_EVAL)
            message(FATAL_ERROR "Only one of VALUE or EVAL may be specified for a DEFAULT")
        endif()
        set("${outvar}" "${dflt_VALUE}" PARENT_SCOPE)
    elseif(DEFINED dflt_EVAL)
        # Evaluate some code to determine the default
        _mongo_eval_cmake(DEFAULT "${dflt_EVAL}")
        set("${outvar}" "${DEFAULT}" PARENT_SCOPE)
        if(DEFINED DEFAULT)
            message(DEBUG "Computed default ${setting_NAME} value to be β€œ${DEFAULT}”")
        else()
            message(DEBUG "No default for ${setting_NAME} was computed. Default will be an empty string.")
        endif()
    elseif(dflt_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR
                "${setting_NAME}: "
                "DEFAULT got unexpected arguments: ${dflt_UNPARSED_ARGUMENTS}")
    endif()
endfunction()

#[==[
Define a new boolean build setting::

    mongo_bool_setting(
        <name> <doc>
        [DEFAULT [[DEVEL] [VALUE <value> | EVAL <code>]] ...]
        [VALIDATE [CODE <code>]]
        [ADVANCED]
    )

This is a shorthand for defining a boolean setting. See mongo_setting() for more
option information. The TYPE of the setting will be BOOL, and the implicit
default value for the setting will be ON if no DEFAULT is provided.

]==]
function(mongo_bool_setting name doc)
    set(args ${ARGN})
    # Inject "ON" as a default:
    if(NOT "DEFAULT" IN_LIST args)
        list(APPEND args DEFAULT VALUE ON)
    endif()
    mongo_setting("${name}" "${doc}" TYPE BOOL ${args})
endfunction()

# Set the variable named by 'out' to the 'if_true' or 'if_false' value based on 'cond'
function(mongo_pick out if_true if_false cond)
    string(REPLACE "'" "\"" cond "${cond}")
    mongo_bool01(b "${cond}")
    if(b)
        set("${out}" "${if_true}" PARENT_SCOPE)
    else()
        set("${out}" "${if_false}" PARENT_SCOPE)
    endif()
endfunction()

# Evaluate CMake code <code>, and lift the given variables into the caller's scope.
function(_mongo_eval_cmake get_variables code)
    # Set a name that is unlikely to collide:
    set(__eval_liftvars "${get_variables}")
    # Clear the values before we evaluate the code:
    foreach(__varname IN LISTS __eval_liftvars)
        unset("${__varname}" PARENT_SCOPE)
        unset("${__varname}")
    endforeach()
    # We do the "eval" the old fashion way, since we can't yet use cmake_language()
    message(TRACE "Evaluating CMake code:\n\n${code}")
    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/_eval.tmp.cmake" "${code}")
    include("${CMAKE_CURRENT_BINARY_DIR}/_eval.tmp.cmake")
    # Lift the variables into the caller's scope
    foreach(__varname IN LISTS __eval_liftvars)
        if(DEFINED "${__varname}")
            message(TRACE "Eval variable result: ${__varname}=${${__varname}}")
            set("${__varname}" "${${__varname}}" PARENT_SCOPE)
        endif()
    endforeach()
endfunction()

#[==[
    mongo_bool01(<var> <cond>)

Evaluate a condition and store the boolean result as a "0" or a "1".

Parameters:

<var>
    - The name of the variable to define in the caller's scope.

<cond>
    - `...cond` The condition to evaluate. It must be a single string that
      contains wraps the syntax of a CMake `if()` command

Example: Evaluate Boolean Logic
###############################

    mongo_bool01(is_mingw [[WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU"]])

Note the quoting and use of [[]]-bracket strings

]==]
function(mongo_bool01 var code)
    if(ARGN)
        message(FATAL_ERROR "Too many arguments passed to mongo_bool01")
    endif()
    string(CONCAT fullcode
        "if(${code})\n"
        "  set(bool 1)\n"
        "else()\n"
        "  set(bool 0)\n"
        "endif()\n")
    _mongo_eval_cmake(bool "${fullcode}")
    set("${var}" "${bool}" PARENT_SCOPE)
endfunction()

#[==[
Append usage requirement properties to a set of targets.

    mongo_target_requirements(
        [<target> [...]]
        [INCLUDE_DIRECTORIES [spec...]]
        [LINK_LIBRARIES [spec...]]
        [COMPILE_DEFINITIONS [spec...]]
        [COMPILE_OPTIONS [spec...]]
        [LINK_OPTIONS [spec...]]
        [SOURCES [spec...]]
    )

]==]
function(mongo_target_requirements)
    set(properties
        INCLUDE_DIRECTORIES LINK_LIBRARIES COMPILE_DEFINITIONS
        COMPILE_OPTIONS LINK_OPTIONS SOURCES
    )
    cmake_parse_arguments(PARSE_ARGV 0 ARG "" "" "${properties}")
    foreach(target IN LISTS ARG_UNPARSED_ARGUMENTS)
        if(ARG_INCLUDE_DIRECTORIES)
            target_include_directories("${target}" ${ARG_INCLUDE_DIRECTORIES})
        endif()
        if(ARG_LINK_LIBRARIES)
            target_link_libraries("${target}" ${ARG_LINK_LIBRARIES})
        endif()
        if(ARG_COMPILE_DEFINITIONS)
            target_compile_definitions("${target}" ${ARG_COMPILE_DEFINITIONS})
        endif()
        if(ARG_COMPILE_OPTIONS)
            target_compile_options("${target}" ${ARG_COMPILE_OPTIONS})
        endif()
        if(ARG_LINK_OPTIONS)
            target_link_options("${target}" ${ARG_LINK_OPTIONS})
        endif()
        if(ARG_SOURCES)
            target_sources("${target}" ${ARG_SOURCES})
        endif()
    endforeach()
endfunction()