When using a CMake list to specify multiple arguments to a function, empty arguments are not passed as arguments to the list. In some cases an empty string is needed as an argument. Is there a way to achieve this?
If I run this
set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDOUT)
set(LIST_VAR
"ONE"
"TWO"
""
"FOUR"
)
execute_process(
COMMAND
${CMAKE_COMMAND} -E echo
${LIST_VAR}
)
execute_process(
COMMAND
${CMAKE_COMMAND} -E echo
"ONE"
"TWO"
""
"FOUR"
)
with
cmake -P test.cmake
I get:
'cmake' '-E' 'echo' 'ONE' 'TWO' 'FOUR'
ONE TWO FOUR
'cmake' '-E' 'echo' 'ONE' 'TWO' '' 'FOUR'
ONE TWO FOUR
In the first variant the third, empty argument is swallowed, which is really annoying if there are cases, where an empty argument may be possible/needed and arguments are prepared as CMake lists.
In my application I need to call a script and not cmake -E echo
, which expects empty arguments in certain situations.
Also, the empty entries are - of course - not put in literally as in this simplified example. Instead of ""
I have something like "${MIGHT_BE_EMPTY}"
.
Is there a way to safely transport empty strings as list entries to function arguments?
If not, is there a good work-around for this problem?
E.g. transform unset variables to something like a space (" "
) which might be equivalent to an empty argument for the called script?
The problem is that there are no lists in CMake, only strings. And there is a convention that some CMake commands understand: if there are unquoted
;
(semicolon) in the variable then it is a list, where each element of the list separated from another by;
. And there is a rule which allows to create lists out of multiple strings separated by a whitespace. So this command:Creates a variable with the following content:
ONE;TWO;;FOUR
which is a list in the CMake book. Now there is another rule (reverse) which CMake uses when it expands unquoted variables:So you can't use empty elements and have CMake lists propagate them across the script. You can use something non-empty like an empty element, though. For example, you could use the space character to mean the element is empty if it wouldn't mess with your other data:
And if you can't modify the list with explicitly providing an
${EMPTY}
element you can add it to the existing list like this:string(REPLACE ";;" ";${EMPTY};" LIST_VAR "${LIST_VAR}")
.Finally, if you need to modify not a list but some particular, potentially empty variable then you can use the following:
I use the
EMPTY
variable because it is convenient, you can drop it and replace with whatever symbol you like—it won't make a difference.