Skip to content

Dev_PreProcDir

Mehmet Emre Çakal edited this page Oct 10, 2024 · 1 revision

C# Preprocessor Directives in ROS#

Preprocessor directives are used mainly for ROS version dependent behavior, i.e. when it is not possible or practical to dynamically change class behavior at runtime, the solution is built specifically for each ROS version. For more information about C# Preprocessor Directives, see the official .NET page.

.NET Integration

In the .NET solution, you can see preprocessor directives in each class under the RosSharp.RosBridgeClient.MessageTypes namespace, as they are all automatically generated via MessageGeneration. For example, see the Header.cs message type in the RosBridgeClient project:

Runtime\Libraries\RosBridgeClient\MessageTypes\ROS1\Std\msg\Header.cs:

#if !ROS2
namespace RosSharp.RosBridgeClient.MessageTypes.Std
{
    ...
        public Header()
        {
            this.seq = 0;
            this.stamp = new Time();
            this.frame_id = "";
        }
    ...
}
#endif

And compare it with:

Runtime\Libraries\RosBridgeClient\MessageTypes\ROS2\Std\msg\Header.cs:

#if ROS2
using RosSharp.RosBridgeClient.MessageTypes.BuiltinInterfaces;
namespace RosSharp.RosBridgeClient.MessageTypes.Std
{
    ...
        public Header()
        {
            this.stamp = new Time();
            this.frame_id = "";
        }
    ...
}
#endif

Both versions differ in their constructor, and additionally the ROS2 version depends on a different namespace which does not exist in ROS1. And considering the nature of ROS, we want both to be Std\msg\Header.cs at the same time, while accepting their differences, so they are compiled separately. In Visual Studio it is possible to configure a batch build and compile both versions at the same time (see the image below), but that's not the case for Unity.


Unity Integration

In Unity, this compilation is performed only once, for the version selected from the drop-down menu located in the RosConnector component. When a version change is triggered (manually or via OnInspectionGUI), the ROS2 define symbol (#define ROS2) is added to the EditorUserBuildSettings.selectedBuildTargetGroup via PlayerSettings.SetScriptingDefineSymbolsForGroup. Finally, the assembly builder is triggered with AssetDatabase.Refresh(). Of course, all necessary scripts will be recompiled and this process takes quite a long time.

com.siemens.ros-sharp\Editor\RosBridgeClient\RosConnectorEditor.cs:

// Toggle ROS Version
public static void ToggleROSVersion(RosVersion selectedROSVersion)
{
    string defineSymbolROS2 = "ROS2"; 

    BuildTargetGroup targetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
    string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup);

    // Remove ROS2 define symbol
    defines = defines.Replace($"{defineSymbolROS2};", "").Replace(defineSymbolROS2, "");

    // Add the define symbol for the selected ROS version (ROS2 is default if not present)
    string defineSymbol = selectedROSVersion == RosVersion.ROS1 ? "" : defineSymbolROS2;
    if (!string.IsNullOrEmpty(defineSymbol) && !defines.Contains(defineSymbol))
    {
        defines += $";{defineSymbol}";
    }

    // Set scripting define symbols
    PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, defines);

    // Execute Assembly Builder
    AssetDatabase.Refresh();
}

Why not build both in the first place and dynamically link like in .NET? Well, because Unity does not provide the latest stable versions of our dependencies, and we have to follow what they provide. This means that our DLLs would ask for different versions (e.g. System.Text.Json.dll) and throw errors unless we downgrade our dependencies. Yes, in theory it is possible to modify the Unity installation and use our preferred DLLs. In practice, however, this approach is neither very user-friendly nor very secure. So Unity compiles our scripts the way it wants, using its own built-in DLLs, and we do not deliberately try to downgrade ROS# just to follow Unity's old packages.


© Siemens AG, 2017-2024

Clone this wiki locally