Archives for category: CMake

While working on a package manager for CMake I came across the problem of finding a suitable format for my package descriptor files. First I thought about and tried using plain old CMake file that simply sets variables and can be included to access its contents.  It was very quick and easy to implement. Hierarchical data structures however where hard to implement and a none standard format makes it harder to exchange data with a webservice/other programs. So I opted for using JSON as my import/export format.  JSON is alot easier to parse than XML and is still ubiquitous in software developement so I cast aside XML (for now).

You can grab my implementation for reading and writing JSON with CMake  at  https://github.com/toeb/oo-cmake.git.  Its part of my object oriented CMake library and uses my implementation for CMake maps and references.

Note: Because CMake only understands strings the deserializer only accepts string , array or object values.  Also all keys and values have to be double quoted.

As always: feedback is most welcome if you feel like it you can tell me if you find it usefull, have ideas, or think that I have reinvented the wheel.

Here are some examples for serialization and deserialization:

Code Snippet
  1. # serialize empty value
  2. json_serialize(res “”)
  3. assert(NOT res)
  4. # serialze simple value
  5. json_serialize(res “hello!”)
  6. assert(res)
  7. assert(“\”hello!\”” STREQUAL ${res})
  8. #empty object
  9. element(uut MAP)
  10. element(END)
  11. json_serialize(res ${uut})
  12. assert(“{}” STREQUAL ${res})
  13. # empty list
  14. element(uut LIST)
  15. element(END)
  16. json_serialize(res ${uut})
  17. assert(“[]” STREQUAL ${res})
  18. # ref
  19. ref_new(uut)
  20. ref_set(${uut} “a b c”)
  21. json_serialize(res ${uut})
  22. assert(“\”a b c\”” STREQUAL ${res})
  23. # list with one element
  24. element(uut LIST)
  25. value(1)
  26. element(END)
  27. json_serialize(res ${uut})
  28. assert(“[\”1\”]” STREQUAL ${res})
  29. # list with multiple elements element
  30. element(uut LIST)
  31. value(1)
  32. value(2)
  33. element(END)
  34. json_serialize(res ${uut})
  35. assert(“[\”1\”,\”2\”]” STREQUAL ${res})
  36. # object with single value
  37. element(uut MAP)
  38. value(KEY k1 val1)
  39. element(END)
  40. json_serialize(res ${uut})
  41. assert(“{\”k1\”:\”val1\”}” STREQUAL ${res})
  42. # object with multiple value
  43. element(uut MAP)
  44. value(KEY k1 val1)
  45. value(KEY k2 val2)
  46. element(END)
  47. json_serialize(res ${uut})
  48. assert(“{\”k1\”:\”val1\”,\”k2\”:\”val2\”}” STREQUAL ${res})
  49. # list with single map
  50. element(uut LIST)
  51. element()
  52. value(KEY k1 1)
  53. element(END)
  54. element(END)
  55. json_serialize(res ${uut})
  56. assert(“[{\”k1\”:\”1\”}]” STREQUAL ${res})
  57. # list with differnt elements map
  58. element(uut LIST)
  59.     element(MAP)
  60.         value(KEY k1 1)
  61.         value(KEY k2 2)
  62.         value(KEY k3 3)
  63.     element(END)
  64.     element(LIST)
  65.         value(1)
  66.         value(2)
  67.     element(END)
  68.     value(a)
  69.     value(b)
  70. element(END)
  71. json_serialize(res ${uut})
  72. assert(“[{\”k1\”:\”1\”,\”k2\”:\”2\”,\”k3\”:\”3\”},[\”1\”,\”2\”],\”a\”,\”b\”]” STREQUAL ${res})
  73. # deserialize a empty value
  74. json_deserialize(res “”)
  75. assert(NOT res)
  76. # deserialize a empty object
  77. json_deserialize(res “{}”)
  78. assert(res)
  79. ref_isvalid(is_ref ${res} )
  80. assert(is_ref MESSAGE “expected res to be a ref”)
  81. # desirialize a empty array
  82. json_deserialize(res “[]”)
  83. assert(res)
  84. ref_isvalid(is_ref ${res})
  85. assert(is_ref MESSAGE “expected res to be a ref”)
  86. # deserialize a simple value
  87. json_deserialize(res “\”teststring\””)
  88. assert(${res} STREQUAL “teststring”)
  89. # deserialize a array with one value
  90. json_deserialize(res “[\”1\”]”)
  91. map_navigate(${res} val “[0]”)
  92. assert(${val} STREQUAL “1”)
  93. #deserialize a array with multiple values
  94. json_deserialize(res “[\”1\”, \”2\”]”)
  95. map_navigate(${res} val “[0]”)
  96. assert(${val} STREQUAL “1”)
  97. map_navigate(${res} val “[1]”)
  98. assert(${val} STREQUAL “2”)
  99. # deserialize a simple object with one value
  100. json_deserialize(res “{ \”key\” : \”value\”}”)
  101. map_navigate(${res} val “key”)
  102. assert(${val} STREQUAL “value”)
  103. # deserialize a simple object with multiple values
  104. json_deserialize(res “{ \”key\” : \”value\”, \”key2\” : \”val2\”}”)
  105. map_navigate(${res} val “key”)
  106. assert(${val} STREQUAL “value”)
  107. map_navigate(${res} val “key2”)
  108. assert(${val} STREQUAL “val2”)
  109. # deserialize a simple nested structure
  110. json_deserialize(res “{ \”key\” : {\”key3\”:\”myvalue\” }, \”key2\” : \”val2\”}”)
  111. map_navigate(${res} val “key2”)
  112. assert(${val} STREQUAL “val2”)
  113. map_navigate(${res} val “key.key3”)
  114. assert(${val} STREQUAL “myvalue”)
  115. # deserialize a nested structure containing both arrays and objects
  116. json_deserialize(res “{ \”key\” : [\”1\”, \”2\”], \”key2\” : \”val2\”}”)
  117. map_navigate(${res} val “key2”)
  118. assert(${val} STREQUAL “val2”)
  119. map_navigate(${res} val “key[0]”)
  120. assert(${val} STREQUAL “1”)
  121. map_navigate(${res} val “key[1]”)
  122. assert(${val} STREQUAL “2”)
  123. # deserialize a ‘deeply’ nested structure and get a value
  124. json_deserialize(res “{ \”key\” : [{\”k1\”:\”v1\”}, \”2\”], \”key2\” : \”val2\”}”)
  125. map_navigate(${res} val “key[0].k1”)
  126. assert(${val} STREQUAL “v1”)

I worked on my object oriented extensions for CMake  and am on a much higher level of usability than before!

try it at https://github.com/toeb/oo-cmake 

and as always: Feedback is most welcome

See the following object tutorial for ease of use: (for the current version look at the readme.md on github)


### using objects
    ### =============
    # oo-cmake is very similar to javascript
    # I actually used the javascript reference to figure out how things could be done :)
    # oo-cmake is a pure object oriented language like javascript (only objects no types per se)
    # oo-cmake is currently file based and relies heavily on dynamic functions to be upfron about it:
    # oo-cmake is very slow (depending on what your doing)

    ## creating a object
    ## =================
    obj_new(myobject)
    # ${myobject} now is a reference to an object
    obj_exists(${myobject} _exists)
    assert(_exists)

    ## deleting a object
    ## =================
    # oo-cmake does not contains automatic memory management
    # you can however remove all objects by calling obj_cleanup 
    # (a very crude way of garbage collection) I would suggest calling it at the end of cmake.
    obj_new(object_to_delete)
    obj_delete(${object_to_delete})
    # object_to_delete still contains the same reference
    # but the object does not exists anymore and the following returns false
    obj_exists(${object_to_delete} _exists)
    assert(NOT _exists)

    ## setting and setting property
    ## ==================
    obj_new(myobject)
    # call obj_set passing the object reference
    # the propertyname 'key1' and the value 'val1'
    # everything beyond 'key1' is saved (as a list)
    obj_set(${myobject} key1 "val1")
    #call obj_get passing the object refernce the result variable and
    # the key which is to be gotten
    obj_get(${myobject} theValue key1)
    assert(theValue)
    assert(${theValue} STREQUAL "val1")

    ## setting a function and calling it
    ## =================================
    obj_new(obj)
    obj_set(${obj} last_name "Becker")
    obj_set(${obj} first_name "Tobias")
    #obj_setfunction accepts any function (cmake command, string function, file function, unique function (see function tutorial))
    # if you use a cmake function be sure that it will not be overwritten
    # the safest way to add a function is to use obj_declarefunction
    # you can either specify the key where it is to be stored or not
    # if you do not specify it the name of the function is used
    function(greet result)
        # in the function you have read access to all fields of the proeprty
        # as will as to 'this' which contains the reference to the object

        # this sets the variable ${result} in PARENT_SCOPE (returning values in cmake)
        set(${result} "Hello ${first_name} ${last_name}!" PARENT_SCOPE)

    endfunction()
    obj_setfunction(${obj} greet)
    obj_callmember(${obj} greet res)
    assert(res)
    assert(${res} STREQUAL "Hello Tobias Becker!")
    # alternatively you can also use obj_declarefunction
    # this is actually the easiest way to define a function in code
    obj_declarefunction(${obj} say_goodbye)
    function(${say_goodbye} result)
        set(${result} "Goodbye ${first_name} ${last_name}!" PARENT_SCOPE)
    endfunction()
    obj_callmember(${obj} say_goodbye res)
    assert(res)
    assert(res STREQUAL "Goodbye Tobias Becker!")

    ## built in methods
    ## ================
    # obj_new creates a object which automatically inherits Object
    # Object contains some functions e.g. to_string, print, ...
    # 
    obj_new(obj)
    obj_callmember(${obj} print)

    # this prints all members
    # ie
    #{
    # print: [function], 
    # to_string: [function], 
    # __ctor__: [object :object_Y3dVWkChKi], 
    # __proto__: [object :object_AztQwnKoE7], 
    #}

    ## constructors
    ## ============
    # you can easily define a object type via constructor
    function(MyObject)
        # declare a function on the prototype (which is accessible for all objects)
        # inheriting from MyObject
        obj_declarefunction(${__proto__} myMethod)
        function(${myMethod} result)
            set(${result} "myMethod: ${myValue}" PARENT_SCOPE)
            this_set(myNewProperty "this is a text ${myValue}")
        endfunction()

        # set a field for the object
        this_set(myValue "hello")
    endfunction()

    obj_new(obj MyObject)
    # type of object will now be MyObject
    obj_gettype(${obj} type)
    assert(type)
    assert(${type} STREQUAL MyObject)
    # call
    obj_callmember(${obj} myMethod res)
    assert(res)
    assert(${res} STREQUAL "myMethod: hello")
    obj_set(${obj} myValue "othervalue")
    obj_callmember(${obj} myMethod res)
    assert(res)
    assert(${res} STREQUAL "myMethod: othervalue")
    obj_get(${obj} res myNewProperty)
    assert(res)
    assert(${res} STREQUAL "this is a text othervalue")

    ## functors
    ## ========

    ## binding a function
    ## ==================
    # you can bind any function to an object without
    # setting it as property
    # causing the function to get access to 'this'
    # and all defined properties
    function(anyfunction)
        this_callmember(print)
    endfunction()
    obj_new(obj)
    obj_bindcall(${obj} anyfunction)
    ## print the object
    # alternatively you can bind the function to the object
    obj_bind(boundfu ${obj} anyfunction)
    call_function(${boundfu})
    # prints the object
    # alternatively you can bind and import then function
    # beware that you might overwrite a defined function if you append REDEFINE
    # 
    obj_bindimport(${obj} anyfunction myBoundFunc REDEFINE)
    myBoundFunc()
    # print the object