Skip to content

Commit 3a618a1

Browse files
authored
Merge pull request #41 from RobotecAI/ubuntu_standalone
Ubuntu standalone
2 parents bf195c8 + bfec45f commit 3a618a1

File tree

6 files changed

+260
-19
lines changed

6 files changed

+260
-19
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ log
33
build
44
.idea
55
src/ros2cs
6+
**/metadata*.xml
67
src/Ros2ForUnity/Plugins
78
!src/Ros2ForUnity/Plugins/.gitkeep

build.ps1

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ if($clean_install) {
3434
Write-Host "Cleaning install directory..." -ForegroundColor White
3535
Remove-Item -Path "$scriptPath\install" -Force -Recurse -ErrorAction Ignore
3636
}
37+
38+
if($standalone) {}
39+
& "python3 $SCRIPTPATH\src\scripts\metadata_generator.py" --standalone
40+
} else {
41+
& "python3 $SCRIPTPATH\src\scripts\metadata_generator.py"
42+
}
43+
3744
& "$scriptPath\src\ros2cs\build.ps1" @options
3845
if($?) {
3946
md -Force $scriptPath\install\asset | Out-Null
@@ -42,6 +49,9 @@ if($?) {
4249
$plugin_path=Join-Path -Path $scriptPath -ChildPath "\install\asset\Ros2ForUnity\Plugins\"
4350
Write-Host "Deploying build to $plugin_path" -ForegroundColor Green
4451
& "$scriptPath\deploy_unity_plugins.ps1" $plugin_path
52+
53+
Copy-Item -Path $scriptPath\src\Ros2ForUnity\metadata_ros2cs.xml -Destination $scriptPath\install\asset\Ros2ForUnity\Plugins\Linux\x86_64\
54+
Copy-Item -Path $scriptPath\src\Ros2ForUnity\metadata_ros2cs.xml -Destination $scriptPath\install\asset\Ros2ForUnity\Plugins\
4555
} else {
4656
Write-Host "Ros2cs build failed!" -ForegroundColor Red
4757
exit 1

build.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,18 @@ if [ $CLEAN_INSTALL == 1 ]; then
5555
echo "Cleaning install directory..."
5656
rm -rf $SCRIPTPATH/install/*
5757
fi
58+
59+
if [ $STANDALONE == 1 ]; then
60+
python3 $SCRIPTPATH/src/scripts/metadata_generator.py --standalone
61+
else
62+
python3 $SCRIPTPATH/src/scripts/metadata_generator.py
63+
fi
64+
5865
if $SCRIPTPATH/src/ros2cs/build.sh $OPTIONS; then
5966
mkdir -p $SCRIPTPATH/install/asset && cp -R $SCRIPTPATH/src/Ros2ForUnity $SCRIPTPATH/install/asset/
6067
$SCRIPTPATH/deploy_unity_plugins.sh $SCRIPTPATH/install/asset/Ros2ForUnity/Plugins/
68+
cp $SCRIPTPATH/src/Ros2ForUnity/metadata_ros2cs.xml $SCRIPTPATH/install/asset/Ros2ForUnity/Plugins/Linux/x86_64/metadata_ros2cs.xml
69+
cp $SCRIPTPATH/src/Ros2ForUnity/metadata_ros2cs.xml $SCRIPTPATH/install/asset/Ros2ForUnity/Plugins/metadata_ros2cs.xml
6170
else
6271
echo "Ros2cs build failed!"
6372
exit 1
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2019-2022 Robotec.ai.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#if UNITY_EDITOR
16+
using System.IO;
17+
using UnityEngine;
18+
using UnityEditor;
19+
using UnityEditor.Build;
20+
using UnityEditor.Build.Reporting;
21+
22+
namespace ROS2
23+
{
24+
25+
/// <summary>
26+
/// An internal class responsible for installing ros2-for-unity metadata files
27+
/// </summary>
28+
internal class PostInstall : IPostprocessBuildWithReport
29+
{
30+
public int callbackOrder { get { return 0; } }
31+
public void OnPostprocessBuild(BuildReport report)
32+
{
33+
var r2fuMetadataName = "metadata_ros2_for_unity.xml";
34+
var r2csMetadataName = "metadata_ros2cs.xml";
35+
36+
// FileUtil.CopyFileOrDirectory: All file separators should be forward ones "/".
37+
var r2fuMeta = ROS2ForUnity.GetRos2ForUnityPath() + "/" + r2fuMetadataName;
38+
var r2csMeta = ROS2ForUnity.GetPluginPath() + "/" + r2csMetadataName;
39+
var outputDir = Directory.GetParent(report.summary.outputPath);
40+
var execFilename = Path.GetFileNameWithoutExtension(report.summary.outputPath);
41+
FileUtil.CopyFileOrDirectory(
42+
r2fuMeta, outputDir + "/" + execFilename + "_Data/" + r2fuMetadataName);
43+
FileUtil.CopyFileOrDirectory(
44+
r2csMeta, outputDir + "/" + execFilename + "_Data/Plugins/" + r2csMetadataName);
45+
}
46+
47+
}
48+
49+
}
50+
#endif

src/Ros2ForUnity/Scripts/ROS2ForUnity.cs

Lines changed: 118 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using System.Collections.Generic;
1818
using UnityEngine;
1919
using UnityEditor;
20+
using System.Xml;
2021

2122
namespace ROS2
2223
{
@@ -28,14 +29,16 @@ internal class ROS2ForUnity
2829
{
2930
private static bool isInitialized = false;
3031
private static string ros2ForUnityAssetFolderName = "Ros2ForUnity";
32+
private XmlDocument ros2csMetadata = new XmlDocument();
33+
private XmlDocument ros2ForUnityMetadata = new XmlDocument();
3134

3235
enum Platform
3336
{
3437
Windows,
3538
Linux
3639
}
3740

38-
private Platform GetOS()
41+
private static Platform GetOS()
3942
{
4043
if (Application.platform == RuntimePlatform.LinuxEditor || Application.platform == RuntimePlatform.LinuxPlayer)
4144
{
@@ -48,11 +51,11 @@ private Platform GetOS()
4851
throw new System.NotSupportedException("Only Linux and Windows are supported");
4952
}
5053

51-
private bool InEditor() {
54+
private static bool InEditor() {
5255
return Application.isEditor;
5356
}
5457

55-
private string GetOSName()
58+
private static string GetOSName()
5659
{
5760
switch (GetOS())
5861
{
@@ -80,7 +83,7 @@ private string GetEnvPathVariableValue()
8083
return Environment.GetEnvironmentVariable(GetEnvPathVariableName());
8184
}
8285

83-
private string GetPluginPath()
86+
public static string GetRos2ForUnityPath()
8487
{
8588
char separator = Path.DirectorySeparatorChar;
8689
string appDataPath = Application.dataPath;
@@ -89,6 +92,14 @@ private string GetPluginPath()
8992
if (InEditor()) {
9093
pluginPath += separator + ros2ForUnityAssetFolderName;
9194
}
95+
return pluginPath;
96+
}
97+
98+
public static string GetPluginPath()
99+
{
100+
char separator = Path.DirectorySeparatorChar;
101+
string ros2ForUnityPath = GetRos2ForUnityPath();
102+
string pluginPath = ros2ForUnityPath;
92103

93104
pluginPath += separator + "Plugins";
94105

@@ -116,7 +127,7 @@ private string GetPluginPath()
116127
/// Note that on Linux, LD_LIBRARY_PATH as used for dlopen() is determined on process start and this change won't
117128
/// affect it. Ros2 looks for rmw implementation based on this variable (independently) and the change
118129
/// is effective for this process, however rmw implementation's dependencies itself are loaded by dynamic linker
119-
/// anyway so setting it for Linux is pointless.
130+
/// anyway so setting it for Linux is pointless.
120131
/// </description>
121132
private void SetEnvPathVariable()
122133
{
@@ -132,16 +143,69 @@ private void SetEnvPathVariable()
132143
Environment.SetEnvironmentVariable(GetEnvPathVariableName(), pluginPath + envPathSep + currentPath);
133144
}
134145

146+
public bool IsStandalone() {
147+
return Convert.ToBoolean(Convert.ToInt16(GetMetadataValue(ros2csMetadata, "/ros2cs/standalone")));
148+
}
149+
150+
public string GetROSVersion()
151+
{
152+
string ros2SourcedCodename = GetROSVersionSourced();
153+
string ros2FromRos4UMetadata = GetMetadataValue(ros2ForUnityMetadata, "/ros2_for_unity/ros2");
154+
155+
// Sourced ROS2 libs takes priority
156+
if (string.IsNullOrEmpty(ros2SourcedCodename)) {
157+
return ros2FromRos4UMetadata;
158+
}
159+
160+
return ros2SourcedCodename;
161+
}
162+
163+
/// <summary>
164+
/// Checks if both ros2cs and ros2-for-unity were build for the same ros version as well as
165+
/// the current sourced ros version matches ros2cs binaries.
166+
/// </summary>
167+
public void CheckIntegrity()
168+
{
169+
string ros2SourcedCodename = GetROSVersionSourced();
170+
string ros2FromRos2csMetadata = GetMetadataValue(ros2csMetadata, "/ros2cs/ros2");
171+
string ros2FromRos4UMetadata = GetMetadataValue(ros2ForUnityMetadata, "/ros2_for_unity/ros2");
172+
173+
if (ros2FromRos4UMetadata != ros2FromRos2csMetadata) {
174+
Debug.LogError(
175+
"ROS2 versions in 'ros2cs' and 'ros2-for-unity' metadata files are not the same. " +
176+
"This is caused by mixing versions/builds. Plugin might not work correctly."
177+
);
178+
}
179+
180+
if(!IsStandalone() && ros2SourcedCodename != ros2FromRos2csMetadata) {
181+
Debug.LogError(
182+
"ROS2 version in 'ros2cs' metadata doesn't match currently sourced version. " +
183+
"This is caused by mixing versions/builds. Plugin might not work correctly."
184+
);
185+
}
186+
187+
if (IsStandalone() && !string.IsNullOrEmpty(ros2SourcedCodename)) {
188+
Debug.LogError(
189+
"You should not source ROS2 in 'ros2-for-unity' standalone build. " +
190+
"Plugin might not work correctly."
191+
);
192+
}
193+
}
194+
195+
public string GetROSVersionSourced()
196+
{
197+
return Environment.GetEnvironmentVariable("ROS_DISTRO");
198+
}
199+
135200
/// <summary>
136201
/// Check if the ros version is supported, only applicable to non-standalone plugin versions
137202
/// (i. e. without ros2 libraries included in the plugin).
138203
/// </summary>
139-
private string CheckROSVersionSourced()
204+
private void CheckROSSupport(string ros2Codename)
140205
{
141-
string currentVersion = Environment.GetEnvironmentVariable("ROS_DISTRO");
142206
List<string> supportedVersions = new List<string>() { "foxy", "galactic" };
143207
var supportedVersionsString = String.Join(", ", supportedVersions);
144-
if (string.IsNullOrEmpty(currentVersion))
208+
if (string.IsNullOrEmpty(ros2Codename))
145209
{
146210
string errMessage = "No ROS environment sourced. You need to source your ROS2 " + supportedVersionsString
147211
+ " environment before launching Unity (ROS_DISTRO env variable not found)";
@@ -155,9 +219,9 @@ private string CheckROSVersionSourced()
155219
#endif
156220
}
157221

158-
if (!supportedVersions.Contains(currentVersion))
222+
if (!supportedVersions.Contains(ros2Codename))
159223
{
160-
string errMessage = "Currently sourced ROS version differs from supported one. Sourced: " + currentVersion
224+
string errMessage = "Currently sourced ROS version differs from supported one. Sourced: " + ros2Codename
161225
+ ", supported: " + supportedVersionsString + ".";
162226
Debug.LogError(errMessage);
163227
#if UNITY_EDITOR
@@ -168,8 +232,6 @@ private string CheckROSVersionSourced()
168232
Application.Quit(ROS_BAD_VERSION_CODE);
169233
#endif
170234
}
171-
Debug.Log("Running with a supported ROS 2 version: " + currentVersion);
172-
return currentVersion;
173235
}
174236

175237
private void RegisterCtrlCHandler()
@@ -192,28 +254,65 @@ private void ConnectLoggers()
192254
Ros2csLogger.LogLevel = LogLevel.WARNING;
193255
}
194256

257+
private string GetMetadataValue(XmlDocument doc, string valuePath)
258+
{
259+
return doc.DocumentElement.SelectSingleNode(valuePath).InnerText;
260+
}
261+
262+
private void LoadMetadata()
263+
{
264+
char separator = Path.DirectorySeparatorChar;
265+
try
266+
{
267+
ros2csMetadata.Load(GetPluginPath() + separator + "metadata_ros2cs.xml");
268+
ros2ForUnityMetadata.Load(GetRos2ForUnityPath() + separator + "metadata_ros2_for_unity.xml");
269+
}
270+
catch (System.IO.FileNotFoundException)
271+
{
272+
var errMessage = "Could not find metadata files.";
273+
#if UNITY_EDITOR
274+
EditorApplication.isPlaying = false;
275+
throw new System.IO.FileNotFoundException(errMessage);
276+
#else
277+
const int NO_METADATA = 1;
278+
Application.Quit(NO_METADATA);
279+
#endif
280+
}
281+
}
282+
195283
internal ROS2ForUnity()
196284
{
197-
// TODO: Find a way to determine whether we run standalone build
285+
// Load metadata
286+
LoadMetadata();
287+
string currentRos2Version = GetROSVersion();
288+
string standalone = IsStandalone() ? "standalone" : "non-standalone";
289+
290+
// Self checks
291+
CheckROSSupport(currentRos2Version);
292+
CheckIntegrity();
293+
294+
// Library loading
198295
if (GetOS() == Platform.Windows) {
199296
// Windows version can run standalone, modifies PATH to ensure all plugins visibility
200297
SetEnvPathVariable();
201298
} else {
202-
// Linux version needs to have ros2 sourced, which is checked here. It also loads plugins by absolute path
203-
// since LD_LIBRARY_PATH cannot be set dynamically within the process for dlopen() which is used under the hood.
204-
// Since libraries are built with -rpath=".", dependencies will be correcly located within plugins directory.
205-
// For foxy, it is also necessary to use modified version of librcpputils to resolve custom msgs packages.
206-
string currentRosVersion = CheckROSVersionSourced();
299+
// For foxy, it is necessary to use modified version of librcpputils to resolve custom msgs packages.
207300
ROS2.GlobalVariables.absolutePath = GetPluginPath() + "/";
208-
if (currentRosVersion == "foxy") {
301+
if (currentRos2Version == "foxy") {
209302
ROS2.GlobalVariables.preloadLibrary = true;
210303
ROS2.GlobalVariables.preloadLibraryName = "librcpputils.so";
211304
}
212305
}
306+
307+
// Initialize
213308
ConnectLoggers();
214309
Ros2cs.Init();
215310
RegisterCtrlCHandler();
216311

312+
string rmwImpl = Ros2cs.GetRMWImplementation();
313+
314+
Debug.Log("ROS2 version: " + currentRos2Version + ". Build type: " + standalone + ". RMW: " + rmwImpl);
315+
217316
#if UNITY_EDITOR
218317
EditorApplication.playModeStateChanged += this.EditorPlayStateChanged;
219318
EditorApplication.quitting += this.DestroyROS2ForUnity;

0 commit comments

Comments
 (0)