Building ROS Noetic on Ubuntu 22.04
What is this article about ?
This article enables you to self-build a roscore and ROS tools like rostopic, roslaunch and rosparam, by providing a step-by-step description of how to build ROS Noetic on Ubuntu 22.04 from sources.
ROS offers different software bundles in order to serve different use cases, as can be seen here. To keep the efforts limited, this article’s focus is on the ROS Noetic Base bundle. In order to have a green field and no unexpected errors, we will create a docker image including all the necessary dependencies for building and running the code.
Performing all of the following steps gives the same result as running sudo apt install ros-noetic-ros-base
as described at the
ROS Installation Guide.
Why do we want to do this ?
As mentioned here, ROS Noetic is primarily targeted at Ubuntu 20.04 and doesn’t officially support any newer distribution. Further, ROS Noetic is the last available ROS 1 version and is going to be discontinued in May 2025.
Thus, if you want to use ROS Noetic after end of life on Ubuntu 22.04 or any newer Ubuntu distribution, there is actually almost no way around building the required packages on your own.
How can we do it ?
First of all, please make sure you have the following packages installed on your native system to be able to run the commands without error interruptions:
- docker
- python-3
- pip3
- git
ROS Noetic base packages
The first thing we need to do is to figure out which packages are part of the original ros-noetic-ros-base package. The easiest way to get this information, is to make use of the rosinstall_generator
as it is described here.
To get a list of required packages and version tags we simply run the following two commands within the terminal:
pip3 install -U rosinstall_generator
rosinstall_generator ros_base --rosdistro noetic --deps --tar > noetic-base.rosinstall
The resulting file noetic-base.rosinstall should contain something like:
- tar:
local-name: actionlib/actionlib
uri: https://github.com/ros-gbp/actionlib-release/archive/release/noetic/actionlib/1.14.0-1.tar.gz
version: actionlib-release-release-noetic-actionlib-1.14.0-1
- tar:
local-name: bond_core/bond
uri: https://github.com/ros-gbp/bond_core-release/archive/release/noetic/bond/1.8.6-1.tar.gz
version: bond_core-release-release-noetic-bond-1.8.6-1
- tar:
local-name: bond_core/bond_core
uri: https://github.com/ros-gbp/bond_core-release/archive/release/noetic/bond_core/1.8.6-1.tar.gz
version: bond_core-release-release-noetic-bond_core-1.8.6-1
- tar:
local-name: bond_core/bondcpp
uri: https://github.com/ros-gbp/bond_core-release/archive/release/noetic/bondcpp/1.8.6-1.tar.gz
version: bond_core-release-release-noetic-bondcpp-1.8.6-1
...
By inspecting noetic-base.rosinstall and researching for the original GitHub repositories, we get the following list of packages and version tags:
actionlib-1.14.0 | bond_core-1.8.6 | catkin-0.8.10 | class_loader-0.5.0 | cmake_modules-0.5.0 | common_msgs-1.13.1 | dynamic_reconfigure-1.7.3 | gencpp-0.7.0 | geneus-3.0.0 | genlisp-0.4.18 | genmsg-0.6.0 | gennodejs-2.0.1 | genpy-0.6.16 | message_generation-0.4.1 | message_runtime-0.4.13 | nodelet_core-1.10.2 | pluginlib-1.13.0 | ros-1.15.18 | ros_comm-1.16.0 | ros_comm_msgs-1.11.3 | ros_environment-1.3.2 | rosbag_migration_rule-1.0.1 | rosconsole-1.14.3 | rosconsole_bridge-0.5.4 | roscpp_core-0.7.2 | roslisp-1.9.25 | rospack-2.6.2 | std_msgs-0.5.13
Cloning the repositories
Since we are dealing with ROS packages and make use of catkin as a build tool, we need to follow the ROS package structure.
Therefore, we simply create a root directory called ros_noetic_base_2204 and a catkin workspace by executing
mkdir -p ros_noetic_base_2204/catkin_ws/src
ros_noetic_base_2204
└── catkin_ws
└── src
Now it is time to clone all the necessary GitHub repositories. This can be achieved by executing the following commands within the directory ros_noetic_base_2204/catkin_ws/src
git clone https://github.com/ros/actionlib.git -b 1.14.0
git clone https://github.com/ros/bond_core.git -b 1.8.6
git clone https://github.com/ros/catkin.git -b 0.8.10
git clone https://github.com/ros/class_loader.git -b 0.5.0
git clone https://github.com/ros/cmake_modules.git -b 0.5.0
git clone https://github.com/ros/common_msgs.git -b 1.13.1
git clone https://github.com/ros/dynamic_reconfigure.git -b 1.7.3
git clone https://github.com/ros/gencpp.git -b 0.7.0
git clone https://github.com/jsk-ros-pkg/geneus.git -b 3.0.0
git clone https://github.com/ros/genlisp.git -b 0.4.18
git clone https://github.com/ros/genmsg.git -b 0.6.0
git clone https://github.com/RethinkRobotics-opensource/gennodejs.git -b 2.0.1
git clone https://github.com/ros/genpy.git -b 0.6.16
git clone https://github.com/ros/message_generation.git -b 0.4.1
git clone https://github.com/ros/message_runtime.git -b 0.4.13
git clone https://github.com/ros/nodelet_core.git -b 1.10.2
git clone https://github.com/ros/pluginlib.git -b 1.13.0
git clone https://github.com/ros/ros.git -b 1.15.8
git clone https://github.com/ros/ros_comm.git -b 1.16.0
git clone https://github.com/ros/ros_comm_msgs.git -b 1.11.3
git clone https://github.com/ros/ros_environment.git -b 1.3.2
git clone https://github.com/ros/rosbag_migration_rule.git -b 1.0.1
git clone https://github.com/ros/rosbag_migration_rule.git -b 1.0.1
git clone https://github.com/ros/rosconsole.git -b 1.14.3
git clone https://github.com/ros/rosconsole_bridge.git -b 0.5.4
git clone https://github.com/ros/roscpp_core.git -b 0.7.2
git clone https://github.com/ros/roslisp.git -b 1.9.25
git clone https://github.com/ros/rospack.git -b 2.6.2
git clone https://github.com/ros/std_msgs.git -b 0.5.13
Additionally to the repositories listed above, we also need to clone catkin_pkg as well as rospkg. Those libraries are non catkin packages and therefore need to stay outside the catkin_ws in order to avoid build errors later on. It is ok to just put it into the root directory
git clone https://github.com/ros-infrastructure/catkin_pkg.git -b 0.5.2
git clone https://github.com/ros-infrastructure/rospkg.git -b 1.5.0
ros_noetic_base_2204
├── catkin_pkg
├── catkin_ws
└── rospkg
Creating the Docker environment
To build the previously cloned packages, a docker environment is used. We start with a minimum Dockerfile based on Ubuntu 22.04 containing some build essentials and add in the course of the following steps further dependencies.
ros_noetic_base_2204
├── catkin_pkg
├── catkin_ws
├── Dockerfile
└── rospkg
Dockerfile:
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
cmake \
build-essential \
python3 \
pip
The docker image can be build by run the following command inside the root directory:
docker build -t ros_noetic_base_2204 .
In order to run the docker image and mount the current directory (ros_noetic_base_2204), we need to execute:
docker run -it --rm -v .:/ros_noetic_base_2204 ros_noetic_base_2204 bash
Building
The easiest way to build ROS Noetic base from scratch successfully, is to use a trial and error approach.
This simply means that we loop through the following steps over and over again until finally everything is building without errors:
- execute the build command
- add missing dependencies and python packages directly to the Dockerfile or adapt code
- rebuild and rerun the docker image
- start over again
Lets do it !
At first we need to build and run the docker image
docker build -t ros_noetic_base_2204 .
docker run -it --rm -v .:/ros_noetic_base_2204 ros_noetic_base_2204 bash
and then start the build by using the following commands
cd /ros_noetic_base_2204/catkin_pkg && python3 setup.py install
cd /ros_noetic_base_2204/rospkg && python3 setup.py install
cd /ros_noetic_base_2204/catkin_ws
./src/catkin/bin/catkin_make install \
-DCMAKE_BUILD_TYPE=Release \
-DPYTHON_EXECUTABLE=/usr/bin/python3
after a few seconds we get the following error
...
-- Could NOT find PY_em (missing: PY_EM)
CMake Error at catkin/cmake/empy.cmake:30 (message):
Unable to find either executable 'empy' or Python module 'em'... try
installing the package 'python3-empy'
Call Stack (most recent call first):
catkin/cmake/all.cmake:164 (include)
CMakeLists.txt:29 (include)
-- Configuring incomplete, errors occurred!
In order to resolve this error, we need to add the missing pyton3-empy
dependency to the Dockerfile and redo the execution loop:
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
cmake \
build-essential \
python3 \
pip
RUN apt-get install -y \
python3-empy
# Execute within the native terminal
docker build -t ros_noetic_base_2204 .
docker run -it --rm -v .:/ros_noetic_base_2204 ros_noetic_base_2204 bash
# Execute inside the docker image
cd /ros_noetic_base_2204/catkin_pkg && python3 setup.py install
cd /ros_noetic_base_2204/rospkg && python3 setup.py install
cd /ros_noetic_base_2204/catkin_ws
./src/catkin/bin/catkin_make install \
-DCMAKE_BUILD_TYPE=Release \
-DPYTHON_EXECUTABLE=/usr/bin/python3
Et voilà! The above error is gone, but we run right away into the next one
CMake Error at /usr/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
Could NOT find Boost (missing: Boost_INCLUDE_DIR thread system)
Call Stack (most recent call first):
/usr/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
/usr/share/cmake-3.22/Modules/FindBoost.cmake:2360 (find_package_handle_standard_args)
class_loader/CMakeLists.txt:12 (find_package)
-- Configuring incomplete, errors occurred!
See also "/ros_noetic_base_2204/catkin_ws/build/CMakeFiles/CMakeOutput.log".
In this case the boost-thread library is missing. Therefore, we also add this dependency to the Dockerfile and redo the execution loop.
This procedure is now done over and over again until all dependency issues are resolved.
In the end, the final Dockerfile looks like:
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
cmake \
build-essential
RUN apt-get install -y \
libboost-thread-dev \
libboost-system-dev \
libboost-filesystem-dev \
libboost-regex-dev \
libboost-program-options-dev \
libconsole-bridge-dev \
libpoco-dev \
libtinyxml2-dev \
liblz4-dev \
libbz2-dev \
uuid-dev \
liblog4cxx-dev \
libgpgme-dev \
libgtest-dev
RUN apt-get install -y \
python3 \
python3-pip \
python3-setuptools \
python3-empy \
python3-nose \
python3-pycryptodome \
python3-defusedxml \
python3-mock \
python3-netifaces \
python3-gnupg \
python3-numpy \
python3-psutil
Once we run the build again after creating the new Docker image, we get the following error:
/ros_noetic_base_2204/catkin_ws/src/rosconsole/src/rosconsole/impl/rosconsole_log4cxx.cpp: In function ‘void ros::console::impl::initialize()’:
/ros_noetic_base_2204/catkin_ws/src/rosconsole/src/rosconsole/impl/rosconsole_log4cxx.cpp:169:23: error: cannot convert ‘ros::console::impl::ROSConsoleStdioAppender*’ to ‘log4cxx::AppenderPtr’ {aka ‘std::
shared_ptr<log4cxx::Appender>’}
169 | logger->addAppender(new ROSConsoleStdioAppender);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| ros::console::impl::ROSConsoleStdioAppender*
...
This error is caused by a change of the log4cxx
API from version 0.10.0
to 0.12.1
.
log4cxx
is used within the ROS packages ros_comm
as well as rosconsole
. In order to resolve these errors, we need to apply the following patches to the packages ros_comm
and rosconsole
.
The easiest way to apply the patches, is to save the diff in a file and make use of the command git apply --ignore-whitespace <patch-file>
within the appropriate packages.
After applying the patches we run the build again and IT BUILDS!
Testing
Unfortunately, we are not completely done yet, because we should also check if all the unit tests are passing.
In order to do so, we simply add the command run_tests
to the end of our build command and execute it
cd /ros_noetic_base_2204/catkin_ws
./src/catkin/bin/catkin_make install \
-DCMAKE_BUILD_TYPE=Release \
-DPYTHON_EXECUTABLE=/usr/bin/python3 \
run_tests
and unfortunately, there is a build error again
In file included from /usr/include/log4cxx/log4cxx.h:45,
from /usr/include/log4cxx/logstring.h:28,
from /usr/include/log4cxx/level.h:22,
from /ros_noetic_base_2204/catkin_ws/src/rosconsole/include/ros/console.h:46,
from /ros_noetic_base_2204/catkin_ws/src/pluginlib/pluginlib/include/pluginlib/class_loader.hpp:42,
from /ros_noetic_base_2204/catkin_ws/src/pluginlib/pluginlib/test/unique_ptr_test.cpp:32:
/usr/include/log4cxx/boost-std-configuration.h:10:18: error: ‘shared_mutex’ in namespace ‘std’ does not name a type
10 | typedef std::shared_mutex shared_mutex;
but this one is rather easy to fix.
By having a look at the CMakeLists file of the package pluginlib
we can see that the target ${PROJECT_NAME}_unique_ptr_test
is explicitly compiled with c++ standard 11. pluginlib
is making use of the library log4cxx
, which is using the new shared_mutex
feature only available within c++ standard 17 upwards.
Thus, to make this work we need to change the CMakeLists file so that ${PROJECT_NAME}_unique_ptr_test
is compiled with c++17 instead of c++11:
diff --git a/pluginlib/CMakeLists.txt b/pluginlib/CMakeLists.txt
index 289c5af..1776c02 100644
--- a/pluginlib/CMakeLists.txt
+++ b/pluginlib/CMakeLists.txt
@@ -24,12 +24,12 @@ if(CATKIN_ENABLE_TESTING)
endif()
include(CheckCXXCompilerFlag)
- check_cxx_compiler_flag("-std=c++11" COMPILER_SUPPORTS_CXX11)
- if(COMPILER_SUPPORTS_CXX11)
+ check_cxx_compiler_flag("-std=c++17" COMPILER_SUPPORTS_CXX17)
+ if(COMPILER_SUPPORTS_CXX17)
catkin_add_gtest(${PROJECT_NAME}_unique_ptr_test test/unique_ptr_test.cpp)
if(TARGET ${PROJECT_NAME}_unique_ptr_test)
target_link_libraries(${PROJECT_NAME}_unique_ptr_test ${TinyXML2_LIBRARIES} ${catkin_LIBRARIES} ${Boost_LIBRARIES})
- set_target_properties(${PROJECT_NAME}_unique_ptr_test PROPERTIES COMPILE_FLAGS -std=c++11 LINK_FLAGS -std=c++11)
+ set_target_properties(${PROJECT_NAME}_unique_ptr_test PROPERTIES COMPILE_FLAGS -std=c++17 LINK_FLAGS -std=c++17)
add_dependencies(${PROJECT_NAME}_unique_ptr_test test_plugins)
endif()
endif()
cd /ros_noetic_base_2204/catkin_ws
./src/catkin/bin/catkin_make install \
-DCMAKE_BUILD_TYPE=Release \
-DPYTHON_EXECUTABLE=/usr/bin/python3 \
run_tests
Congratulations, you managed to build ROS Noetic base from sources!
Since everything is building now, we are ready to start a roscore. Therefore we need to source, the ROS setup file and run the command roscore.
source /ros_noetic_base_2204/catkin_ws/devel/setup.bash
roscore