Developer Guidelines

Workspace

Package description

The following packages are provided:

Each repository may contain one or more packages. When a repository contains two or more packages, it is expected that all packages’ versions within the same repository get updated together. Git will tag them all simultaneously.

Continuous integration

Each repository in the workspace contains a few jobs that run under the following circumstances:

  • On a push event: the last commit of branch compiles and runs the package tests with gcc and ld.

  • On a pull request event:

    • gcc build and tests will be executed:

      For this workflow, action-ros-ci is used, in an attempt to be as standard as possible with ros packages. This action supports having interdependent pull request, see here. This may be useful when your PR depends on PRs/MRs/branches from other repos for it to work or be properly tested.

    • clang build, sanitizers and static analyzer will be triggered using specific labels in the pull request:

      • do-clang-test executes clang build and test, asan, ubsan and tsan (when enabled) build and test.

      • do-static-analyzer-test executes scan-build in the project.

  • Scheduled job: there are two types of scheduled jobs. One that runs every night and executes a full build and test of the entire workspace with gcc. Another weekly event runs also the sanitizers and static analyzer. Every night, a tarball with a full build is generated as a way to have snapshots of the workspace binaries.

See Compiler support for more details.

Coding standards

Languages

C++ programming

The workspace uses C++ 17 and each package should compile with gcc and clang (see Compiler support for more details).

The workspace follows Drake style guide which is a derivative of Google style guide.

Exceptions:

  • Line length: is modified to 120 columns to better fit the modern and wider screens.

Python programming

Code is formatted following PEP8.

CMake programming

CMake is the underlying build system tool and language, it is treated as a first class citizen like C++ and Python. For that reason, the following general conventions must be followed on top of ROS2 CMake conventions.

Libraries
  • All libraries should be SHARED libraries. Consider using set(BUILD_SHARED_LIBS true) in your top level CMakeLists.txt file.

  • Libraries should not include in their target name the project name unless they are the main library in the package. We don’t expect to have as target names maliput_foo for the foo functionality.

  • Use namespaces the following way: project_name\:\:library_name as follows:

1add_library(maliput::foo ALIAS foo)
  • Use _ instead of - in compound names.

  • Include in the binary name the project name:

1set_target_properties(foo
2  PROPERTIES
3    OUTPUT_NAME maliput_foo
4)
  • General install() commands are expected as follows:

1install(
2  TARGETS foo
3  EXPORT ${PROJECT_NAME}-targets
4  ARCHIVE DESTINATION lib
5  LIBRARY DESTINATION lib
6  RUNTIME DESTINATION bin
7)
  • Use ament_export_libraries(my_custom_library).

  • Consider using the generation expressions for target_include_directories within the project:

1target_include_directories(foo
2  PUBLIC
3    $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
4    $<INSTALL_INTERFACE:include>
5)
  • Header file only libraries should be created as interfaces and header files must be placed in the include directory at the top level of the package. Make sure to install those header files later on. The target name is superfluous because those files will be discoverable by the consuming target if paths are properly set. However, the decision is to add another layer of security at the target level.

  • When using the maliput plugin architecture system, if shared library and executable are compiled using ubsan`(undefined behavior sanitizer) the property `ENABLE_EXPORTS should be enabled on the executable target in order to instruct the linker to add all symbols to the dynamic symbol table. For further information see next reference link.

1set_target_properties(foo
2  PROPERTIES
3    ENABLE_EXPORTS ON
4)
Executables
  • Use _ instead of - in compound names.

  • install() commands are expected as follows:

1install(foo
2  EXPORT ${PROJECT_NAME}-targets
3  ARCHIVE DESTINATION lib
4  LIBRARY DESTINATION lib
5  RUNTIME DESTINATION bin
6)
Resources
  • Define a project resources path and install resources following your structure within share/project_name/resources folder in the install space.

Testing

  • 100% coverage of the public API of any entity must be unit-tested.

  • Complex pieces of code that are not exposed should be considered to be re-engineered in favor of increased coverage.

  • Integration test between modules can be done when appropriate.

  • Consider using maliput_integration_tests for complex integration tests.

  • gtest and gmock via ament_cmake packages are the default testing frameworks for C++.

  • python3-pytest via ament_cmake packages is the default testing frameworks for Python.

Linting

ament_clang_format alone cannot be used because we have a custom format. So packages hold a tools folder at the root level in which a script called reformat_code.sh calls the previous tool with the custom package.

For Python code, make sure to use ament cmake flake8. To do so, you should follow the instructions here and use one of the .flake8 files in your package root directory to tell the linter which are the tests you want to perform. In particular, we edit it so it has the following extras:

 1# Set the maximum length that any line (with some exceptions) may be.
 2max-line-length = 100
 3# Set the maximum allowed McCabe complexity value for a block of code.
 4max-complexity = 10
 5# Toggle whether pycodestyle should enforce matching the indentation of the opening bracket’s line.
 6# incluences E131 and E133
 7hang-closing = True
 8# Specify a list of codes to ignore.
 9ignore =
10    E133,
11    E226,
12# Specify the list of error codes you wish Flake8 to report.
13select =
14  E,
15  W,
16  F,
17  C

Supported OSs and environments

The workspace is only maintained on Ubuntu 18.04 and ROS2 Dashing.

Compiler support

The workspace is built with Ubuntu’s default gcc (version 7.5) and ld (version 2.30) and clang and llvm tools (version 8).

  • Address sanitizer

  • Undefined behavior sanitizer.

  • Thread sanitizer.

  • Static analyzer (scan-build): it runs with clang.

Building the documentation

maliput_documentation package is in charge of concentrating the documentation of the entire maliput ecosystem.

The page is built upon Sphinx framework, while the docstring’s code is converted to html by Doxygen.

The documentation is finally served via Read the Docs.

In order to build the documentation, the cmake flag -DBUILD_DOCS=On should be added:

colcon build --packages-up-to maliput_documentation --cmake-args "-DBUILD_DOCS=On"