Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .github/scripts/run-xcode-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh

BUILD_DIR=`xcodebuild -configuration Debug -showBuildSettings -scheme MLX | grep 'BUILT_PRODUCTS_DIR = /' | sed -e 's/^[^=]*= //g' | head -1`

# rpath points to PackageFrameworks so link it to the built products
(cd $BUILD_DIR/PackageFrameworks; ln -s ../*.framework .)

xcrun xctest "$BUILD_DIR/MLXTests.xctest"
15 changes: 13 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
run: |
brew install cmake ninja

- name: Build (Xcode, macOS)
- name: Build SwiftPM (Xcode, macOS)
shell: sh
run: |
xcodebuild -version
Expand All @@ -96,12 +96,23 @@ jobs:
rm -rf ~/Library/Developer/Xcode/DerivedData/*
xcodebuild build-for-testing -scheme mlx-swift-Package -destination 'platform=macOS'

- name: Run Tests (Xcode, macOS)
- name: Run Tests SwiftPM (Xcode, macOS)
shell: sh
run: |
xcrun xctest ~/Library/Developer/Xcode/DerivedData/mlx-swift-*/Build/Products/Debug/CmlxTests.xctest
xcrun xctest ~/Library/Developer/Xcode/DerivedData/mlx-swift-*/Build/Products/Debug/MLXTests.xctest

- name: Build xcodeproj (Xcode, macOS)
shell: sh
run: |
rm -rf ~/Library/Developer/Xcode/DerivedData/*
cd xcode
xcodebuild build-for-testing -scheme MLX -destination 'platform=macOS'

- name: Run Tests xcodeproj (Xcode, macOS)
working-directory: xcode
run: ../.github/scripts/run-xcode-tests.sh

- name: Upload test results
if: failure()
uses: actions/upload-artifact@v4
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ playground.xcworkspace
Packages/
Package.pins
Package.resolved
*.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
Expand Down
42 changes: 38 additions & 4 deletions MAINTENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,45 @@ pre-generating the source when updating the `mlx` version.
2. Add any vendored dependencies as needed in `/vendor`

3. Regenerate any build-time source: `./tools/update-mlx.sh`
- this updates headers in Source/Cmlx/include
- this updates headers in Source/Cmlx/include-framework
- this generates various files in Source/Cmlx/mlx-generated

4. Fix any build issues
4. Fix any build issues with SwiftPM build (opening Package.swift)
5. Fix any build issues with xcodeproj build (opening xcode/MLX.codeproj), see also [README.xcodeproj.md]

5. Wrap any new API with swift, update documentation, etc.
6. Wrap any new API with swift, update documentation, etc.

6. Run `pre-commit run --all-files`
7. Run `pre-commit run --all-files`

8. Make a PR

## Updating `xcode/MLX.xcodeproj`

### Updating

After updating the mlx/mlx-c version the xcodeproj needs to be brought up to date.

- the headers in Cmlx/include-framework must all be public
- no other headers in the project should be included as resources (public/private/project)
- the easiest way to adjust is look at Project -> Cmlx -> Build Phases and then look at the Headers task
- similarly there should be _no_ Copy Bundle Resources from the same section
- compilation issues in .metal files typically mean they are new to the project and need to be removed from Cmlx target membership

### Cmlx

This is set up to build roughly how Package.swift builds.

- Look at Project -> Cmlx -> Build Phases
- remove all Project headers
- remove all Copy Bundle Resources
- remove any files that should not be built from the Target membership, e.g the items in `exclude`

Public headers are in `include-framework` and this is managed by tools/update-mlx

Settings, including header search paths are in xcode/xcconfig.

### MLX, etc.

These are just normal frameworks that link to Cmlx and others as needed. The source files are all swift and there are no special settings needed.

7. Make a PR
4 changes: 4 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ let package = Package(
.target(
name: "Cmlx",
exclude: [
// xcodeproj pieces
"framework",
"include-framework",

// vendor docs
"vendor-README.md",

Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,25 @@ The ``MLX`` Swift package can be built and run from Xcode or SwiftPM. A CMake in

More details are in the [documentation](https://swiftpackageindex.com/ml-explore/mlx-swift/main/documentation/mlx/install).

### Xcode
### Xcode (1)

In Xcode you can add `https://github.com/ml-explore/mlx-swift.git` as a package
dependency and link `MLX`, `MLXNN`, `MLXOptimizers` and `MLXRandom` as needed.

### XCode (2)

Note that the SwiftPM and XCode (1) methods build `MLX` as a Library, not as a framework.
It is possible to construct a situation where YourApp -> MLX, YourApp -> YourFramework
and YourFramework -> MLX. This would give two copies of MLX in the resulting process
and it may not work as expected.

If this cannot be avoided, either by making YourFramework a Library or having YourApp
_not_ link MLX, you can use the `xcode/MLX.xcodeproj` to build MLX as a _Framework_.
This will require `mlx-swift` to be checked out adjacent or inside your project,
possibly using git submodules, and dragging the `mlx-swift/xcode/MLX.xcodeproj` into
your project. Once that is done your application can build and link MLX and related
as Frameworks.

### SwiftPM

To use ``MLX`` with SwiftPM you can add this to your `Package.swift`:
Expand Down
12 changes: 12 additions & 0 deletions Source/Cmlx/framework/Cmlx.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Copyright © 2025 Apple Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

// ObjC class to trigger loading as a NSBundle.allFrameworks
@interface Cmlx: NSObject
@end

@implementation Cmlx
@end
45 changes: 45 additions & 0 deletions Source/Cmlx/include-framework/Cmlx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <Cmlx/mlx-c-mlx.h>
#include <Cmlx/mlx-c-transforms_impl.h>
#include <Cmlx/mlx-c-linalg.h>
#include <Cmlx/mlx-c-fast.h>

#include <Cmlx/mlx-array.h>
#include <Cmlx/mlx-backend-cuda-cuda.h>
#include <Cmlx/mlx-backend-gpu-available.h>
#include <Cmlx/mlx-backend-metal-metal.h>
#include <Cmlx/mlx-compile.h>
#include <Cmlx/mlx-device.h>
#include <Cmlx/mlx-distributed-distributed.h>
#include <Cmlx/mlx-distributed-ops.h>
#include <Cmlx/mlx-einsum.h>
#include <Cmlx/mlx-export.h>
#include <Cmlx/mlx-fast.h>
#include <Cmlx/mlx-fft.h>
#include <Cmlx/mlx-io.h>
#include <Cmlx/mlx-linalg.h>
#include <Cmlx/mlx-memory.h>
#include <Cmlx/mlx-ops.h>
#include <Cmlx/mlx-random.h>
#include <Cmlx/mlx-stream.h>
#include <Cmlx/mlx-transforms.h>
#include <Cmlx/mlx-utils.h>
#include <Cmlx/mlx-version.h>
#include <Cmlx/mlx-allocator.h>
#include <Cmlx/mlx-dtype.h>
#include <Cmlx/mlx-event.h>
#include <Cmlx/mlx-small_vector.h>
#include <Cmlx/mlx-types-complex.h>
#include <Cmlx/mlx-types-half_types.h>
#include <Cmlx/mlx-types-bf16.h>
#include <Cmlx/mlx-types-fp16.h>
#include <Cmlx/mlx-io-load.h>
#include <Cmlx/mlx-export_impl.h>
#include <Cmlx/mlx-threadpool.h>
#include <Cmlx/mlx-scheduler.h>
#include <Cmlx/mlx-primitives.h>
#include <Cmlx/mlx-backend-metal-device.h>
#include <Cmlx/mlx-backend-metal-utils.h>
#include <Cmlx/mlx-backend-common-utils.h>
#include <Cmlx/mlx-backend-cpu-encoder.h>
#include <Cmlx/mlx-backend-gpu-eval.h>
#include <Cmlx/Metal.hpp>
Loading