ros2-java / ros2_java

Java and Android bindings for ROS2
Apache License 2.0
174 stars 93 forks source link

Colcon build fails to undefined symbol: osrf_testing_tools_cpp #247

Open Hyrtsi opened 1 month ago

Hyrtsi commented 1 month ago

Greetings,

I followed the build instructions and got this error:

ld.lld: error: undefined symbol: osrf_testing_tools_cpp::memory_tools::on_unexpected_calloc(std::__ndk1::variant<std::__ndk1::function<void (osrf_testing_tools_cpp::memory_tools::MemoryToolsService&)>, std::__ndk1::function<void ()>, std::nullptr_t>)
>>> referenced by performance_test_fixture.cpp:57 (/home/x/ros2_android_ws/src/ros2/performance_test_fixture/src/performance_test_fixture.cpp:57)
>>>               CMakeFiles/performance_test_fixture.dir/src/performance_test_fixture.cpp.o:(performance_test_fixture::PerformanceTest::SetUp(benchmark::State&))

ld.lld: error: undefined symbol: osrf_testing_tools_cpp::memory_tools::on_unexpected_malloc(std::__ndk1::variant<std::__ndk1::function<void (osrf_testing_tools_cpp::memory_tools::MemoryToolsService&)>, std::__ndk1::function<void ()>, std::nullptr_t>)
>>> referenced by performance_test_fixture.cpp:60 (/home/x/ros2_android_ws/src/ros2/performance_test_fixture/src/performance_test_fixture.cpp:60)
>>>               CMakeFiles/performance_test_fixture.dir/src/performance_test_fixture.cpp.o:(performance_test_fixture::PerformanceTest::SetUp(benchmark::State&))

ld.lld: error: undefined symbol: osrf_testing_tools_cpp::memory_tools::on_unexpected_realloc(std::__ndk1::variant<std::__ndk1::function<void (osrf_testing_tools_cpp::memory_tools::MemoryToolsService&)>, std::__ndk1::function<void ()>, std::nullptr_t>)
>>> referenced by performance_test_fixture.cpp:63 (/home/x/ros2_android_ws/src/ros2/performance_test_fixture/src/performance_test_fixture.cpp:63)
>>>               CMakeFiles/performance_test_fixture.dir/src/performance_test_fixture.cpp.o:(performance_test_fixture::PerformanceTest::SetUp(benchmark::State&))
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
gmake[2]: *** [CMakeFiles/performance_test_fixture.dir/build.make:103: libperformance_test_fixture.so] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:160: CMakeFiles/performance_test_fixture.dir/all] Error 2
gmake: *** [Makefile:146: all] Error 2
---
Failed   <<< performance_test_fixture [0.90s, exited with code 2]

How should I resolve it?

I'm using ROS2 Humble, Ubuntu 22.04, Python 3.10.12. Android NDK r27b (27.1.12297006), Android 34 (I guess).


------------------------------------------------------------
Gradle 8.7
------------------------------------------------------------

Build time:   2024-03-22 15:52:46 UTC
Revision:     650af14d7653aa949fce5e886e685efc9cf97c10

Kotlin:       1.9.22
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          21.0.4 (Oracle Corporation 21.0.4+8-LTS-274)
OS:           Linux 6.8.0-45-generic amd64

There is a similar build error here (on macOS): https://github.com/ros2/ros2/issues/1398

There is a plan B to use this: https://github.com/YasuChiba/ros2-android-build

Hyrtsi commented 1 month ago

It looks like performance_test_fixture is a necessary package, because if we add it to --packages-ignore we get:

CMake Error at CMakeLists.txt:19 (find_package):
  By not providing "Findperformance_test_fixture.cmake" in CMAKE_MODULE_PATH
  this project has asked CMake to find a package configuration file provided
  by "performance_test_fixture", but CMake did not find one.

  Could not find a package configuration file provided by
  "performance_test_fixture" with any of the following names:

    performance_test_fixtureConfig.cmake
    performance_test_fixture-config.cmake

  Add the installation prefix of "performance_test_fixture" to
  CMAKE_PREFIX_PATH or set "performance_test_fixture_DIR" to a directory
  containing one of the above files.  If "performance_test_fixture" provides
  a separate development package or SDK, be sure it has been installed.

in building tracetools which is used for ament_build_type_gradle.

Hyrtsi commented 1 month ago

I studied this a little bit more. You can see the actual code as in the repositories here: https://raw.githubusercontent.com/ros2-java/ros2_java/main/ros2_java_android.repos

I built just the culprit and its dependencies. First a vanilla build (no crosscompile):

rm -rf build install
colcon build --packages-select performance_test_fixture google_benchmark_vendor osrf_testing_tools_cpp ament_cmake_google_benchmark

Output: lots of warnings like this:

[0.324s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/x/ros2_android_ws/install/ament_lint_common' in the environment variable AMENT_PREFIX_PATH doesn't exist
[0.325s] WARNING:colcon.colcon_ros.prefix_path.catkin:The path '/home/x/ros2_android_ws/install/ament_cmake_export_definitions' in the environment variable CMAKE_PREFIX_PATH doesn't exist
...
    'performance_test_fixture' is in: /home/x/ros2_android_ws/install/performance_test_fixture
If a package in a merged underlay workspace is overridden and it installs headers, then all packages in the overlay must sort their include directories by workspace order. Failure to do so may result in build failures or undefined behavior at run time.
If the overridden package is used by another package in any underlay, then the overriding package in the overlay must be API and ABI compatible or undefined behavior at run time may occur.

If you understand the risks and want to override a package anyways, add the following to the command line:
    --allow-overriding performance_test_fixture

This may be promoted to an error in a future release of colcon-override-check.

and

Starting >>> ament_cmake_google_benchmark
[5.330s] WARNING:colcon.colcon_core.shell:The following packages are in the workspace but haven't been built:
- ament_package
- ament_cmake_core
- ament_cmake_libraries
- ament_cmake_python
- ament_cmake_export_dependencies
- ament_cmake_test

and

To suppress this warning ignore these packages in the workspace:
--packages-ignore ament_cppcheck ament_lint ament_package ament_cmake_core ament_flake8 ament_cmake_export_definitions ament_cmake_export_include_directories ament_cmake_export_libraries ament_cmake_export_link_flags ament_cmake_include_directories ament_cmake_libraries ament_cmake_python ament_cmake_version ament_pep257 ament_cmake_export_dependencies ament_cmake_export_interfaces ament_cmake_export_targets ament_cmake_target_dependencies ament_cmake_test ament_copyright ament_cmake ament_cpplint ament_lint_auto ament_lint_cmake ament_xmllint ament_cmake_lint_cmake uncrustify_vendor ament_cmake_copyright ament_uncrustify ament_cmake_cppcheck ament_cmake_cpplint ament_cmake_flake8 ament_cmake_pep257 ament_cmake_uncrustify ament_cmake_xmllint ament_lint_common
Finished <<< performance_test_fixture [1.31s]                    

Summary: 4 packages finished [7.01s]
  2 packages had stderr output: google_benchmark_vendor osrf_testing_tools_cpp

but nonetheless the packages have been built. I could get rid of the stderr output like this:

$ colcon build --packages-select performance_test_fixture google_benchmark_vendor osrf_testing_tools_cpp ament_cmake_google_benchmark --allow-overriding performance_test_fixture  ament_cmake_google_benchmark osrf_testing_tools_cpp

Next, if I do the cross compile (as in the README of this repo):

 export PYTHON3_EXEC="$( which python3 )"
 export PYTHON3_LIBRARY="$( ${PYTHON3_EXEC} -c 'import os.path; from distutils import sysconfig; print(os.path.realpath(os.path.join(sysconfig.get_config_var("LIBPL"), sysconfig.get_config_var("LDLIBRARY"))))' )"
 export PYTHON3_INCLUDE_DIR="$( ${PYTHON3_EXEC} -c 'from distutils import sysconfig; print(sysconfig.get_config_var("INCLUDEPY"))' )"
 export ANDROID_ABI=armeabi-v7a
 export ANDROID_NATIVE_API_LEVEL=android-21
 export ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-clang

then build only these packages:

 $ colcon build --packages-select performance_test_fixture google_benchmark_vendor osrf_testing_tools_cpp ament_cmake_google_benchmark --allow-overriding performance_test_fixture  ament_cmake_google_benchmark osrf_testing_tools_cpp    --cmake-args \
   -DPYTHON_EXECUTABLE=${PYTHON3_EXEC} \
   -DPYTHON_LIBRARY=${PYTHON3_LIBRARY} \
   -DPYTHON_INCLUDE_DIR=${PYTHON3_INCLUDE_DIR} \
   -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
   -DANDROID_FUNCTION_LEVEL_LINKING=OFF \
   -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \
   -DANDROID_TOOLCHAIN_NAME=${ANDROID_TOOLCHAIN_NAME} \
   -DANDROID_STL=c++_shared \
   -DANDROID_ABI=${ANDROID_ABI} \
   -DANDROID_NDK=${ANDROID_NDK} \
   -DTHIRDPARTY=ON \
   -DCOMPILE_EXAMPLES=OFF \
   -DCMAKE_FIND_ROOT_PATH="${PWD}/install"

it actually succeeds. So the root problem isn't these packages, but which order they are built or something in my system or that some other packages are broken.

I tried this build script instead, but ran into another problem:

ros2_android_ws/src/ros2-java/ros2_java/rcljava_common/src/main/cpp/rcljava_common.cpp:14:10: fatal error: jni.h: No such file or directory
   14 | #include <jni.h>
      |          ^~~~~~~

Note that this uses a different way to choose the packages. I suspect that the --packages-up-to can be changed to something else to build enough packages for my needs. Some of the packages are definitely obsolete and outdated.

Hyrtsi commented 1 month ago

Ok I got past that error. Instructions here. I just checked my java version:

$ ls /usr/lib/jvm
default-java  java-1.11.0-openjdk-amd64  java-11-openjdk-amd64  jdk-17.0.12-oracle-x64  jdk-21.0.4-oracle-x64  openjdk-11

and then chose which java I want. Then edited the variable JAVA_HOME:

export JAVA_HOME=/usr/lib/jvm/jdk-21.0.4-oracle-x64/

to my desired Java version. Then I reran the build and got my next errors:

ros2_android_ws/src/eProsima/Fast-DDS/src/cpp/fastdds/topic/DDSSQLFilter/DDSFilterValue.hpp:22:10: fatal error: fastcdr/cdr/fixed_size_string.hpp: No such file or directory
   22 | #include <fastcdr/cdr/fixed_size_string.hpp>
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Indeed,

$ find . -name "fixed_size_string.hpp"

yields nothing, and I can't find anything related to that in eProsima/Fast-CDR. It may be, that this header needs to be acquired from somewhere else. I did some searching and found out, that we are checked out to an ancient release v1.0.20 of Fast-CDR. I checked out to the latest release and it works.

I got the same errors back about the jni.h, and I "violently" added these include directories in ros2-java/ros2_java/rcljava_common/CMakeLists.txt:

target_include_directories(${PROJECT_NAME}
  PUBLIC
  ${JNI_INCLUDE_DIRS}
  /usr/lib/jvm/jdk-21.0.4-oracle-x64/include/
  /usr/lib/jvm/jdk-21.0.4-oracle-x64/include/linux
  )

then I got past everything else except this in rcljava_common package:

warning: [options] bootstrap class path not set in conjunction with -source 6
error: Source option 6 is no longer supported. Use 8 or later.
error: Target option 6 is no longer supported. Use 8 or later.
gmake[2]: *** [CMakeFiles/rcljava_common_jar.dir/build.make:92: CMakeFiles/rcljava_common_jar.dir/java_compiled_rcljava_common_jar] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:154: CMakeFiles/rcljava_common_jar.dir/all] Error 2
gmake[1]: *** Waiting for unfinished jobs....
gmake: *** [Makefile:146: all] Error 2
---

I suspect a java version mismatch somewhere. I tried

$ export ANDROID_NATIVE_API_LEVEL=android-34

but that didn't help.

Hyrtsi commented 1 month ago

I may have to change the jdk version to something else.