We need these libraries:
- cpp_common
- rosconsole
- rosconsole_backend_interface
- rosconsole_log4cxx
- roscpp
- roscpp_serialization
- rostime
- xmlrpcpp
These libraries can be found in the ros_comm and roscpp_core packages. We can compile all of these into static / dynamic libraries and merge them into one (for static libraries).
In Unreal there is a macro check() for assertion, but there is also a function check() in Roscpp headers so it cannot compile.
We can use push/pop macro pragmas to disable the check() macro temporarily. Every time we use roscpp headers, we write such pragmas in the beginning of the cpp file:
#pragma pop_macro("check")
#undef check
#include <ros/ros.h>
#pragma push_macro("check")
The RTTI (Run time type information) is by default disabled in Unreal Build Tool and even if we force it to be true in UnrealEngine/Engine/Saved/UnrealBuildTool/BuildConfiguration.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<UEBuildConfiguration>
<bForceEnableRTTI>true</bForceEnableRTTI>
</UEBuildConfiguration>
...
it cannot enable RTTI for all Unreal source files. We need to manually modify the Engine/Source/Programs/UnrealBuildTool/Linux/LinuxToolChain.cs
static string GetRTTIFlag(CPPEnvironment CompileEnvironment)
{
string Result = " -frtti"; // always using rtti
return Result;
}
Unreal doesn't use C++ exception system to handle exceptions and disabled it in the UBT, but ROS needs the C++ exception handling. We need to enable it in Unreal Build Tool's configuration file UnrealEngine/Engine/Saved/UnrealBuildTool/BuildConfiguration.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<UEBuildConfiguration>
<bForceEnableRTTI>true</bForceEnableRTTI>
</UEBuildConfiguration>
...
Roscpp and its dependency libraries (including log4cxx, boost, etc. ) are using libstdc++ as the C++ STL library by default in Linux, and most of linux binaries are compiled using libstdc++, but Unreal is compiled and linked with libc++ rather than libstdc++ by default. So if we directly link libstdc++ libraries to Unreal there will be "undefined symbol" errors. It is not easy to compile all the roscpp and dependencies in libstdc++, since there are so many libstdc++-linked dependency binaries existing in Linux. So we just modified the Unreal build tool's source file to link the libstdc++.
private static bool ShouldUseLibcxx(string Architecture)
{
return false;
}
If we are going to use dynamic libraries, we need to set the LD_LIBRARY_PATH environment variable to let the dynamic linker find the dynamic libraries (libroscpp.so, etc. ) easily.
Add this line in the $HOME/.bashrc file:
export LD_LIBRARY_PATH=$HOME/Documents/UnrealProjects/UE4ROS/ThirdParty/Roscpp/DynLibraries:$LD_LIBRARY_PATH
Sometimes pointers that created by ROS can not be freed by Unreal's Memory management system correctly. We apply this patch to the MallocBinned.cpp file to solve the problem.
https://github.com/spatialos/RPGDemo/blob/master/0001-Make-linux-work-with-WorkerSdk.patch
After applying this patch, the ros library works in the debug mode, but it still cannot work in development mode. There are still memory errors (double free or corruption) in function ros::Subscription::negotiateConnection, where there is a delete operation inside. And in debug mode the shader cannot work: