Jereme Givens-Lamothe

ZestyMeta: A pleasing arrangement of vowels and consonants.

github gitlab twitter linkedin
Building DDS Applications with CMake
Jul 22, 2018
3 minutes read

Previously we modified the example application published on Qt Company’s blog to build on Ubuntu 16.04 LTS. We then migrated the examples from RTI’s Traditional C++ API to the newer Modern C++ API. I’d lack to scratch one more itch, and make use of Modern CMake to build the DDS blog examples.

CMake is an open-source, cross-platform family of tools designed to build, test and package software (https://cmake.org). Qt has excellent support for CMake, although a few holes in the documentation can make adoption a bit challenging (Presenting an opportunity for future blog posts on the topic!). Modern CMake is set of best practices that as best I can tell are documented everywhere and nowhere online. There is no single authoritative source on the subject at this time, but it’s easy to find talks and blogs that seem to come to a general consensus on the do’s and don’ts.

RTI provides official CMake modules, which are made available to our project via the following lines in the top-level CMakeLists.txt. This offers an immediate improvement over our hardcoded support, for a single platform, in the prior qmake project file. Complete documentation on the capabilities of these CMake modules can be found within the headers of the two cmake files at $NDDSHOME/resource/cmake.

find_package(RTIConnextDDS)
find_package(RTICodeGenerator)

The headers, libraries, and compile defitions are then explicitly added as dependencies to the “common” project. I’ve created this project to encompass the responsibilities of the old dds.pri, the generation of sources from our sensor.idl file. “common” is both project name and the name of the CMake target, a static library which will be used by all three example applications.

target_link_libraries(common
  PUBLIC ${CONNEXTDDS_CPP2_API_LIBRARIES_RELEASE_SHARED}
)

target_include_directories(common
  PUBLIC ${PROJECT_BINARY_DIR}
  PUBLIC ${PROJECT_SOURCE_DIR}
  PUBLIC ${CONNEXTDDS_INCLUDE_DIRS}
)

target_compile_definitions(common
  PUBLIC RTI_UNIX
  PUBLIC RTI_LINUX
  PUBLIC RTI_64BIT
)

All of this work gets brought into the individual examples via the following. Let’s say that “example” is the project name of a Qt application. Using target_link_libraries we can instruct CMake to figure out what dependencies to bring along for the ride. In this case, anything marked PUBLIC from “common”.

target_link_libraries(example
  common
)

The greatest advantage to our use of CMake is the reduction from the whole of dds.pri to the following 15 lines. This can be leveraged to great effect when generating sources from multiple IDL files. Simply loop over the custom command in a macro with a list of IDL to generate the needed source files.

set(GENERATED_SOURCES
  ${PROJECT_BINARY_DIR}/sensor.cxx
  ${PROJECT_BINARY_DIR}/sensorImpl.cxx
  ${PROJECT_BINARY_DIR}/sensorImplPlugin.cxx
 )

add_custom_command(OUTPUT ${GENERATED_SOURCES}
  COMMAND ${RTICODEGEN} -language C++11 -d ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/sensor.idl
  WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  DEPENDS ${PROJECT_SOURCE_DIR}/sensor.idl
)

set_source_files_properties(${GENERATED_SOURCES} PROPERTIES GENERATED TRUE)

add_library(common
  ${GENERATED_SOURCES}
)

To build the project, we’ll assume that Qt is in your PATH. The follwing commands effectively replace qmake and make.

cmake -DCONNEXTDDS_ARCH=x64Linux3gcc5.4.0 -DCMAKE_MODULE_PATH=$NDDSHOME/resource/cmake -DRTICODEGEN_DIR=$NDDSHOME/bin .. 
cmake --build .

Qt Creator is capable of opening CMake projects as well. In my opinion, this results in a cleaner project view and better management of shared dependencies. Some additional work is needed in the Projects configuration to set the CMake variables as in the command above.

Qt Creator CMake

There is an even cleaner, and more “Modern CMake”-ish way to integrate RTI Connext DDS into this project, but I leave that as an exercise to the reader.


Back to posts