Build ROS2 stack for iOS software development.
This valuable experience allows us to build and run ROS2 on Mac including graphical tools such as RVIZ as well. Even better, you can simply download our release, add some environment variables and run.
For the impatient: Instead of building ROS2 from source (see below), you can download our prebuilt libs and extract it.
Then make a symlink ros2
pointing to the extracted ros2_$PLATFORM
where we can find the ROS2 lib
and include
headers
ln -s PATH_TO_EXTRACTED_ros2_$PLATFORM ros2
You should of course change the symlink target when switching between building for real iPhone, simulator and Mac Catalyst. Now we can run the demo application which ports the official example: Run the app on two simulator instances, click on Start publishing on one and Start listening on the other.
Note: To run Mac Catalyst app on your macOS machine, you need to sign the app with your development signing certificate.
Main guides:
We are going to need
- CMake 3.23 until this issue is sorted out
- Python 3.10
- Xcode + Command Line tools
installed. All subsequent shell commands are to be done at $REPO_ROOT
.
Also, create a Python virtual environment for ease of package installation
python3 -m venv ros2PythonEnv
source ros2PythonEnv/bin/activate
python3 -m pip install -r requirements.txt
If you have other environment management such as Anaconda, remember to DEACTIVATE them.
-
We are going to disable most packages and add back only those that are necessary. To do that, I deviate from the guide to get the sources into
unused_src
insteadmkdir unused_src vcs import unused_src < ros2.repos touch unused_src/AMENT_IGNORE # So that colcon will not find packages in unused_src
Note: The better method is to use
colcon
's--packages-up-to
. -
Move the minimal packages
ros2/rcl
,ros2/rmw
,ros2/rosidl
tosrc
to startmkdir -p src/ros2 mv unused_src/ament src/ mv unused_src/eProsima src/ mv unused_src/ros2/rcl src/ros2/ mv unused_src/ros2/rmw src/ros2/ mv unused_src/ros2/rosidl src/ros2/ mv unused_src/ros2/common_interfaces src/ros2/
It is good to have
ros2/common_interfaces
as it provides the commonly used packages such asstd_msgs
.Certain heavy graphic-based packages such as
rviz
are obviously not easy to port. We will runcolcon
commands (below) and add back more dependent packages.Tip: Do
find unused_src -name PKG_NAME
inunused_src
to find the repository containing the needed package. -
The minimal list of repositories is available in the file
ros2_min.repos
. So of course, one can simply import this instead. Here, I choose to use a single RMW implementation (via Fast-DDS). -
Create a new workspace and link the
src
inmkdir -p ros2_ws cd ros2_ws ln -s $REPO_ROOT/src src
-
During development, it is good to have multiple workspaces such as
ament_ws
: moveament
here, build andsource
it before moving on tobase_ws
: addrcl
and its dependencies and once successfulrclcpp_ws
: add other desired packages such asrclcpp
.
This way, one can minimize the amount of packages to rebuild.
Before building, we need to change the line #include <net/if_arp.h>
in src/eProsima/Fast-DDS/src/cpp/utils/IPFinder.cpp
into #include <net/ethernet.h>
according to this as the original header is only available in the macOS SDK.
We also disable the package rcl_logging_spdlog
by
touch src/ros2/rcl_logging/rcl_logging_spdlog/AMENT_IGNORE
To build for iOS simulator on Intel Macs, do
cd ros2_ws
#Prepend with VERBOSE=1 and add --executor sequential --event-handlers console_direct+ while debugging
colcon build --merge-install \
--cmake-force-configure \
--cmake-args \
-DCMAKE_TOOLCHAIN_FILE=$REPO_ROOT/cmake/iOS_Simulator.cmake \
-DBUILD_TESTING=NO \
-DTHIRDPARTY=FORCE \
-DCOMPILE_TOOLS=NO \
-DFORCE_BUILD_VENDOR_PKG=ON \
-DBUILD_MEMORY_TOOLS=OFF \
-DRCL_LOGGING_IMPLEMENTATION=rcl_logging_noop
For M1 Mac or for real iPhones, you would need to change iOS_Simulator.cmake
appropriately.
After my tons of failures, here is what went going on behind the above command:
-
The classical method to CMake for iOS simulator in my other projects such as LibGit2 is to set the appropriate
CMAKE_OSX_SYSROOT
andCMAKE_OSX_ARCHITECTURES
.Note: The right way to get
clang
to compile for iOS simulator is to set toCMAKE_C_FLAGS
andCMAKE_CXX_FLAGS
, namely-target x86_64-apple-ios-simulator -mios-version-min=14.0
together with-isysroot
to find the standard headers.However, that is not going to work here. The reason is because of the
***_vendor
packages which are proxy packages for 3rd party libraries such aslibyaml
: their CMake files fetch the library and passing to their CMake with the "right" options. Checking for examplelibyaml_vendor/CMakeLists.txt
reveals that it does NOT pass along all ourCMAKE_***
options except forCMAKE_C_FLAGS
and even forceBUILD_SHARED_LIBS=ON
. We need to pass along all desired options in-DCMAKE_TOOLCHAIN_FILE
and in that file, we set up all the desired CMake variables.Note: Even this is not going to be enough for some package such as
mimick_vendor
as it sets its internal variable_ARCH
BEFORE considering the toolchain file! -
BUILD_TESTING=NO
to disable all test packages, without this, we are going to need a ton of third party packages such asament/google_benchmark_vendor
,ament/uncrustify_vendor
,ament/googletest
,osrf/osrf_testing_tools_cpp
,ros2/performance_test_fixture
andros2/mimick_vendor
and account for a ton of CMake issues -
THIRDPARTY=FORCE
is to ask eProsima Fast-DDS to build and use its own dependencies (asio
, ...) so that we do not have to install it to the system with Homebrew -
COMPILE_TOOLS=NO
forFast-DDS
to NOT compile the fast discovery server executable. -
FORCE_BUILD_VENDOR_PKG=ON
is to build and use the*_vendor
packages such aslibyaml_vendor
, again so that we do not have to install it to the system with Homebrew -
BUILD_MEMORY_TOOLS=OFF
is forfoonathan_memory
to disable buildingnodesize_db
program -
RCL_LOGGING_IMPLEMENTATION=rcl_logging_noop
is to select the logging backend forrcl_logging
. Here, I am usingnoop
one to avoid one more dependencyspdlog_vendor
. -
ROS2 depends significantly on dynamic linking. Do NOT add
BUILD_SHARED_LIBS=NO
, contrary to my other project LLVM where building static libs is needed!