# Cross Compile with OSX as a host ## compile crosstool-ng One debian systems, there are pre-compiled toolchains, for OSX however they have to be built from scratch. A decent tool for creating such toolchains is [crosstool-ng](http://crosstool-ng.github.io/docs/). *Compilation Note* there's a problem with having ncurses installed via homebrew. Add the libs and include paths to LDFLAGS/CXXFLAGS before the configure step For python problems on gdb, see https://stackoverflow.com/a/11600411/4583130 crosstool-ng works similar to linux kernel configurations. A complete example can be found below 01_aarch64-unknown-linux-gnu.config . *Execution Note* the tool requires a case-sensitive filesystem. OSX is not case-sensitive by default. So we have to create a new Volume which is: ``` #!/bin/bash ImageName=CrossToolNG ImageNameExt=${ImageName}.sparseimage diskutil umount force /Volumes/${ImageName} && true rm -f ${ImageNameExt} && true hdiutil create ${ImageName} -volname ${ImageName} -type SPARSE -size 8g -fs HFSX hdiutil mount ${ImageNameExt} cd /Volumes/$ImageName ``` Found here: https://docs.zephyrproject.org/1.9.0/getting_started/installation_mac.html#creating-a-case-sensitive-file-system Once the configuration is built correctly (use samples and modify them for the correct version), the folder layout looks as follows: ``` ➭ ll ~/workspace/toolchains/x86_64/gcc-7.5/x86_64-unknown-linux-gnu total 4096 dr-xr-xr-x 9 karsten staff 288 Oct 16 00:54 ./ drwxr-xr-x 5 karsten staff 160 Oct 19 11:49 ../ dr-xr-xr-x 37 karsten staff 1184 Oct 16 00:53 bin/ -r--r--r-- 1 karsten staff 2095985 Oct 16 00:53 build.log.bz2 dr-xr-xr-x 2 karsten staff 64 Oct 16 00:49 include/ dr-xr-xr-x 7 karsten staff 224 Oct 16 00:49 lib/ dr-xr-xr-x 3 karsten staff 96 Oct 16 00:49 libexec/ dr-xr-xr-x 5 karsten staff 160 Oct 16 00:53 share/ dr-xr-xr-x 8 karsten staff 256 Oct 16 00:49 x86_64-unknown-linux-gnu/ ``` ## cross compile with clang one does not have to cross-compile with a special created gcc compiler. Clang itself (the one on the host platoform) is by defualt a cross compiler. once the toolchain is created with clang, it requires two arguments set, i.e. `sysroot` and `gcc-toolchain`. ``` [ 50%] Building CXX object CMakeFiles/karsten_hello_world.dir/main.cpp.o /usr/local/opt/ccache/libexec/clang++ --target=x86_64-unknown-linux-gnu --sysroot=/Users/karsten/workspace/toolchains/x86_64/gcc-7.5/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/sysroot --gcc-toolchain=/Users/karsten/workspace/toolchains/x86_64/gcc-7.5/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/sysroot/../.. -o CMakeFiles/karsten_hello_world.dir/main.cpp.o -c /Users/karsten/workspace/ctrlx/snap_ws/ctrlx_hello_world/main.cpp [100%] Linking CXX executable karsten_hello_world /usr/local/Cellar/cmake/3.18.4/bin/cmake -E cmake_link_script CMakeFiles/karsten_hello_world.dir/link.txt --verbose=1 /usr/local/opt/ccache/libexec/clang++ --target=x86_64-unknown-linux-gnu --sysroot=/Users/karsten/workspace/toolchains/x86_64/gcc-7.5/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/sysroot --gcc-toolchain=/Users/karsten/workspace/toolchains/x86_64/gcc-7.5/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/sysroot/../.. -L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib -fuse-ld=lld CMakeFiles/karsten_hello_world.dir/main.cpp.o -o karsten_hello_world [100%] Built target karsten_hello_world /usr/local/Cellar/cmake/3.18.4/bin/cmake -E cmake_progress_start /Users/karsten/workspace/ctrlx/snap_ws/ctrlx_hello_world/build/CMakeFiles 0 ``` The equivalent cmake toolchain file: ``` set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR x86_64) set(CMAKE_SYSROOT /Users/karsten/workspace/toolchains/x86_64/gcc-7.5/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/sysroot) set(CMAKE_CXX_FLAGS_INIT "--gcc-toolchain=${CMAKE_SYSROOT}/../..") set(CMAKE_C_FLAGS_INIT "--gcc-toolchain=${CMAKE_SYSROOT}/../..") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(triple x86_64-unknown-linux-gnu) set(CMAKE_C_COMPILER clang) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_CXX_COMPILER clang++) set(CMAKE_CXX_COMPILER_TARGET ${triple}) ``` ## Cross Compile ROS2 Used toolchain file being used is in the file below: 02_aarch64_toolchain.cmake in comibination with a aarch64-unknown-linux-gnu toolchain generated by crosstool-ng. ### Compile Python We need to cross-compile Python and enhance our toolchain with this: ``` wget -c https://www.python.org/ftp/python/3.8.6/Python-3.8.6.tar.xz ``` ``` PATH=~/workspace/toolchains/aarch64/aarch64-unknown-linux-gnu/bin:$PATH ./configure CC=aarch64-unknown-linux-gnu-gcc CXX=aarch64-unknown-linux-gnu-g++ AR=aarch64-unknown-linux-gnu-ar LD=aarch64-unknown-linux-gnu-ld RANLIB=aarch64-unknown-linux-gnu-ranlib --host=aarch64-unknown-linux-gnu --build=x86_64-apple-darwin18 --target=aarch64 -prefix=`pwd`/python3_install --disable-ipv6 ac_cv_have_long_long_format=yes ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no --enable-shared --enable-optimizations && make && make install ``` We then have to integrate these files into our crosstool-ng toolchain sysroot folder. I would assume that's the same as specifying the toolchain sysroot as a `--prefix` in the `configure` step above. ``` cp -r ~/workspace/ros2/ros2_cross_compile/third_party/python3.8.6/Python-3.8.6/python3_install/bin/* bin/ cp -r ~/workspace/ros2/ros2_cross_compile/third_party/python3.8.6/Python-3.8.6/python3_install/lib/* lib/ cp -r ~/workspace/ros2/ros2_cross_compile/third_party/python3.8.6/Python-3.8.6/python3_install/include/* include/ cp -r ~/workspace/ros2/ros2_cross_compile/third_party/python3.8.6/Python-3.8.6/python3_install/share/* share/ ``` ## Compile TinyXml2, libexpat, logging-log4cxx The three packages listed above are all cmake-based packages and can thus conveniently be installed via colcon. ## Compile a ROS2 workspace Foonathan memory can't really be cross-compiled, cyclone_dds is easier. So we skip fastrtps and their dependencies. There is some code generation for cyclonedds needed as well. For this, the `ddsconf` tool has to be executed from the host. Luckily, cyclonedds lets you easily pass in that tool via `-DDDSCONF_EXECUTABLE`. ``` colcon build --merge-install --build-base build_aarch64 --install-base install_aarch64 --event-handler=console_cohesion+ --cmake-args -DBUILD_TESTING=OFF -DCMAKE_TOOLCHAIN_FILE=~/workspace/toolchains/aarch64/aarch64_toolchain.cmake -DDDSCONF_EXECUTABLE=/Users/karsten/workspace/ros2/ros2_cross_compile/tmp/cyclonedds/build/bin/ddsconf --packages-ignore fastrtps rmw_fastrtps_shared_cpp rmw_fastrtps_cpp rmw_fastrtps_dynamic_cpp foonathan_memory_vendor rosidl_typesupport_fastrtps_cpp rosidl_typesupport_fastrtps_c --cmake-clean-ca --packages-up-to examples_rclcpp_minimal_publisher ```