近期在编译一个Ros2的包(jazzy)时,出现交叉编译一直无法编译通过的问题,但是在非交叉编译环境能正常编译和运行,报错如下:
上图错误信息主要显示:
1、在编译elevation_map_publisher_node这个节点的时候,要链接libbuiltin_interfacesrosidl_generator_c.so
2、这个库在交叉编译工具链中存在,并已经被编译器找到(dir 0 is [/opt/sysroot/opt/ros/jazzy/lib]),该路径为交叉编译目录(aarch64)
3、但是提示(dir 4 must precede it due to runtime library [libuiltin_interfacesrosidl_generator_c.so]),意思是dir 的路径必须要在运行时库libuiltin_interfacesrosidl_generator_c.so之前链接
4、dir 4(/opt/ros/jazzy/lib)是主机环境目录(x86_64),但是提示dir 0必须在运行时库libnav_msgsrosidl_generator_py.so之前链接
5、/usr/lib/gcc-cross/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/bin/ld: /opt/ros/jazzy/lib/libbuiltin_interfacesrosidl_generator_c.so: error adding symbols: file in wrong format,显示libbuiltin_interfacesrosidl_generator_c.so文件格式错误
核心报错有两个:
1、同时链接到了交叉编译环境(aarch64)和主机环境(x86),并存在循环依赖的问题,导致编译器无法确定到底要链接哪个库,编译报错
2、链接libbuiltin_interfacesrosidl_generator_c.so的时候,链接到了/opt/ros/jazzy/lib/libbuiltin_interfacesrosidl_generator_c.so路径,该文件路径是x86_64的环境,应该链接到aarch64的环境,导致报库文件格式不对的错误。
求助cursor,回答如下:
1、检查CMakeLists.txt文件
首先怀疑是Ros2包CMakeLists.txt的问题,可能哪里依赖不对,但是检查后没发现任何异常,这是一个比较简单常见写法的CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)project(elevation_map_publisher)# ROS 2 jazzy 推荐使用 C++17if(NOT CMAKE_CXX_STANDARD)set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic -O2)endif()find_package(ament_cmake REQUIRED)find_package(rclcpp REQUIRED)find_package(std_msgs REQUIRED)find_package(sensor_msgs REQUIRED)find_package(geometry_msgs REQUIRED)find_package(nav_msgs REQUIRED)find_package(tf2 REQUIRED)find_package(tf2_ros REQUIRED)find_package(tf2_eigen REQUIRED)find_package(tf2_geometry_msgs REQUIRED)find_package(grid_map_core REQUIRED)find_package(grid_map_ros REQUIRED)find_package(grid_map_msgs REQUIRED)find_package(pcl_ros REQUIRED)find_package(pcl_conversions REQUIRED)find_package(PCL REQUIRED COMPONENTS common io filters)find_package(Eigen3 REQUIRED)include_directories(include${EIGEN3_INCLUDE_DIRS}${PCL_INCLUDE_DIRS})add_executable(elevation_map_publisher_nodesrc/MapCropper.cppsrc/ElevationMapNode.cppsrc/elevation_map_node_main.cpp)ament_target_dependencies(elevation_map_publisher_noderclcppstd_msgssensor_msgsgeometry_msgsnav_msgstf2tf2_rostf2_eigentf2_geometry_msgsgrid_map_coregrid_map_rosgrid_map_msgspcl_rospcl_conversions)target_link_libraries(elevation_map_publisher_node${PCL_LIBRARIES}Eigen3::Eigen)install(TARGETS elevation_map_publisher_nodeDESTINATION lib/${PROJECT_NAME})install(DIRECTORY launch config rvizDESTINATION share/${PROJECT_NAME})install(DIRECTORY include/DESTINATION include/)if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)ament_lint_auto_find_test_dependencies()endif()ament_package()
2、检查交叉编译配置
交叉环境的配置文件已经使用过很长时间,之前从来没有出现过类似问题,相关设置也是标准设置:
# Copyright (c) 2018, ARM Limited.# SPDX-License-Identifier: Apache-2.0set(CMAKE_SYSTEM_NAME Linux)set(CMAKE_SYSTEM_VERSION 1)set(CMAKE_SYSTEM_PROCESSOR aarch64)# Specify the cross compilerset(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)set(CMAKE_SYSROOT /opt/sysroot)set(CMAKE_FIND_ROOT_PATH /opt/sysroot /opt/sysroot/opt/ros/jazzy)set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
在交叉编译配置文件中强制设置rosidl_typesupport_c的查找目录为交叉编译环境目录(已经确认头文件和库文件都存在):
set(rosidl_typesupport_c_DIR ${CMAKE_SYSROOT}/opt/ros/jazzy/share/rosidl_typesupport_c/cmake CACHE PATH "" FORCE)set(rosidl_typesupport_c_LIB ${CMAKE_SYSROOT}/opt/ros/jazzy/lib)
重新编译依然报相同错误。
3、修改编译脚本
怀疑是编译脚本中的环境设置问题(主要是AMENT_PREFIX_PATH和CMAKE_PREFIX_PATH环境便来那个),导致同时链接到了交叉编译目录和主机目录,尝试修改:
修改前:
source /opt/ros/jazzy/local_setup.bashcolcon build \--cmake-args -DCMAKE_TOOLCHAIN_FILE=/opt/sysroot/toolchain_aarch64.cmake
修改脚本,把AMENT_PREFIX_PATH等环境变量都unset掉,然后强制设置AMENT_PREFIX_PATH指向交叉编译目录,并增加环境变量的打印:
修改后:
source /opt/ros/jazzy/local_setup.bashunset AMENT_PREFIX_PATHunset CMAKE_PREFIX_PATHunset LD_LIBRARY_PATHunset ROS_DISTROunset COLCON_PREFIX_PATH# 强制设置AMENT_PREFIX_PATH指向交叉编译目录export AMENT_PREFIX_PATH=/opt/sysroot/opt/ros/jazzy# 打印AMENT_PREFIX_PATHenv | grep AMENT_source /opt/sysroot/opt/ros/jazzy/setup.bash# 打印AMENT_PREFIX_PATHenv | grep AMENT_# 清空后必须为空!echo "====================================="echo "AMENT_PREFIX_PATH=$AMENT_PREFIX_PATH"echo "CMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH"echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"echo "====================================="colcon build \--cmake-args -DCMAKE_TOOLCHAIN_FILE=/opt/sysroot/toolchain_aarch64.cmakeenv | grep AMENT_
修改完后重新编译,依然报错。
4、继续求助cursor:
cursor给出了几个疑点,其中这个疑点最可疑:
大致意思是编译中有Ros包在它自己的*Config.cmake 文件中导出了它自己的绝对路径的库目录(/opt/ros/jazzy/lib/…),并给出了查看方法:
grep -rln "/opt/ros/jazzy/lib" /opt/sysroot/opt/ros/jazzy/share 2>/dev/null | head -20
搜索了一下,果然有两个文件中包含绝对路径:
/opt/sysroot/opt/ros/jazzy/share/nav2_costmap_2d/cmake/export_nav2_costmap_2dExport.cmake/opt/sysroot/opt/ros/jazzy/share/pcl_ros/cmake/export_pcl_rosExport.cmake
对应的两个包分别是pcl_ros和nav2_constmap_2d,这两个包都是使用apt直接安装的。
看文件内容:
头文件目录固定指向了/usr/include和/opt/ros/jazzy/include,库文件目录固定指向了/usr/lib和/opt/ros/jazzy/lib:
找到了问题所在,解决方法很简单,将上面两个Config.cmake中的路径指向修改为交叉编译路径:
cd /opt/sysroot/opt/ros/jazzy/share/pcl_ros/cmakesudo cp export_pcl_rosExport.cmake export_pcl_rosExport.cmake.bksudo sed -i "s|/usr/include|/opt/sysroot/usr/include|g" export_pcl_rosExport.cmakesudo sed -i "s|/usr/lib|/opt/sysroot/usr/lib|g" export_pcl_rosExport.cmakesudo sed -i "s|/opt/ros/jazzy|/opt/sysroot/opt/ros/jazzy|g" export_pcl_rosExport.cmakecd /opt/sysroot/opt/ros/jazzy/share/nav2_costmap_2d/cmakesudo cp export_nav2_costmap_2dExport.cmake export_nav2_costmap_2dExport.cmake.bksudo sed -i "s|/usr/include|/opt/sysroot/usr/include|g" export_nav2_costmap_2dExport.cmakesudo sed -i "s|/usr/lib|/opt/sysroot/usr/lib|g" export_nav2_costmap_2dExport.cmakesudo sed -i "s|/opt/ros/jazzy|/opt/sysroot/opt/ros/jazzy|g" export_nav2_costmap_2dExport.cmake
重新编译,OK,在此感谢cursor的强大!