Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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

Expand Down
84 changes: 0 additions & 84 deletions MLXSharp.sln

This file was deleted.

13 changes: 13 additions & 0 deletions MLXSharp.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Solution>
<Configurations>
<Platform Name="Any CPU" />
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Folder Name="/src/">
<Project Path="src/MLXSharp.Native/MLXSharp.Native.csproj" />
<Project Path="src/MLXSharp.SemanticKernel/MLXSharp.SemanticKernel.csproj" />
<Project Path="src/MLXSharp.Tests/MLXSharp.Tests.csproj" />
<Project Path="src/MLXSharp/MLXSharp.csproj" />
</Folder>
</Solution>
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ The design mirrors the packaging approach from projects such as [LLamaSharp](htt
- `IChatClient`, `IEmbeddingGenerator<string, Embedding<float)>`, 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.
Expand All @@ -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
```

Expand Down Expand Up @@ -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 [![NuGet](https://img.shields.io/nuget/v/MLXSharp.SemanticKernel.svg)](https://www.nuget.org/packages/MLXSharp.SemanticKernel)

Semantic Kernel integration:
Expand Down
10 changes: 5 additions & 5 deletions src/MLXSharp.Native/README.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion src/MLXSharp.Native/runtimes/osx-arm64/native/README.txt
Original file line number Diff line number Diff line change
@@ -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.
20 changes: 18 additions & 2 deletions src/MLXSharp/MLXSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
</ItemGroup>

<PropertyGroup>
<MLXSharpMacNativeBinary Condition="'$(MLXSharpMacNativeBinary)' == ''">$(MSBuildProjectDirectory)..\..\native\build\libmlxsharp.dylib</MLXSharpMacNativeBinary>
<MLXSharpMacNativeDestination>..\MLXSharp.Native\runtimes\osx-arm64\native\libmlxsharp.dylib</MLXSharpMacNativeDestination>
<MLXSharpProjectDirectory>$(MSBuildThisFileDirectory)</MLXSharpProjectDirectory>
<MLXSharpNativeRuntimeRoot>$(MLXSharpProjectDirectory)..\MLXSharp.Native\runtimes</MLXSharpNativeRuntimeRoot>
<MLXSharpMacNativeBinary Condition="'$(MLXSharpMacNativeBinary)' == ''">$(MLXSharpProjectDirectory)..\..\native\build\libmlxsharp.dylib</MLXSharpMacNativeBinary>
<MLXSharpMacNativeDestination>$(MLXSharpNativeRuntimeRoot)\osx-arm64\native\libmlxsharp.dylib</MLXSharpMacNativeDestination>
<MLXSharpMacNativeDestinationDir>$([System.IO.Path]::GetDirectoryName('$(MLXSharpMacNativeDestination)'))</MLXSharpMacNativeDestinationDir>
<MLXSharpSkipMacNativeValidation Condition="'$(MLXSharpSkipMacNativeValidation)' == ''">false</MLXSharpSkipMacNativeValidation>
</PropertyGroup>

Expand All @@ -28,11 +31,24 @@
Condition="Exists('$(MLXSharpMacNativeBinary)')" />
</ItemGroup>

<MakeDir Directories="$(MLXSharpMacNativeDestinationDir)"
Condition="'$(MLXSharpMacNativeDestinationDir)' != ''" />

<Copy SourceFiles="@(_MacNativeSource)"
DestinationFiles="$(MLXSharpMacNativeDestination)"
SkipUnchangedFiles="true"
Condition="'@(_MacNativeSource)' != ''" />

<ItemGroup>
<None Include="$(MLXSharpMacNativeDestination)"
Condition="Exists('$(MLXSharpMacNativeDestination)')">
<Pack>true</Pack>
<PackagePath>runtimes/osx-arm64/native/%(Filename)%(Extension)</PackagePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>runtimes\osx-arm64\native\%(Filename)%(Extension)</Link>
</None>
</ItemGroup>

<Error Condition="'$(MLXSharpSkipMacNativeValidation)' != 'true' and !Exists('$(MLXSharpMacNativeDestination)')"
Text="libmlxsharp.dylib is missing. Build the native library or supply MLXSharpMacNativeBinary before packing." />
</Target>
Expand Down