Global maps

A global map models an association between a name and one or more [key, value] pairs. In the implementation, these pairs are saved by the calls to

set_property(GLOBAL PROPERTY ${prefix}${key} ${value})

A prefix usually identifies a program context, so that different global maps separate different contexts. A global map maintains an index of the keys it stores, which can be used to find out whether a property is in the map or not. A map can also be cleared with the help of its index. It’s possible to set, unset, or append to a property using syntax similar to that of usual variables:

# set(variable value)
global_set(context variable value)
# get_property(GLOBAL PROPERTY variable value)
global_set(context variable value)
# unset(variable)
global_unset(context variable)
# list(APPEND variable value)
global_append(context variable value)

The first argument is always a map name; it limits the scope of the operation to a certain context. It’s convenient to think of this argument as of a map name, although in implementation it’s just a prefix of the stored keys.

When to use

Sometimes, a CMake function or a module can have a complex state. In such cases, writing something like

get_property(value GLOBAL PROPERTY property)
set_property(GLOBAL PROPERTY property ${value} ${additional_value})

just to append a value to an existing property becomes a tedious, error-prone task.

Write functions

global_set
global_set(map_name property value)

Stores the [property, value] pair in the global map map_name. The value can be retrieved later using read functions.

Example:

function(setup_test value)
    global_set(test conf_key ${value})
endfunction()

function(run_test)
    global_get(test conf_key value)
    message(STATUS "run the test with the conf_key = ${value}")
    # run the test ...
endfunction()

setup_test(conf_value)
# ...
run_test()
global_set_if_empty
global_set_if_empty(map_name property value)

If the global map map_name does not contain the key property, stores the [property, value] pair in that map. Otherwise, raises an error (SEND_ERROR) without updating the map.

Example:

foreach(key ${keys})
    # require key uniqueness
    global_set_if_empty(unique keys ${key})
endforeach()
global_append
global_append(map_name property value)

If the property property exists, it is treated as a list, and the value of value is appended to it. Otherwise, the property property is created and set to the given value.

Example:

# filter out the list into a new list for later use
function(filter_interface_targets)
   foreach(_target ${_targets})
       get_target_property(_type ${_target} TYPE)
       if (_type STREQUAL INTERFACE_LIBRARY)
           global_append(interface_targets ${_target})
       endif()
    endforeach()
endfunction()

add_library(target1 INTERFACE)
add_library(target2 INTERFACE)
add_library(target3 tests/test1.cpp)
filter_interface_targets(target1 target2 target3)
# ...
global_get(interface_targets targets)
# prints: target1;target2
print("INTERFACE targets: ${targets}")
global_unset
global_unset(map_name property)

Removes the property property from the global map map_name.

Example:

global_set(test key1 value1)
global_set(test key2 value2)
global_set(test key3 value3)
# ...
global_unset(test)
global_get(test key1 value)
assert_empty("${value}")
global_get(test key2 value)
assert_not_empty("${value}")
global_clear
global_clear(map_name)

Clears all the properties previously set in the global map map_name by the calls to global_set and global_append.

Example:

global_set(test key1 value1)
global_set(test key2 value2)
global_set(test key3 value3)
# ...
global_clear(test)
global_get(test key1 value)
assert_empty("${value}")
global_get(test key2 value)
assert_empty("${value}")
global_get(test key3 value)
assert_empty("${value}")

Read functions

global_get
global_get(map_name property out_var)

Stores the value of the property property into the output variable designated by out_var. If the requested property is not found, sets out_var to an empty string.

Example See the example for global_set.

global_get_or_fail
global_get_or_fail(map_name property out_var)

Searches the property property in the given global map map_name. If found, the output variable out_var is updated to store the property’s value. Otherwise, fatal error is raised.

Example

if(condition)
    unset(var)
endif()
global_set(test property ${var})
# this will raise the fatal error - condition was not expected to work
global_get_or_fail(test property value)