Hi David, with the help of AI and some testbed app's I located the problem in the static RT() at line 469, a detailed report below:
Issue:
RT..cctor fails with ArgumentException when hosted in a native process (e.g. BricsCAD, AutoCAD) due to AppDomain.CurrentDomain.BaseDirectory returning empty string
Problem Description
When ClojureCLR is loaded as a plugin inside a native C++ host process (such as BricsCAD or AutoCAD) via their .NET plugin APIs, RT..cctor throws:
System.ArgumentException: Path "Clojure.Source.dll" is not an absolute path. (Parameter 'path')
at System.Reflection.Assembly.LoadFile(String path)
at clojure.lang.RT..cctor()
Root Cause
In Clojure/Clojure/Lib/RT.cs, the static constructor locates Clojure.Source.dll using:
csharpstring baseDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
try {
Assembly.LoadFile(Path.Combine(baseDir, "Clojure.Source.dll"));
}
catch (FileLoadException) { }
catch (FileNotFoundException) { }
When .NET is hosted inside a native C++ process, AppDomain.CurrentDomain.BaseDirectory returns an empty string rather than the application directory. This causes Path.Combine("", "Clojure.Source.dll") to return the bare relative filename "Clojure.Source.dll". On .NET 8, Assembly.LoadFile with a relative path throws ArgumentException immediately ā and crucially, ArgumentException is not in the catch list, so it propagates and permanently faults the RT type initializer.
On .NET Framework this worked accidentally because LoadFile with a relative path resolved against Environment.CurrentDirectory. On .NET 8 this was tightened to require absolute paths, exposing the latent bug.
Why console apps are unaffected
In a normal console app, AppDomain.CurrentDomain.BaseDirectory correctly returns the executable's directory, so Path.Combine produces a valid absolute path and LoadFile succeeds.
Fix
Replace AppDomain.CurrentDomain.BaseDirectory with typeof(RT).Assembly.Location, which always returns the correct absolute path to Clojure.dll regardless of how the CLR is hosted:
// Before:
string baseDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
// After:
string baseDir = Path.GetDirectoryName(typeof(RT).Assembly.Location);
Optionally also add ArgumentException to the catch block as a secondary safety net:
try {
Assembly.LoadFile(Path.Combine(baseDir, "Clojure.Source.dll"));
}
catch (ArgumentException) { } // add this - relative path in hosted contexts
catch (FileLoadException) { }
catch (FileNotFoundException) { }
File to change
Clojure/Clojure/Lib/RT.cs ā the static constructor RT()
Why typeof(RT).Assembly is the correct fix
typeof(RT).Assembly always refers to Clojure.dll itself ā the assembly that contains Clojure.Source.dll alongside it
It is unaffected by how the CLR is hosted or what the current process is
AppDomain.BaseDirectory is a process-level concept that is meaningless when .NET is a guest inside a native host
This is consistent with how other assemblies in the codebase locate their resources
Environment
ClojureCLR NuGet package version: 1.12.2
.NET version: net8.0
Host process: BricsCAD V26 (native C++ exe hosting .NET 8 via plugin API)
Platform: Windows x64
hope that helps, thanks for all of your hard work, cheers
Mick