diff --git a/src/CSnakes.Runtime.Tests/Properties/launchSettings.json b/src/CSnakes.Runtime.Tests/Properties/launchSettings.json new file mode 100644 index 00000000..7a01e998 --- /dev/null +++ b/src/CSnakes.Runtime.Tests/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "CSnakes.Runtime.Tests": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/src/CSnakes.Runtime/CPython/Init.cs b/src/CSnakes.Runtime/CPython/Init.cs index 621e3a6c..cbf35c7a 100644 --- a/src/CSnakes.Runtime/CPython/Init.cs +++ b/src/CSnakes.Runtime/CPython/Init.cs @@ -11,11 +11,13 @@ internal unsafe partial class CPythonAPI : IDisposable private static string? pythonLibraryPath = null; private static readonly object initLock = new(); - private bool disposedValue; + private readonly bool freeThreaded = false; + private bool disposedValue = false; - public CPythonAPI(string pythonLibraryPath) + public CPythonAPI(string pythonLibraryPath, bool freeThreaded = false) { CPythonAPI.pythonLibraryPath = pythonLibraryPath; + this.freeThreaded = freeThreaded; try { NativeLibrary.SetDllImportResolver(typeof(CPythonAPI).Assembly, DllImportResolver); diff --git a/src/CSnakes.Runtime/IServiceCollectionExtensions.cs b/src/CSnakes.Runtime/IServiceCollectionExtensions.cs index fb03354f..27f490c2 100644 --- a/src/CSnakes.Runtime/IServiceCollectionExtensions.cs +++ b/src/CSnakes.Runtime/IServiceCollectionExtensions.cs @@ -83,9 +83,9 @@ public static IPythonEnvironmentBuilder FromMacOSInstallerLocator(this IPythonEn return builder; } - public static IPythonEnvironmentBuilder FromSource(this IPythonEnvironmentBuilder builder, string folder, string version, bool debug = true) + public static IPythonEnvironmentBuilder FromSource(this IPythonEnvironmentBuilder builder, string folder, string version, bool debug = true, bool freeThreaded = false) { - builder.Services.AddSingleton(new SourceLocator(folder, version, debug)); + builder.Services.AddSingleton(new SourceLocator(folder, version, debug, freeThreaded)); return builder; } diff --git a/src/CSnakes.Runtime/Locators/PythonLocationMetadata.cs b/src/CSnakes.Runtime/Locators/PythonLocationMetadata.cs index 12879422..763d9f76 100644 --- a/src/CSnakes.Runtime/Locators/PythonLocationMetadata.cs +++ b/src/CSnakes.Runtime/Locators/PythonLocationMetadata.cs @@ -4,4 +4,4 @@ /// /// Path on disk where Python is to be loaded from. /// Version of Python being used from the location. -public sealed record PythonLocationMetadata(string Folder, string Version, bool Debug = false); +public sealed record PythonLocationMetadata(string Folder, string Version, bool Debug = false, bool FreeThreaded = false); diff --git a/src/CSnakes.Runtime/Locators/SourceLocator.cs b/src/CSnakes.Runtime/Locators/SourceLocator.cs index 08b63caf..7d93be93 100644 --- a/src/CSnakes.Runtime/Locators/SourceLocator.cs +++ b/src/CSnakes.Runtime/Locators/SourceLocator.cs @@ -2,7 +2,7 @@ namespace CSnakes.Runtime.Locators; -internal class SourceLocator(string folder, string version, bool debug = true) : PythonLocator(version: version) +internal class SourceLocator(string folder, string version, bool debug = true, bool freeThreaded = false) : PythonLocator(version: version) { public override PythonLocationMetadata LocatePython() { @@ -10,7 +10,8 @@ public override PythonLocationMetadata LocatePython() return new PythonLocationMetadata( buildFolder, version, - debug + debug, + freeThreaded ); } diff --git a/src/CSnakes.Runtime/Properties/launchSettings.json b/src/CSnakes.Runtime/Properties/launchSettings.json new file mode 100644 index 00000000..31e3c894 --- /dev/null +++ b/src/CSnakes.Runtime/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "CSnakes.Runtime": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/src/CSnakes.Runtime/PythonEnvironment.cs b/src/CSnakes.Runtime/PythonEnvironment.cs index 8c4c209f..85dbd6e5 100644 --- a/src/CSnakes.Runtime/PythonEnvironment.cs +++ b/src/CSnakes.Runtime/PythonEnvironment.cs @@ -138,11 +138,17 @@ private CPythonAPI SetupStandardLibrary(PythonLocationMetadata pythonLocationMet string pythonDll = string.Empty; string pythonPath = string.Empty; string pythonLocation = pythonLocationMetadata.Folder; + string suffix = String.Empty; + + if (pythonLocationMetadata.FreeThreaded) + { + suffix += "t"; + } // Add standard library to PYTHONPATH if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - string suffix = pythonLocationMetadata.Debug ? "_d" : string.Empty; + suffix += pythonLocationMetadata.Debug ? "_d" : string.Empty; pythonDll = Path.Combine(pythonLocation, $"python{versionPath}{suffix}.dll"); if (pythonLocationMetadata.Debug) { @@ -156,12 +162,12 @@ private CPythonAPI SetupStandardLibrary(PythonLocationMetadata pythonLocationMet } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - pythonDll = Path.Combine(pythonLocation, "lib", $"libpython{majorVersion}.dylib"); + pythonDll = Path.Combine(pythonLocation, "lib", $"libpython{majorVersion}{suffix}.dylib"); pythonPath = Path.Combine(pythonLocation, "lib", $"python{majorVersion}") + sep + Path.Combine(pythonLocation, "lib", $"python{majorVersion}", "lib-dynload"); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - pythonDll = Path.Combine(pythonLocation, "lib", $"libpython{majorVersion}.so"); + pythonDll = Path.Combine(pythonLocation, "lib", $"libpython{majorVersion}{suffix}.so"); pythonPath = Path.Combine(pythonLocation, "lib", $"python{majorVersion}") + sep + Path.Combine(pythonLocation, "lib", $"python{majorVersion}", "lib-dynload"); } else @@ -172,7 +178,7 @@ private CPythonAPI SetupStandardLibrary(PythonLocationMetadata pythonLocationMet Logger.LogInformation("Python DLL: {PythonDLL}", pythonDll); Logger.LogInformation("Python path: {PythonPath}", pythonPath); - var api = new CPythonAPI(pythonDll) + var api = new CPythonAPI(pythonDll, pythonLocationMetadata.FreeThreaded) { PythonPath = pythonPath };