<commit_before><commit_msg>add draft of ament article<commit_after>---
layout: default
title: The meta build system "ament"
permalink: articles/ament.html
abstract:
  This article describes the meta build system "ament".
published: true
author: '[<NAME>](https://github.com/dirk-thomas)'
---

* This will become a table of contents (this text will be scraped).
{:toc}

# {{ page.title }}

<div class="abstract" markdown="1">
{{ page.abstract }}
</div>

Original Author: {{ page.author }}


## ament

`ament` is a meta build system to build applications which are split into separate packages.

It relies on meta information about the packages to determine their build dependencies.
This meta information is specified in a file called `package.xml` which is defined in [REP 140](http://www.ros.org/reps/rep-0140.html).

ament consists of several separate parts:

* [ament_package](https://github.com/ament/ament_package) is a Python package providing an API to parse the files containing the meta information.
* [ament_cmake](https://github.com/ament/ament_cmake) contains a set of packages which provide CMake based functionality.
  The features are split across several packages in order to ensure that they are cleanly separated from each other.
  The main feature of the CMake packages is to automatically generate a CMake config file to pass information to downstream packages.
* [ament_lint](https://github.com/ament/ament_lint) contains a set of packages which perform linting tasks.
  For a set of linters a ROS 2 specific configuration is provided which can be used via the command line as well as from within CMake (commonly as a CTest).
* [ament_tools](https://github.com/ament/ament_tools) is a Python package which provides command line tools to build, test and install packages.
  It is similar to [catkin_tools](https://github.com/catkin/catkin_tools) and builds each package in a workspace in topological order.
  Each different build system is integrated through extension points.
  While it currently does not build packages in parallel that will be added in the future to speed up the build process.
* [ament_index](https://github.com/ament/ament_index) contains a set of packages which provide API to access the [ament resource index](https://github.com/ament/ament_cmake/blob/master/ament_cmake_core/doc/resource_index.md).
  Currently it only contains a Python implementation but other languages like C++ should follow.


### Integrate arbitrary build systems

Each package can utilize a different build system to perform the steps of configuring, building and installing.
Currently supported are CMake and Python but support for others (e.g. autotools, plain Makefiles) will likely be added in the future.
For each of them the native steps are being applied separately by the ament tools.


### Environment creation

Commonly the install space should follow the [Filesystem Hierarchy Standard (FHS)](http://www.pathname.com/fhs/).
But that is just a recommendation and not enforced by ament.

Depending on where the packages are being installed it might be necessary to setup the environment in order to find all resources.
E.g. the location of installed executables should be on the `PATH`, installed Python code should be on the `PYTHONPATH` etc.

Therefore each package can provide a shell script to setup the environment to match its needs.
The shells scripts in the root of the install space, which are generated by the ament tools, will then only iterate over the scripts from each package to setup the environment.


### Symlinked install

It is very important to maximize the efficiency of the development cycle of changing code, building and installing it and then run it to confirm the changes.
Commonly the installation steps involves copying some resources from the source space to their final destination in the install location.
ament provides an option to create symbolic links instead (if the platform supports that).
This enables the developer to change the resources in the source space and skipping the installation step in many situations.

For CMake packages this is achieved by overriding the CMake `install()` function.
For Python packages the [development mode[(http://pythonhosted.org//setuptools/setuptools.html#development-mode) is used to install the package.


## How does *ament* relate to *catkin*?

`catkin` has been used for ROS 1 since ROS Groovy.
`catkin` is based around CMake and even packages only containing Python code are being processed via CMake.
It was developed as a replacement of `rosbuild` which was used from the beginning of ROS.
Therefore various features of catkin have been designed to be similar to rosbuild.


### Why not continue to use *catkin*?

catkin has many advantages over rosbuild.
Those cover out-of-source builds, automatic CMake config file generation, an installation target and many more.
But for some cases it is not flexible enough or not as easy to use as it should be.
A few of these cases are mentioned below and all addressed by ament:


#### *Devel space*

catkin has the feature to provide a so called [devel space](http://wiki.ros.org/catkin/workspaces#Development_.28Devel.29_Space) after building a set of packages.
That folder is providing a fully working ROS environment without the need to install the packages.
Avoiding to copy any files allows to e.g. edit Python code and immediately try running the code.

While this is a very convenient feature and speeds up the development process it comes at a cost.
The necessary logic in catkin increases its complexity significantly.
Additionally the CMake code in every ROS package has to make sure to handle the *devel space* correctly which puts an extra effort on every ROS developer.

ament provides the same advantage using the option of *symlinked installs* without the extra complexity for each ROS package.


#### *CMAKE_PREFIX_PATH*

catkin relies directly on the `CMAKE_PREFIX_PATH` environment variable to store the prefixes of multiple workspace.
This has been considered not a good approach since it interferes with other values set in the variable and is a CMake specific build variable.
Therefore ament uses a separate environment variable (`AMENT_PREFIX_PATH`) for that purpose which is used at runtime.
At build time of CMake packages the CMake specific variable can be derived from the generic ament variable.


#### catkin_simple

The ROS package [catkin_simple](https://github.com/catkin/catkin_simple) was the attempt to make the common cases of developing ROS packages easier.
While it is able to reduce the complexity of the CMake code in some ROS packages it fails conceptually in other cases.
Some of the limitations were due to core catkin design decisions like the order and position of calling certain CMake functions etc.

E.g. the function `catkin_package()` must be invoked *before* any target in order to setup the appropriate location for the build targets in the devel space.
But in order to automatically perform several tasks in the code generation step this functionality needs to happen *after* all target have been defined.

With the different design of ament it becomes possible to implement a package similar to catkin_simple which can actually work reliably in all the cases where catkin_simple fails.


#### Building within a single CMake context

catkin allows to build multiple packages within a single CMake context (using `catkin_make`).
While this significantly speeds up the process it is not scalable at large.
This is due to the fact that all packages share the same CMake namespace.
Therefore the package might have colliding target names or fail to build correctly due to side effects between the packages.
ament does not provide that feature due to these drawbacks.


### Additional improvements in ament over catkin

catkin is a single monolithic package providing various features and functionalities.
E.g. it integrates support for `gtest` which makes it very difficult to also optionally support `gmock` since only one tool can be selected at a time.

ament on the other hand is designed to be very modular.
Almost every feature is provided by a separate package and can be optionally used.
The CMake part of ament also features an extension point system to extend it with further functionality (see above).


### Why not evolve *catkin* with the necessary features?

One important goal of ROS 2 is to [*not* interrupt ROS 1](http://design.ros2.org/articles/why_ros2.html) in any way.
Any changes to catkin would potentially introduce regressions into ROS 1 which is undesired.

Additionally some necessary changes would require a different usage of catkin in every ROS package.
Releasing such a change into ROS 1 in a future distribution would imply a significant effort for each developer which should also be avoided.
Not to mention the effort to update the documentation and tutorials and making the users aware of the subtle changes.


### Why use a new name instead of continuing to call it *catkin*?

For the use case of building a bridge between ROS 1 and ROS 2 it must be possible to access both code bases in a single project.
With both build systems having the same name they would not be distinguishable on a CMake level (which of the two packages is found with `find_package(catkin)`?).
Therefore the package names of both build system must be different.

The newly developed build system has similar CMake functions but they have partly different arguments and / or are being called in different locations.
With both system called the same (or even very similar) a significant user confusion was expected.
It was considered to name the new build system `catkin2` but the similarity would likely still have led to user confusion.
Therefore a different name has been selected (ament is a synonym for catkin) to clarify the different context and behavior.


### Why has *catkin_pkg* been forked to *ament_package*?

ament as well as ROS 2 in general is using Python 3 exclusively.
`catkin_pkg` as well as many other ROS 1 Python packages cannot be side-by-side installed for Python 2 and Python 3 at the same time.
So requiring python3-catkin-pkg for ROS 2 would collide with python-catkin-pkg for ROS 1 and would make both ROS versions not installable at the same time.

ament_package only implements the specification [REP 140](http://www.ros.org/reps/rep-0140.html).
It does not support *package.xml* files with an older format.

Additionally it does provide the templates for all the environment hooks so that each package can generate its own environment and does not rely on an external tool to setup the environment.
Beside that the package provides none of the additional functionalities of catkin_pkg (no crawling, no topological ordering, etc.).

{'fraction_non_alphanumeric': 0.04677494199535963, 'fraction_numerical': 0.0035266821345707657, 'mean_word_length': 4.644840230487166, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 6, 'https://': 9, 'lorem ipsum': 0, 'www.': 3, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1738531', 'n_tokens_mistral': 2633, 'n_tokens_neox': 2503, 'n_words': 1588}