Datatypes

There Are No Datatypes, Basta

  • Everything is a string

  • Can be interpreted as numeric, boolean, path, … (see if, And Conditions for full ranting)

  • My impressions is: although other languages are not typed either, no language does a job as bad as CMake’s (even the good ol’ shell is somewhat cool)

  • Not all is as hard as if booleans though

  • “Methods” provided for strings that are interpreted as

    • Strings

    • Lists

    • Regular expressions

  • Complication: where methods in other languages have return values (such as a str.substring(0,5)), CMake sets output variables (there is no return value in the language)

  • Rule: variable names are passed to method unquoted

    string(APPEND variable "value")
    

Attention: Inconsistencies All Over

What follows is a relatively random list of “methods” on strings and lists. Please read the documentation to get an impression of what is available.

CMake is not very consistent! Be sure to test your code, if possible, using standalone scripts before you integrate it into a project build!

The string(FIND...) method, for example, requires us to pass the string content - not the variable name - for it to work.

set(some_variable "Mississippi")
string(FIND "${some_variable}" "ss" position_found)

On the contrary, the list(LENGTH...) method wants me to pass the variable name that contains the list.

set(some_variable "a" "b" "c")
list(LENGTH some_variable length)

Strings

  • Many methods for string modification ⟶ variable passed unquoted (c/f “per-reference”)

  • Many methods for string examination ⟶ variable passed quoted (c/f “per-copy”)

Strings: In-Place Modification Of A Variable (Use Unquoted Names)

  • Variable is passed for modification

  • ⟶ per-reference

  • ⟶ unquoted

set(some_string "Hello")
string(APPEND some_string " ")
string(APPEND some_string "String")
message("${some_string}")
$ cmake -P string-inplace-simple.cmake
Hello String

Pitfall: In-Place Modification Of Undefined Variable

Appending to an undefined variable creates that variable

string(APPEND some_string "Hello")
message("${some_string}")
$ cmake -P string-append-undefined.cmake
Hello

Attention

This is not only true for string operations, but is a pattern across the language!

Pitfall: Quoted Variable Names For In-Place Modification

Passing a variable in quotes ("${some_variable}") is rarely what’s wanted

  • Evaluates "${some_variable}"

  • Operates on that variable

  • ⟶ undefined, mostly

set(some_string "Hello")
string(APPEND ${some_string} " ")
string(APPEND ${some_string} "String")

message("Variable 'some_string': >${some_string}<")
message("Variable 'Hello' created: >${Hello}<")
$ cmake -P string-pitfall-quote-varname.cmake
Variable 'some_string': >Hello<
Variable 'Hello' created: > String<

Strings: Non-Modifying Operations (Use Quoted Names)

  • Non-modifying methods work best on copies of variables

  • ⟶ quoting/evaluation

  • Note how the to-be-created output variable is passwd

set(some_string "Mississippi")
string(FIND "${some_string}" "ss" position_found)
message("${position_found}")
$ cmake -P string-substring.cmake
2

Pitfall: Unquoted Variable Names For Non-Modifying Operations

set(some_string "Mississippi")
string(FIND some_string "ss" position_found)
message("${position_found}")
$ cmake -P string-substring-unquoted.cmake
-1

Strings: Methods, By Example

  • Find a substring (returns position)

    set(some_string "Mississippi")
    string(FIND "${some_string}" "ss" position_found)
    message("${position_found}")
    
    $ cmake -P string-substring.cmake
    2
    
    set(some_string "Mississippi")
    string(FIND "${some_string}" "ss" position_found REVERSE)
    message("${position_found}")
    
    $ cmake -P string-substring-reverse.cmake
    5
    
  • Joining a number of strings

    string(JOIN " " joined_string "Hello" "World")
    message("${joined_string}")
    
    $ cmake -P string-join.cmake
    Hello World
    
  • Comparing strings (and storing a boolean value for later use)

    set(lhs "Faschingbauer")
    set(rhs "Zeilinger")
    
    string(COMPARE LESS "${lhs}" "${rhs}" is_less)
    if (is_less)
      message("${lhs} < ${rhs}")
    endif()
    
    $ cmake -P string-compare.cmake
    Faschingbauer < Zeilinger
    

Lists

  • A list is a string where the list items are separated with semicolons (";")

  • Created using set()

    set(some_list "a" "b" "c")
    message("${some_list}")
    
    $ cmake -P list-create-with-set.cmake
    a;b;c
    
  • … or with any of the modifying list commands

    list(APPEND some_list "a" "b" "c")
    message("${some_list}")
    
    $ cmake -P list-create-with-append.cmake
    a;b;c
    
  • Various commands (message()) take lists, implicitly. Best by example.

    set(some_list "a" "b")
    message("some_list as string: >${some_list}<")
    message("some_list as string: >" ${some_list} "<")
    
    set(some_string "a b")
    message("some_string, interpolated: >${some_list}<")
    message("some_string, unquoted: >" ${some_list} "<")
    
    $ cmake -P list-message.cmake
    some_list as string: >a;b<
    some_list as string: >ab<
    some_string, interpolated: >a;b<
    some_string, unquoted: >ab<
    

Lists: Iteration (foreach Loop)

  • foreach() operates on elements, not on lists (see foreach Loops)

  • Separators can either be spaces (" ") or semicolons (";")

  • ⟶ Unquoted string reference (clearly 🐷)

list(APPEND some_list "a" "b" "c")
foreach (loop_var ${some_list})
  message("${loop_var}")
endforeach()
$ cmake -P list-iterate.cmake
a
b
c

Lists: Methods, By Example

  • Appending elements to a list

    set(some_list "a" "b")
    list(APPEND some_list "c" "d")
    
    message("${some_list}")
    
    $ cmake -P list-append.cmake
    a;b;c;d
    
  • Length of a list

    set(some_list "a" "b")
    list(LENGTH some_list some_length)
    message("${some_length}")
    
    list(LENGTH "${some_list}" some_length)
    message("${some_length}")
    
    $ cmake -P list-length.cmake
    2
    0
    
  • Remove element at position

    set(some_list "a" "b" "c" "d")
    list(REMOVE_AT some_list 2)
    message("${some_list}")
    
    $ cmake -P list-remove-at.cmake
    a;b;d