diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 029c1a3..4507e00 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,10 +23,10 @@ jobs:
run: dotnet --info
- name: Restore dependencies
- run: dotnet restore MLXSharp.sln
+ run: dotnet restore MLXSharp.slnx
- name: Build C# projects (initial validation)
- run: dotnet build MLXSharp.sln --configuration Release --no-restore
+ run: dotnet build MLXSharp.slnx --configuration Release --no-restore
- name: Install CMake
run: brew install cmake
@@ -41,7 +41,7 @@ jobs:
ls -la src/MLXSharp.Native/runtimes/osx-arm64/native/
- name: Rebuild solution with native libraries
- run: dotnet build MLXSharp.sln --configuration Release --no-restore
+ run: dotnet build MLXSharp.slnx --configuration Release --no-restore
- name: Setup Python for HuggingFace
uses: actions/setup-python@v5
@@ -66,7 +66,7 @@ jobs:
ls -la "$TEST_OUTPUT/runtimes/osx-arm64/native/"
- name: Run tests
- run: dotnet test MLXSharp.sln --configuration Release --no-build --logger "trx;LogFileName=TestResults.trx" --results-directory artifacts/test-results
+ run: dotnet test MLXSharp.slnx --configuration Release --no-build --logger "trx;LogFileName=TestResults.trx" --results-directory artifacts/test-results
env:
MLXSHARP_MODEL_PATH: ${{ github.workspace }}/models/Qwen1.5-0.5B-Chat-4bit
@@ -78,22 +78,42 @@ jobs:
cp src/MLXSharp.Native/runtimes/osx-arm64/native/libmlxsharp.dylib artifacts/native/
- name: Pack MLXSharp library
- run: dotnet pack src/MLXSharp/MLXSharp.csproj --configuration Release --output artifacts/packages \
- -p:MLXSharpMacNativeBinary=$GITHUB_WORKSPACE/native/build/libmlxsharp.dylib
+ run: dotnet pack src/MLXSharp/MLXSharp.csproj --configuration Release --output artifacts/packages -p:MLXSharpMacNativeBinary=$GITHUB_WORKSPACE/native/build/libmlxsharp.dylib
- name: Pack MLXSharp.SemanticKernel library
- run: dotnet pack src/MLXSharp.SemanticKernel/MLXSharp.SemanticKernel.csproj --configuration Release --output artifacts/packages \
- -p:MLXSharpMacNativeBinary=$GITHUB_WORKSPACE/native/build/libmlxsharp.dylib
+ run: dotnet pack src/MLXSharp.SemanticKernel/MLXSharp.SemanticKernel.csproj --configuration Release --output artifacts/packages -p:MLXSharpMacNativeBinary=$GITHUB_WORKSPACE/native/build/libmlxsharp.dylib
- name: Verify package contains native libraries
run: |
echo "Checking package contents..."
- if unzip -l artifacts/packages/*.nupkg | grep -q "runtimes/osx-arm64/native/libmlxsharp.dylib"; then
- echo "✓ Native library found in package"
- else
- echo "✗ ERROR: Native library NOT found in package!"
- echo "Package contents:"
- unzip -l artifacts/packages/*.nupkg
+ shopt -s nullglob
+ packages=(artifacts/packages/*.nupkg)
+ if [ ${#packages[@]} -eq 0 ]; then
+ echo "✗ ERROR: No packages were produced"
+ exit 1
+ fi
+
+ missing=0
+ for package in "${packages[@]}"; do
+ echo "Inspecting ${package}"
+ filename=$(basename "${package}")
+ case "${filename}" in
+ MLXSharp.*.nupkg)
+ if unzip -l "${package}" | grep -q "runtimes/osx-arm64/native/libmlxsharp.dylib"; then
+ echo " ✓ Native library found"
+ else
+ echo " ✗ Native library NOT found"
+ unzip -l "${package}"
+ missing=1
+ fi
+ ;;
+ *)
+ echo " ↷ Skipping native check for ${filename}"
+ ;;
+ esac
+ done
+
+ if [ $missing -ne 0 ]; then
exit 1
fi
diff --git a/MLXSharp.sln b/MLXSharp.sln
deleted file mode 100644
index 11abacc..0000000
--- a/MLXSharp.sln
+++ /dev/null
@@ -1,84 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLXSharp", "src\MLXSharp\MLXSharp.csproj", "{69BB544C-9ADD-4561-8B9D-7ACED3B46296}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLXSharp.Tests", "src\MLXSharp.Tests\MLXSharp.Tests.csproj", "{8F2FA235-E636-4D11-A55D-450505BB8F19}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLXSharp.Native", "src\MLXSharp.Native\MLXSharp.Native.csproj", "{F5B45C67-1810-4A04-862F-C33A7DFAE4C2}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLXSharp.SemanticKernel", "src\MLXSharp.SemanticKernel\MLXSharp.SemanticKernel.csproj", "{BF201BBA-D607-4EF5-BF9B-766D89B43A4A}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Debug|x64.ActiveCfg = Debug|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Debug|x64.Build.0 = Debug|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Debug|x86.ActiveCfg = Debug|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Debug|x86.Build.0 = Debug|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Release|Any CPU.Build.0 = Release|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Release|x64.ActiveCfg = Release|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Release|x64.Build.0 = Release|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Release|x86.ActiveCfg = Release|Any CPU
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296}.Release|x86.Build.0 = Release|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Debug|x64.Build.0 = Debug|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Debug|x86.Build.0 = Debug|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Release|Any CPU.Build.0 = Release|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Release|x64.ActiveCfg = Release|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Release|x64.Build.0 = Release|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Release|x86.ActiveCfg = Release|Any CPU
- {8F2FA235-E636-4D11-A55D-450505BB8F19}.Release|x86.Build.0 = Release|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Debug|x64.Build.0 = Debug|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Debug|x86.Build.0 = Debug|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Release|Any CPU.Build.0 = Release|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Release|x64.ActiveCfg = Release|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Release|x64.Build.0 = Release|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Release|x86.ActiveCfg = Release|Any CPU
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2}.Release|x86.Build.0 = Release|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Debug|x64.Build.0 = Debug|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Debug|x86.Build.0 = Debug|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Release|Any CPU.Build.0 = Release|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Release|x64.ActiveCfg = Release|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Release|x64.Build.0 = Release|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Release|x86.ActiveCfg = Release|Any CPU
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {69BB544C-9ADD-4561-8B9D-7ACED3B46296} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {8F2FA235-E636-4D11-A55D-450505BB8F19} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {F5B45C67-1810-4A04-862F-C33A7DFAE4C2} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {BF201BBA-D607-4EF5-BF9B-766D89B43A4A} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- EndGlobalSection
-EndGlobal
diff --git a/MLXSharp.slnx b/MLXSharp.slnx
new file mode 100644
index 0000000..07b5992
--- /dev/null
+++ b/MLXSharp.slnx
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 041bea6..e307ba0 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,6 @@ The design mirrors the packaging approach from projects such as [LLamaSharp](htt
- `IChatClient`, `IEmbeddingGenerator`, and image generation helpers that adhere to the `Microsoft.Extensions.AI` abstractions.
- Builder-based backend configuration with a deterministic managed implementation for tests and a P/Invoke powered native backend.
- Native library resolver that probes application directories, `MLXSHARP_LIBRARY`, or packaged runtimes and loads `libmlxsharp` on demand.
-- `MLXSharp.Native` packaging project that ships stub binaries for CI (Linux x64 today) and a placeholder `osx-arm64` folder for the production MLX wrapper.
- Dependency injection extensions (`AddMlx`) in **MLXSharp** package.
- Semantic Kernel integration (`AddMlxChatCompletion`) in separate **MLXSharp.SemanticKernel** package.
- Integration test suite that exercises chat, embedding, image, and Semantic Kernel flows against both managed and native backends.
@@ -19,8 +18,8 @@ The design mirrors the packaging approach from projects such as [LLamaSharp](htt
├── extern/mlx # Git submodule with the official MLX sources
├── native/ # Native wrapper scaffold (CMake project)
├── src/MLXSharp/ # Managed library with Microsoft.Extensions.AI adapters
+├── src/MLXSharp.Native/ # Native runtime packaging project with stub binaries
├── src/MLXSharp.SemanticKernel/ # Semantic Kernel integration (separate package)
-├── src/MLXSharp.Native/ # NuGet-ready container for native binaries
└── src/MLXSharp.Tests/ # Integration tests covering DI and Semantic Kernel
```
@@ -81,10 +80,12 @@ dotnet add package MLXSharp
This package contains:
- Managed DLL with `Microsoft.Extensions.AI` implementations
-- Native libraries in `runtimes/{rid}/native/`:
- - `runtimes/linux-x64/native/libmlxsharp.so` - stub for CI/testing
+- Native assets in `runtimes/{rid}/native/`:
+ - `runtimes/linux-x64/native/libmlxsharp.so.b64` - Base64-encoded stub that `MlxNativeLibrary` expands for CI/testing
- `runtimes/osx-arm64/native/libmlxsharp.dylib` - built in CI on macOS
+`MlxNativeLibrary` materialises `libmlxsharp.so` from the encoded payload on first use so Git history stays free of binary blobs while tests retain deterministic behaviour.
+
### MLXSharp.SemanticKernel [](https://www.nuget.org/packages/MLXSharp.SemanticKernel)
Semantic Kernel integration:
diff --git a/src/MLXSharp.Native/README.md b/src/MLXSharp.Native/README.md
index 195db0a..590cbb6 100644
--- a/src/MLXSharp.Native/README.md
+++ b/src/MLXSharp.Native/README.md
@@ -1,7 +1,7 @@
# MLXSharp.Native
-This package mirrors the layout that MLXSharp expects when resolving native binaries.
-It ships the `libmlxsharp` stub that our managed layer uses during development and in automated tests.
-The Linux stub lives as a Base64-encoded payload (`libmlxsharp.so.b64`) so we can keep Git history free of binary blobs.
-`MlxNativeLibrary` expands the encoded payload to `libmlxsharp.so` automatically the first time the native backend loads.
-Drop the macOS build of the wrapper into `runtimes/osx-arm64/native/` before publishing a release build.
+This helper project mirrors the runtime layout that MLXSharp expects when probing for native binaries.
+It ships the stubbed `libmlxsharp` artefacts that our managed layer exercises during development and CI runs.
+The Linux build lives as a Base64-encoded payload (`libmlxsharp.so.b64`) so Git history stays free of large binary blobs.
+`MlxNativeLibrary` expands that payload to `libmlxsharp.so` on demand, while macOS builds should drop the compiled
+`libmlxsharp.dylib` into `runtimes/osx-arm64/native/` before packing a release.
diff --git a/src/MLXSharp.Native/runtimes/osx-arm64/native/README.txt b/src/MLXSharp.Native/runtimes/osx-arm64/native/README.txt
index f1accc5..07e6d0b 100644
--- a/src/MLXSharp.Native/runtimes/osx-arm64/native/README.txt
+++ b/src/MLXSharp.Native/runtimes/osx-arm64/native/README.txt
@@ -1 +1 @@
-Place the macOS arm64 build of libmlxsharp.dylib here before packing MLXSharp.Native for distribution.
+Place the macOS arm64 build of libmlxsharp.dylib here before packing MLXSharp for distribution.
diff --git a/src/MLXSharp/MLXSharp.csproj b/src/MLXSharp/MLXSharp.csproj
index 993772e..03e3aed 100644
--- a/src/MLXSharp/MLXSharp.csproj
+++ b/src/MLXSharp/MLXSharp.csproj
@@ -15,8 +15,11 @@
- $(MSBuildProjectDirectory)..\..\native\build\libmlxsharp.dylib
- ..\MLXSharp.Native\runtimes\osx-arm64\native\libmlxsharp.dylib
+ $(MSBuildThisFileDirectory)
+ $(MLXSharpProjectDirectory)..\MLXSharp.Native\runtimes
+ $(MLXSharpProjectDirectory)..\..\native\build\libmlxsharp.dylib
+ $(MLXSharpNativeRuntimeRoot)\osx-arm64\native\libmlxsharp.dylib
+ $([System.IO.Path]::GetDirectoryName('$(MLXSharpMacNativeDestination)'))
false
@@ -28,11 +31,24 @@
Condition="Exists('$(MLXSharpMacNativeBinary)')" />
+
+
+
+
+ true
+ runtimes/osx-arm64/native/%(Filename)%(Extension)
+ PreserveNewest
+ runtimes\osx-arm64\native\%(Filename)%(Extension)
+
+
+