diff --git a/.vscode/launch.json b/.vscode/launch.json
index 0544265c..aa5aa176 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -6,7 +6,8 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build Hops",
- "program": "/Applications/RhinoWIP.app/Contents/MacOS/Rhinoceros",
+ // "program": "/Applications/Rhino 8.app/Contents/MacOS/Rhinoceros",
+ "program": "/Users/curtis/Library/Developer/Xcode/DerivedData/MacRhino-dalqjlsjnqqsltdayygnhqhgntxb/Build/Products/Debug/Rhinoceros.app/Contents/MacOS/Rhinoceros",
"args": [],
"env": {
"GRASSHOPPER_PLUGINS": "${workspaceFolder}/src/hops/bin/Debug/Hops.gha"
@@ -45,13 +46,49 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build",
- "program": "${workspaceFolder}/src/bin/Debug/compute.geometry/compute.geometry.exe",
- "targetArchitecture": "x86_64",
+ "windows": {
+ "program": "${workspaceFolder}/src/bin/Debug/compute.geometry/compute.geometry.exe",
+ "targetArchitecture": "x86_64",
+ },
+ "osx": {
+ "program": "${workspaceFolder}/src/bin/Debug/compute.geometry/osx-arm64/compute.geometry",
+ "env": {
+ // "DYLD_LIBRARY_PATH": "/Users/curtis/Library/Developer/Xcode/DerivedData/MacRhino-dalqjlsjnqqsltdayygnhqhgntxb/Build/Products/Debug/Rhinoceros.app/Contents/Frameworks"
+ "DYLD_LIBRARY_PATH": "/Applications/Rhino 8.app/Contents/Frameworks"
+ }
+ },
"justMyCode": false,
"args": [],
"cwd": "${workspaceFolder}",
- "console": "internalConsole"
- }
+ "console": "integratedTerminal",
+
+ },
+ {
+ "name": "Launch compute.geometry C++",
+ "type": "cppdbg",
+ "request": "launch",
+ "preLaunchTask": "Build",
+ "osx": {
+ "program": "${workspaceFolder}/src/bin/Debug/compute.geometry/compute.geometry",
+ },
+ "args": [
+ // "-runscript=\"grasshopper\""
+ ],
+ "stopAtEntry": false,
+ "targetArchitecture": "arm64",
+ "cwd": "${workspaceFolder}/src/bin/Debug/compute.geometry",
+ "externalConsole": false,
+ "miDebuggerArgs": "--local-lldbinit ",
+ "MIMode": "lldb",
+ "environment": [
+ { "name": "DYLD_LIBRARY_PATH", "value": "/Users/curtis/Library/Developer/Xcode/DerivedData/MacRhino-dalqjlsjnqqsltdayygnhqhgntxb/Build/Products/Debug/Rhinoceros.app/Contents/Frameworks"}
+ { "name": "DOTNET_gcConcurrent", "value": "0" },
+ { "name": "DOTNET_EnableDiagnostics", "value": "0" },
+ { "name": "DOTNET_TC_QuickJit", "value": "1" },
+ // { "name": "DYLD_PRINT_LIBRARIES", "value": "1" }
+ ]
+ },
+
],
"compounds": []
}
\ No newline at end of file
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 00000000..1162eecd
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,8 @@
+
+
+
+ NU1701;NU1702
+ True
+
+
+
diff --git a/src/compute.geometry/Program.cs b/src/compute.geometry/Program.cs
index 85878adf..b3ee92ff 100644
--- a/src/compute.geometry/Program.cs
+++ b/src/compute.geometry/Program.cs
@@ -21,6 +21,9 @@ class Program
static void Main(string[] args)
{
+ if (RhinoInside.Resolver.RelaunchIfNeeded())
+ return;
+
Config.Load();
Logging.Init();
@@ -76,9 +79,9 @@ static void Main(string[] args)
Log.CloseAndFlush();
}
-
- static void ParseCommandLineArgs(string[] args)
- {
+
+ static void ParseCommandLineArgs(string[] args)
+ {
for (int i = 0; i < args.Length; i++)
{
string[] items = args[i].Split(':');
@@ -221,4 +224,4 @@ public void AddRoutes(IEndpointRouteBuilder app)
}
}
}
-}
+}
diff --git a/src/compute.geometry/Resolver.cs b/src/compute.geometry/Resolver.cs
index 8535c218..7bda48fd 100644
--- a/src/compute.geometry/Resolver.cs
+++ b/src/compute.geometry/Resolver.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -62,6 +63,10 @@ public static string AssemblyPathFromName(string systemDirectory, string name)
if (name == "Microsoft.macOS")
return null;
+ // only use the plain name to resolve assemblies, not the full name.
+ var assemblyName = new AssemblyName(name);
+ name = assemblyName.Name;
+
string path = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
@@ -98,6 +103,7 @@ static Assembly ResolveForRhinoAssemblies(object sender, ResolveEventArgs args)
static string FindRhinoSystemDirectory()
{
+
var major = Assembly.GetExecutingAssembly().GetName().Version.Major;
if (RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
@@ -134,9 +140,82 @@ static string FindRhinoSystemDirectory()
}
}
}
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ // TODO: detect the app location
+ var path = "/Applications/Rhino 8.app";
+ // var path = "/Users/curtis/Library/Developer/Xcode/DerivedData/MacRhino-dalqjlsjnqqsltdayygnhqhgntxb/Build/Products/Debug/Rhinoceros.app";
+
+ path = Path.Combine(path, "Contents", "Frameworks");
+ if (Directory.Exists(path))
+ {
+ return path;
+ }
+ }
+
return null;
}
+ public static bool RelaunchIfNeeded()
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ return false;
+
+ const string RHCORE_LIB = "RhCore.framework/Versions/A/RhCore";
+ bool found = false;
+ var libPaths = Environment.GetEnvironmentVariable("DYLD_LIBRARY_PATH")?.Split(";").ToList();
+ if (libPaths != null)
+ {
+ foreach (var libPath in libPaths)
+ {
+ if (File.Exists(Path.Combine(libPath, RHCORE_LIB)))
+ {
+ // found Rhino! Let's use it.
+ RhinoSystemDirectory = libPath;
+ Console.WriteLine($"Using Rhino from {RhinoSystemDirectory}");
+ found = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("DYLD_LIBRARY_PATH is null");
+ }
+
+ if (!found)
+ {
+ Console.WriteLine("DYLD_LIBRARY_PATH not set, launching as child process");
+
+ string systemDirectory = RhinoSystemDirectory;
+ if (!File.Exists(Path.Combine(systemDirectory, RHCORE_LIB)))
+ {
+ Console.WriteLine("Could not find Rhino");
+ return true;
+ }
+
+ // executable has the same name without the .dll extension
+ var executable = Assembly.GetEntryAssembly().Location;
+ if (executable.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
+ executable = executable.Substring(0, executable.Length - 4);
+ var startInfo = new ProcessStartInfo
+ {
+ UseShellExecute = false,
+ FileName = executable
+ };
+ foreach (var arg in Environment.GetCommandLineArgs())
+ {
+ startInfo.ArgumentList.Add(arg);
+ }
+ startInfo.Environment.Add("DYLD_LIBRARY_PATH", systemDirectory);
+ var process = Process.Start(startInfo);
+ process.WaitForExit();
+ return true;
+ }
+ return false;
+ }
+
public static void LoadRhino()
{
string systemDirectory = RhinoSystemDirectory;
@@ -158,13 +237,14 @@ public static void LoadRhino()
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
rhinoLibraryHandle = NativeLibrary.Load(Path.Combine(systemDirectory, "RhinoLibrary.framework/Versions/A/RhinoLibrary"));
+ AssemblyLoadContext.Default.ResolvingUnmanagedDll += ResolvingUnmanagedDll;
}
else
{
throw new Exception("Unsupported platform");
}
- nint handle = NativeLibrary.GetExport(rhinoLibraryHandle, "RhLibRegisterDotNetInitializer");
+ IntPtr handle = NativeLibrary.GetExport(rhinoLibraryHandle, "RhLibRegisterDotNetInitializer");
var setLoaderProc = Marshal.GetDelegateForFunctionPointer(handle);
//Action load = () => ExecuteLoadProc(rhinoContext);
@@ -173,6 +253,15 @@ public static void LoadRhino()
setLoaderProc(load);
}
+ private static IntPtr ResolvingUnmanagedDll(Assembly assembly, string unmanagedDllName)
+ {
+ var systemDirectory = RhinoSystemDirectory;
+ if (unmanagedDllName == "RhinoLibrary")
+ return NativeLibrary.Load(Path.Combine(systemDirectory, "RhinoLibrary.framework/Versions/A/RhinoLibrary"));
+
+ return IntPtr.Zero;
+ }
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void SetLoaderProc(Action p);
diff --git a/src/compute.geometry/compute.geometry.csproj b/src/compute.geometry/compute.geometry.csproj
index 2f334152..4c905367 100644
--- a/src/compute.geometry/compute.geometry.csproj
+++ b/src/compute.geometry/compute.geometry.csproj
@@ -1,30 +1,32 @@
- net7.0-windows
+ net7.0;net7.0-windows
compute.geometry
Exe
- win-x64
7.0.0
LatestMinor
- True
- True
False
False
False
- False
True
8.0.0
-
- ..\bin\Debug\$(AssemblyName)
+
+
+ win-x64
+ True
+ True
-
- ..\bin\Release\$(AssemblyName)
- ..\dist\$(AssemblyName)
+
+ osx-x64;osx-arm64
+ true
-
- True
+
+
+ ..\bin\$(Configuration)\$(AssemblyName)
+ ..\dist\$(AssemblyName)
+
@@ -46,6 +48,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/hops/HopsAppSettingsUserControl.cs b/src/hops/HopsAppSettingsUserControl.cs
index dff55f45..825d5122 100755
--- a/src/hops/HopsAppSettingsUserControl.cs
+++ b/src/hops/HopsAppSettingsUserControl.cs
@@ -46,14 +46,14 @@ public HopsAppSettingsUserControl()
};
_lblCacheCount.Text = $"({Hops.MemoryCache.EntryCount} items in cache)";
- if (Rhino.Runtime.HostUtils.RunningOnOSX)
- {
- _hideWorkerWindows.Visible = false;
- _launchWorkerAtStart.Visible = false;
- _childComputeCount.Visible = false;
- _updateChildCountButton.Visible = false;
- }
- else if (Rhino.Runtime.HostUtils.RunningOnWindows)
+ // if (Rhino.Runtime.HostUtils.RunningOnOSX)
+ // {
+ // _hideWorkerWindows.Visible = false;
+ // _launchWorkerAtStart.Visible = false;
+ // _childComputeCount.Visible = false;
+ // _updateChildCountButton.Visible = false;
+ // }
+ // else if (Rhino.Runtime.HostUtils.RunningOnWindows)
{
_hideWorkerWindows.Checked = HopsAppSettings.HideWorkerWindows;
_hideWorkerWindows.CheckedChanged += (s, e) =>
@@ -99,7 +99,7 @@ public HopsAppSettingsUserControl()
HopsUIHelper.MinGroupBoxHeight += extraSpace;
HopsUIHelper.MinControlHeight -= 32;
_gpboxFunctionMgr.Height += extraSpace;
- _gpboxFunctionMgr.Top -= 74;
+ // _gpboxFunctionMgr.Top -= 74;
Size = new System.Drawing.Size(Size.Width, _gpboxFunctionMgr.Bottom + 4);
}
diff --git a/src/hops/HopsComponent.cs b/src/hops/HopsComponent.cs
index d87649f2..f7f8c545 100644
--- a/src/hops/HopsComponent.cs
+++ b/src/hops/HopsComponent.cs
@@ -42,8 +42,8 @@ public class HopsComponent : GH_TaskCapableComponent, IGH_VariableParame
static HopsComponent()
{
- if (!Rhino.Runtime.HostUtils.RunningOnWindows)
- return;
+ // if (!Rhino.Runtime.HostUtils.RunningOnWindows)
+ // return;
if (Rhino.RhinoApp.IsRunningHeadless)
return;
if (Hops.HopsAppSettings.Servers.Length > 0)
diff --git a/src/hops/Servers.cs b/src/hops/Servers.cs
index 2c7531c8..9c21a743 100644
--- a/src/hops/Servers.cs
+++ b/src/hops/Servers.cs
@@ -2,7 +2,11 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Reflection;
+using System.Runtime.InteropServices;
+using Rhino;
+using Rhino.Runtime;
namespace Hops
{
@@ -118,7 +122,7 @@ static string GetComputeServerBaseUrl()
}
}
- if (string.IsNullOrEmpty(url) && Rhino.Runtime.HostUtils.RunningOnWindows)
+ if (string.IsNullOrEmpty(url)) // && Rhino.Runtime.HostUtils.RunningOnWindows)
{
_computeServerQueue = new Queue();
if (_computeServerQueue.Count == 0)
@@ -194,7 +198,9 @@ static void LaunchLocalRhinoCompute(Queue serverQueue, bool waitU
string pathToGha = typeof(Servers).Assembly.Location;
dir = System.IO.Path.GetDirectoryName(pathToGha);
}
- string pathToRhinoCompute = System.IO.Path.Combine(dir, "rhino.compute", "rhino.compute.exe");
+ string computeExecutable = HostUtils.RunningOnWindows ? "rhino.compute.exe" : "rhino.compute";
+ string runtimeIdentifier = HostUtils.RunningOnWindows ? "win-x64" : RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ? "osx-arm64" : "osx-x64";
+ string pathToRhinoCompute = System.IO.Path.Combine(dir, "rhino.compute", runtimeIdentifier, computeExecutable);
if (!System.IO.File.Exists(pathToRhinoCompute))
{
// debug builds are in net5.0 directory
@@ -208,6 +214,11 @@ static void LaunchLocalRhinoCompute(Queue serverQueue, bool waitU
if (childCount < 1)
childCount = 1;
int thisProc = Process.GetCurrentProcess().Id;
+
+ // Ensure we use this rhino when running on Mac
+ if (HostUtils.RunningOnOSX)
+ startInfo.Environment.Add("DYLD_LIBRARY_PATH", RhinoApp.GetExecutableDirectory().Parent.GetDirectories("Frameworks").FirstOrDefault()?.FullName);
+
startInfo.Arguments = $"--childof {thisProc} --childcount {childCount} --port {RhinoComputePort} --spawn-on-startup";
startInfo.WindowStyle = Hops.HopsAppSettings.HideWorkerWindows ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Minimized;
// uncomment next line to ease debugging
@@ -220,6 +231,18 @@ static void LaunchLocalRhinoCompute(Queue serverQueue, bool waitU
// set to false.
startInfo.UseShellExecute = true;
startInfo.CreateNoWindow = Hops.HopsAppSettings.HideWorkerWindows;
+
+ if (HostUtils.RunningOnOSX && !Hops.HopsAppSettings.HideWorkerWindows)
+ {
+ startInfo.UseShellExecute = false;
+ // launching Terminal.app clears out DYLD_LIBRARY_PATH and doesn't support passing arguments
+ startInfo.Environment["RHINO_COMPUTE_ARGUMENTS"] = startInfo.Arguments;
+ startInfo.Environment["RHINO_DYLD_LIBRARY_PATH"] = RhinoApp.GetExecutableDirectory().Parent.GetDirectories("Frameworks").FirstOrDefault()?.FullName;
+ startInfo.Arguments = $"-W -g -n -a Terminal.app \"{startInfo.FileName}\"";
+ startInfo.FileName = "/usr/bin/open";
+ }
+
+
string assemblyPath = Assembly.GetExecutingAssembly().Location;
// 6 April 2022 - S. Baer (COMPUTE-241)
// When grasshopper memory loads assemblies, the above line results in an
diff --git a/src/rhino.compute/ComputeChildren.cs b/src/rhino.compute/ComputeChildren.cs
index 1aab52c1..53711dbd 100644
--- a/src/rhino.compute/ComputeChildren.cs
+++ b/src/rhino.compute/ComputeChildren.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using Serilog;
namespace rhino.compute
@@ -153,12 +154,14 @@ static void LaunchCompute(Queue> processQueue, bool waitUnti
// compute.geometry is allowed to be either in:
// - a sibling directory named compute.geometry
// - a child directory named compute.geometry
- var parentDirectory = pathToThisAssembly.Directory.Parent;
- string pathToCompute = System.IO.Path.Combine(parentDirectory.FullName, "compute.geometry", "compute.geometry.exe");
+ var parentDirectory = pathToThisAssembly.Directory.Parent.Parent;
+ string geometryExecutable = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "compute.geometry.exe" : "compute.geometry";
+ string runtimeIdentifier = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win-x64" : RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ? "osx-arm64" : "osx-x64";
+ string pathToCompute = System.IO.Path.Combine(parentDirectory.FullName, "compute.geometry", runtimeIdentifier, geometryExecutable);
if (!System.IO.File.Exists(pathToCompute))
{
- pathToCompute = System.IO.Path.Combine(pathToThisAssembly.Directory.FullName, "compute.geometry", "compute.geometry.exe");
+ pathToCompute = System.IO.Path.Combine(pathToThisAssembly.Directory.FullName, "compute.geometry", runtimeIdentifier, geometryExecutable);
if (!System.IO.File.Exists(pathToCompute))
return;
}
@@ -188,6 +191,7 @@ static void LaunchCompute(Queue> processQueue, bool waitUnti
}
var startInfo = new ProcessStartInfo(pathToCompute);
+ startInfo.UseShellExecute = false;
var rhinoProcess = Process.GetCurrentProcess();
string commandLineArgs = $"-port:{port} -childof:{rhinoProcess.Id}";
if (!string.IsNullOrEmpty(RhinoSysDir))
diff --git a/src/rhino.compute/Program.cs b/src/rhino.compute/Program.cs
index c9af9262..244690cc 100644
--- a/src/rhino.compute/Program.cs
+++ b/src/rhino.compute/Program.cs
@@ -56,7 +56,7 @@ compute.geometry.exe processes will shut down and stop incurring core hour billi
static System.Diagnostics.Process _parentProcess;
static System.Timers.Timer _selfDestructTimer;
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
- .SetBasePath(Directory.GetCurrentDirectory())
+ .SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
@@ -71,6 +71,18 @@ public static void Main(string[] args)
.WriteTo.Console()
.CreateLogger();
+ var arguments = Environment.GetEnvironmentVariable("RHINO_COMPUTE_ARGUMENTS");
+ if (!string.IsNullOrEmpty(arguments))
+ {
+ args = arguments.Split(" ");
+ }
+
+ var rhinoPath = Environment.GetEnvironmentVariable("RHINO_DYLD_LIBRARY_PATH");
+ if (rhinoPath != null)
+ {
+ Environment.SetEnvironmentVariable("DYLD_LIBRARY_PATH", rhinoPath);
+ }
+
int port = -1;
Parser.Default.ParseArguments(args).WithParsed(o =>
{
diff --git a/src/rhino.compute/rhino.compute.csproj b/src/rhino.compute/rhino.compute.csproj
index d593a377..cadb3584 100644
--- a/src/rhino.compute/rhino.compute.csproj
+++ b/src/rhino.compute/rhino.compute.csproj
@@ -4,6 +4,7 @@
rhino.compute
Exe
win-x64
+ win-x64;osx-arm64;osx-x64
7.0.0
LatestMinor
false
@@ -11,7 +12,6 @@
true
True
False
- false
..\bin\Debug\$(AssemblyName)
@@ -20,7 +20,7 @@
..\bin\Release\$(AssemblyName)
TRACE;RHINO_COMPUTE
- ..\dist\$(AssemblyName)
+ ..\dist\$(OutputFramework)\$(AssemblyName)
@@ -35,4 +35,10 @@
+
+
+
+
+
+