We use the ROS C++ Style guide for all C++ development and the ROS Python Style guide for Python.
To ease your development, we recommend the automated code formatter clang-format
with a ROS configuration - to use see below.
In addition MoveIt has some extra style preferences:
std::
) whenever possibleFLT_EPSILON
- instead use std::numeric_limits<double>::epsilon()
TODO(username): description
robot_state_
over rs_
auto
, if the variable type doesn’t become clear immediately from the context (e.g. from make_shared<...>
)[[deprecated]]
attributeAdd a useful message describing how to handle the situation:
[[deprecated("use bar instead")]] void foo() {}
Which will result in:
warning: 'foo' is deprecated: use bar instead [-Wdeprecated-declarations] foo(); ^ note: 'foo' has been explicitly marked deprecated here void foo() {} ^
catch (...)
as it hides information about a possible fault. We want to know if something goes wrong.std::exception
in MoveIt. It is the responsibility of the plugin provider to handle non-std::exception
-derived exceptions locally.ROS_INFO_NAMED(LOGNAME, "Starting listener...
.
const
variable. (eg: constexpr char LOGNAME[] = "robot_state";
)"planning_scene"
shared_ptr
of any object, use MoveIt’s standard macro MOVEIT_CLASS_FORWARD(ClassName)
before the class declaration, and add the include #include <moveit/macros/class_forward.h>
. This will create two typedefs of shared pointers - <ClassName>Ptr
and <ClassName>ConstPtr
using either boost
or std
.MoveIt uses one folder for all headers from all of its modules: include/moveit
. To achieve this, install all headers to ${CATKIN_GLOBAL_INCLUDE_DESTINATION}
rather than using the normal CATKIN_PACKAGE_INCLUDE_DESTINATION
:
install(DIRECTORY include/ DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION})
This is rather non-standard for catkin - catkin would prefer to have headers of each ROS package in a separate folder,
e.g. include/moveit_core/...
, include/moveit_ros_planning/...
, etc.
In many of our repos we have a pre-commit check that runs in CI. You can use this locally and set it up to run automatically before you commit something. To install, use pip:
pip3 install pre-commit
To run over all the files in the repo manually:
pre-commit run -a
To run pre-commit automatically before committing in a local repo, install git hooks:
pre-commit install
Note that if you use pre-commit as described above, clang-format is applied automatically before each commit (if clang-format
is installed). This section describes how to use it manually.
You can run clang-format in several ways. To install on Ubuntu simply run:
sudo apt install clang-format
clang-format requires a configuration file in the root of your catkin workspace. The MoveIt repo contains this file here.
Format a single file:
clang-format-10 -i -style=file MY_ROS_NODE.cpp
Format an entire directory recursively including subfolders:
find . -name '*.h' -or -name '*.hpp' -or -name '*.cpp' | xargs clang-format-10 -i -style=file $1
Occasionally the auto formatting used by clang-format might not make sense e.g. for lists of items that are easier to read on separate lines. It can be overwritten with the commands:
// clang-format off
... some untouched code
// clang-format on
Use this sparingly though.
In your ~/.emacs
config file, add the following:
Format your source code if its in some directory such as the catkin_ws
(feel free to change keywords catkin_ws):
(defun run-ros-clang-format ()
"Runs clang-format on cpp,h files in catkin_ws/ and reverts buffer."
(interactive)
(and
(string-match "/catkin_ws/.*\\.\\(h\\|cpp\\)$" buffer-file-name)
(save-some-buffers 'no-confirm)
(shell-command (concat "clang-format-10 -style=file -i " buffer-file-name))
(message (concat "Saved and ran clang-format on " buffer-file-name))
(revert-buffer t t t)
))
Set a keyboard shortcut to run, such as F12
(global-set-key [f12] 'run-ros-clang-format)
Navigate to Tools
> Options
> Beautifier
On the General
tab, enable auto format on file save, using ClangFormat
.
On the Clang Format
tab, configure clang-format-10
as your executable and choose Use predefined style
from File
.
clang-tidy is a linting tool for C++. Where clang-format will fix the formatting of your code (wrong indentation, line length, etc), clang-tidy will fix programming errors to make your code more modern, more readable, and less prone to common bugs.
You can install clang-tidy and other clang related tools with
sudo apt install clang-tidy clang-tools
Similarly to clang-format, clang-tidy uses the configuration file .clang-tidy
that is found first when traversing the source folder hierarchy upwards. The MoveIt repo provides this file here.
Unlike clang-format, clang-tidy needs to know the exact compiler options used to build your project.
To provide them, configure cmake with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
and cmake will create in the package’s build
folder a file called compile_commands.json
. After building, you can run clang-tidy to analyze your code and even
fix issues automatically as follows:
for file in $(find $CATKIN_WS/build -name compile_commands.json) ; do
run-clang-tidy -fix -header-filter="$CATKIN_WS/.*" -p $(dirname $file)
done
You can run it also on selected folders or files of a package by specifying regular expressions to match the file names:
run-clang-tidy -fix -header-filter="$CATKIN_WS/.*" -p $CATKIN_WS/build/moveit_core collision
Note that if you have multiple layers of nested for
loops that need to be converted, clang-tidy
will only fix one at a time. So be sure to run the above command a few times to convert all code.
If you are only interested in the warnings, clang-tidy can also run directly during your build. You can make a specific clang-tidy build with:
catkin config --cmake-args -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_CLANG_TIDY=clang-tidy
catkin build
It is possible to suppress undesired clang-tidy checks by using NOLINT or NOLINTNEXTLINE comments. Please specify the check names explicitly in parentheses following the comments:
const IKCallbackFn solution_callback = 0; // NOLINT(modernize-use-nullptr)
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
robot_state::RobotState robot_state(default_state);
Note that modernize-loop-convert
check may convert for (...; ...; ...)
loops to for (auto & ... : ...)
.
However, auto
is not an expression highly readable.
Please explicitly specify the variable type, if it doesn’t become clear immediately from the context:
for (const int & item : container)
std::cout << item;