How can I generate a GUID in CMake? - cmake

I need to generate GUIDS in CMake to define unique identifiers in some custom configuration files. How can I use CMake to generate GUIDs?

There are several ways to create unique identifiers in CMake (see string() Generation).
E.g. string(TIMESTAMP ...), string(RANDOM ...) or string(UUID ...):
string(UUID <output variable> NAMESPACE <namespace> NAME <name>
TYPE <MD5|SHA1> [UPPER])
Create a univerally unique identifier (aka GUID) as per RFC4122
Examples from CMake's string() Unit Test Uuid.cmake:
set(UUID_DNS_NAMESPACE 6ba7b810-9dad-11d1-80b4-00c04fd430c8)
string(
UUID WWW_EXAMPLE_COM_MD5_UUID
NAMESPACE ${UUID_DNS_NAMESPACE}
NAME "www.example.com"
TYPE MD5
)
string(
UUID WWW_EXAMPLE_COM_SHA1_UUID
NAMESPACE ${UUID_DNS_NAMESPACE}
NAME "www.example.com"
TYPE SHA1 UPPER
)

Related

Expand variable name containing a generator expression in cmake

In the build process, I set directories where I gather the build output of different sub-projects. The directories are set as :
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_LIST_DIR}/../build/bin/debug" )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_LIST_DIR}/../build/bin/release" )
Now, I'd like to copy some files (a directory of qt plugins) to that directory dependent on the configuration which it is built for.
I tried:
# copy qt plugins
add_custom_command( TARGET mytarget POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${QT_DIR}/../../../plugins"
"${$<UPPER_CASE:CMAKE_RUNTIME_OUTPUT_DIRECTORY_$<CONFIG> >}/plugins"
COMMAND_EXPAND_LISTS)
thus, I try to build a string that equals the variable name and then try to expand that as described here: CMake interpret string as variable. In other words: I would like to have a generator expression that evaluates to the content of CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG or CMAKE_RUNTIME_OUTPUT_DIRECTOR_RELEASE dependent on the current build configuration.
However running cmake with the statement above results in an error:
"CMakeLists.txt:112: error: Syntax error in cmake code at [..] when parsing string ${$<UPPER_CASE:CMAKE_RUNTIME_OUTPUT_DIRECTORY_$<CONFIG> >}/plugins Invalid character ('<') in a variable name: '$'
So my question is, how can I use a generator-expression to access the corresponding variable? (Bonus question: is there another/better way to achieve the same goal?)
So my question is, how can I use a generator-expression to access the corresponding variable?
You cannot. There is currently (CMake <=3.23) no way to expand a variable whose name is determined by the value of a generator expression.
Bonus question: is there another/better way to achieve the same goal?
Yes, and you are almost there! You can use $<TARGET_FILE_DIR:...>:
add_custom_command(
TARGET mytarget POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_directory
"${QT_DIR}/../../../plugins"
"$<TARGET_FILE_DIR:mytarget>/plugins"
VERBATIM
)
This works because TARGET_FILE_DIR evaluates to the actual directory containing the executable or library file for mytarget, no matter the active configuration, property values, etc.
Docs: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_FILE_DIR
CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG> is already relative to the binary directory so you should not try to compute the binary directory in its definition. Also, it supports generator expressions. Thus, the following will be much more robust:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/$<LOWER_CASE:$<CONFIG>>"
CACHE STRING "Common output directory for runtime artifacts")
This has a bunch of concrete benefits:
No need to set CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG or CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE
This will work for MinSizeRel and RelWithDebInfo, plus any custom configurations one might add down the line.
Since it's defined as a cache variable, it can be overridden for debugging / working around name clashes, etc.
A bit more context for (3): most CMAKE_* variables are intended to be either read-only or user-configurable (i.e. at the command line, from the GUI, etc.). Overriding their defaults via set(CACHE) is a polite compromise. A notable exception to this rule is the collection of Qt codegen flags (CMAKE_AUTO{MOC,RCC,UIC}). These must typically be set for the build to produce usable binaries.

Detect presence of generator expressions in CMake

The use case for the following problem is macro packages which are deployed, so the input is entirely user defined.
Consider the following minimal example:
function(foo)
cmake_parse_arguments(FOO "" "POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH" "" ${ARGN})
# Chosen as an example for a necessary step which doesn't have a generator expression equivalent
get_filename_component(
ABSOLUTE_PATH
"${FOO_POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH}"
REALPATH
BASE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}"
)
# Compatible with generator expressions by itself
add_custom_command(
OUTPUT
${MY_OUTPUT}
COMMAND
${MY_TOOL}
${ABSOLUTE_PATH}
)
endfunction()
add_custom_command itself supports generator expressions, but the need to go via get_filename_component to handle one class of input (relative paths, for brevity in calling code), and the use of that intermediate step being impossible for the other class of input (build type dependent generator expressions, which get scrambled by get_filename_component) clashes.
get_filename_component effectively can't be used whenever POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH had contained any genex components. get_filename_component has no generator expression equivalent either, so substitution of that logic isn't possible.
Is there a robust way to detect the presence of valid generator expressions in a CMake variable, so it can be used as a signal not to attempt any non-genex transformations on that input?
You could use command string(GENEX_STRIP) which strips generator expressions from the string, and compare its result with original string:
string(GENEX_STRIP "${FOO_POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH}" no_genex)
if(FOO_POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH STREQUAL no_genex)
# The string doesn't contain generator expressions.
# It is safe to use e.g. 'get_filename_component'
else()
# The string contains generator expressions.
# This case requires special handling.
endif()

Map in Cmake script

I'd like to map a variable to a string, as in this example in pseudo-cmake code
map(mymap "val1" "key1" "val2" "key2") # <-- this seems not to exist
set(filename "prependfilename${mymap[${avar}]}otherpartoffilename")
basically in my case i have to concat the strings "a32" or "a64" on the filename based on the ${ANDROID_ABI} (which is a variable expressing the target architecture type) value.
How to achieve a simple map behaviour for variables in CMake?
CMake doesn't support [] or {} operators, but mapping could be achieved by naming scheme for a variable:
# The naming scheme: mymap_<val>
set(mymap_val1 key1) # Maps val1 => key1
set(mymap_val2 key2) # Maps val2 => key2
# ...
set(avar val1) # Some key
message("Key ${avar} is mapped into: ${mymap_${avar}}")
This way for "mapping" is actively used by CMake itself.
E.g. variable CMAKE_<LANG>_COMPILER maps a programming language to the compiler and variable CMAKE_<LANG>_FLAGS_<CONFIG> maps both language and configuration type into the compiler flags, specific for this configuration.

Refer to the property of a target in generator expression of custom target

CMake version: 3.16.2
I'm trying to write a custom target for CMake, which allows me to get some properties from a known target.
I have this code:
add_custom_target(target_printer
COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:known_target, BINARY_DIR>"
)
On the configuration step, I faced the next problem:
Error evaluating generator expression:
$<TARGET_PROPERTY:known_target, BINARY_DIR>
Property name not supported.
Any suggestions?
When using generator expressions to retrieve one of the properties of a CMake target, CMake first verifies that the requested property is valid. During this verification, CMake will check to see if the provided property BINARY_DIR is a well-formed CMake property via regular expressions. It is a valid property, but the verification fails because of the extra space provided next to the property name. Generator expressions have very specific syntax (relevant example here), and in this case, spaces are not permitted surrounding the property name BINARY_DIR. Try removing the extra space before BINARY_DIR:
add_custom_target(target_printer
COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:known_target,BINARY_DIR>"
)

Set type PATH for a Semicolon-separated list of directories CMake variable

Is it legit to write
cmake -S. -Bbuild -DCMAKE_LIBRARY_PATH:PATH="path1;path2"
I mean CMAKE_LIBRARY_PATH is a:
Semicolon-separated list of directories specifying a search path for the find_library() command.
So is it ok to flag it as type PATH ?
src: https://cmake.org/cmake/help/latest/variable/CMAKE_LIBRARY_PATH.html
Actually, you don't need to specify the variable's type when running CMake from command line, since the TYPE property defines which widgets a CMake GUI tool uses for that variable:
Widget type for entry in GUIs.
But to answer your question: No, I think it's not OK to use the PATH type in that case, since then the GUI would present you with a file choose dialog, which allows to select only one directory.