# CMake While you don't need to know everything about CMake to use ROS 2, knowing a bit will really be helpful. You might be interested in the [CMake tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/index.html) which explains the basics of CMake. ## Ament Ament is a set of CMake modules specifically designed for ROS 2 with the intent of making CMake easier to use. See the [Ament CMake](https://docs.ros.org/en/rolling/How-To-Guides/Ament-CMake-Documentation.html) documentation. The basic structure of an ament package: ```cmake cmake_minimum_required(VERSION 3.8) project(my_package_name) # Default to C++17 if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 17) endif() if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif() # Find packages find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) # Include our own headers include_directories(include) # Create a node add_executable(my_node src/my_node.cpp) ament_target_dependencies(my_node rclcpp # Other ament dependencies # This sets up include and linker paths ) add_library(my_library src/my_library.cpp) ament_target_dependencies(my_library rclcpp ) # Install our headers install( DIRECTORY include/ DESTINATION include ) # Install our node and library install( TARGETS my_node my_library ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION lib/${PACKAGE_NAME} ) # Install some Python scripts install( PROGRAMS scripts/my_script.py DESTINATION lib/${PROJECT_NAME} ) # Tell downstream packages where to find our headers ament_export_include_directories(include) # Tell downstream packages our libraries to link against ament_export_libraries(my_library) # Help downstream packages to find transitive dependencies ament_export_dependencies( rclcpp ) ament_package() ``` ## Linting Configuration I prefer a more ROS 1-style code style. To allow braces to be on their own lines: ```cmake if(BUILD_TESTING) find_package(ament_cmake_cpplint) ament_cpplint(FILTERS "-whitespace/braces" "-whitespace/newline") endif() ``` ## Safely Defaulting to Release Build This pattern appears in various places in ROS 2: ```cmake if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) message("${PROJECT_NAME}: Defaulting to Release build") set(CMAKE_BUILD_TYPE Release) endif() ``` ## Installing Python Scripts ```cmake install( PROGRAMS scripts/script1.py scripts/script2.py DESTINATION lib/${PROJECT_NAME} ) ``` ## Depending on Messages in Same Package It is generally best practice to put messages in separate packages, but sometimes, especially for drivers, you want the messages in the same package. The following example worked in earlier versions of ROS 2 - but the syntax has changed See the [Implementing custom interfaces tutorial](https://docs.ros.org/en/rolling/Tutorials/Beginner-Client-Libraries/Single-Package-Define-And-Use-Interface.html#link-against-the-interface) for newer ROS 2 distributions. ```cmake # Note: this WILL NOT work in ROS 2 Humble or later find_package(rosidl_default_generators REQUIRED) # Generate some messages rosidl_generate_interfaces(${PROJECT_NAME} "msg/MyMessage.msg" ) # Add a node which uses the messages add_executable(my_node my_node.cpp) rosidl_target_interfaces(my_node ${PROJECT_NAME} "rosidl_typesupport_cpp") ``` ## Removing Boost from Pluginlib Pluginlib supports both boost::shared_ptrs and std::shared_ptrs by default, if you want to avoid depending on Boost in your shiny new ROS 2 library, you need to specifically tell pluginlib not to include the Boost versions: ```cmake target_compile_definitions(your_library PUBLIC "PLUGINLIB__DISABLE_BOOST_FUNCTIONS") ``` ## Using Eigen3 Add _eigen_ to your package.xml as a dependency, and then: ```cmake find_package(Eigen3 REQUIRED) include_directories(${EIGEN3_INCLUDE_DIRS}) ``` ## Building Python Extensions in C++ The example below is based on the [etherbotix](https://github.com/mikeferguson/etherbotix) package. ```cmake find_package(PythonLibs REQUIRED) find_package(Boost REQUIRED python) find_package(ament_cmake_python REQUIRED) find_package(python_cmake_module REQUIRED) ament_python_install_package(${PROJECT_NAME}) add_library( my_python SHARED ${SOURCE_FILES} ) set_target_properties( my_python PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME} PREFIX "" ) target_link_libraries(my_python ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ) install( TARGETS my_python DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}" ) ```