Skip to content

Commit e74d9aa

Browse files
committed
build MLX, Cmlx via xcodeproj as a framework
tests passing with ml-explore/mlx#2702 locally applied expose C++ API
1 parent b1e8076 commit e74d9aa

File tree

89 files changed

+47221
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+47221
-13
lines changed

.github/scripts/run-xcode-tests.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
3+
BUILD_DIR=`xcodebuild -configuration Debug -showBuildSettings -scheme MLX | grep 'BUILT_PRODUCTS_DIR = /' | sed -e 's/^[^=]*= //g' | head -1`
4+
5+
# rpath points to PackageFrameworks so link it to the built products
6+
(cd $BUILD_DIR/PackageFrameworks; ln -s ../*.framework .)
7+
8+
xcrun xctest "$BUILD_DIR/MLXTests.xctest"

.github/workflows/pull_request.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787
run: |
8888
brew install cmake ninja
8989
90-
- name: Build (Xcode, macOS)
90+
- name: Build SwiftPM (Xcode, macOS)
9191
shell: sh
9292
run: |
9393
xcodebuild -version
@@ -96,12 +96,23 @@ jobs:
9696
rm -rf ~/Library/Developer/Xcode/DerivedData/*
9797
xcodebuild build-for-testing -scheme mlx-swift-Package -destination 'platform=macOS'
9898
99-
- name: Run Tests (Xcode, macOS)
99+
- name: Run Tests SwiftPM (Xcode, macOS)
100100
shell: sh
101101
run: |
102102
xcrun xctest ~/Library/Developer/Xcode/DerivedData/mlx-swift-*/Build/Products/Debug/CmlxTests.xctest
103103
xcrun xctest ~/Library/Developer/Xcode/DerivedData/mlx-swift-*/Build/Products/Debug/MLXTests.xctest
104104
105+
- name: Build xcodeproj (Xcode, macOS)
106+
shell: sh
107+
run: |
108+
rm -rf ~/Library/Developer/Xcode/DerivedData/*
109+
cd xcode
110+
xcodebuild build-for-testing -scheme MLX -destination 'platform=macOS'
111+
112+
- name: Run Tests xcodeproj (Xcode, macOS)
113+
working-directory: xcode
114+
run: ../.github/scripts/run-xcode-tests.sh
115+
105116
- name: Upload test results
106117
if: failure()
107118
uses: actions/upload-artifact@v4

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ playground.xcworkspace
4141
Packages/
4242
Package.pins
4343
Package.resolved
44-
*.xcodeproj
4544
#
4645
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
4746
# hence it is not needed unless you have added a package configuration file to your project

MAINTENANCE.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,15 @@ pre-generating the source when updating the `mlx` version.
140140
2. Add any vendored dependencies as needed in `/vendor`
141141

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

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

146-
5. Wrap any new API with swift, update documentation, etc.
150+
6. Wrap any new API with swift, update documentation, etc.
147151

148-
6. Run `pre-commit run --all-files`
152+
7. Run `pre-commit run --all-files`
149153

150-
7. Make a PR
154+
8. Make a PR

Package.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ let package = Package(
3232
.target(
3333
name: "Cmlx",
3434
exclude: [
35+
// xcodeproj pieces
36+
"framework",
37+
"include-framework",
38+
3539
// vendor docs
3640
"vendor-README.md",
3741

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,25 @@ The ``MLX`` Swift package can be built and run from Xcode or SwiftPM. A CMake in
4646

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

49-
### Xcode
49+
### Xcode (1)
5050

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

54+
### XCode (2)
55+
56+
Note that the SwiftPM and XCode (1) methods build `MLX` as a Library, not as a framework.
57+
It is possible to construct a situation where YourApp -> MLX, YourApp -> YourFramework
58+
and YourFramework -> MLX. This would give two copies of MLX in the resulting process
59+
and it may not work as expected.
60+
61+
If this cannot be avoided, either by making YourFramework a Library or having YourApp
62+
_not_ link MLX, you can use the `xcode/MLX.xcodeproj` to build MLX as a _Framework_.
63+
This will require `mlx-swift` to be checked out adjacent or inside your project,
64+
possibly using git submodules, and dragging the mlx-swift/xcode/MLX.xcodeproj into
65+
your project. Once that is done your application can build and link MLX and related
66+
as Frameworks.
67+
5468
### SwiftPM
5569

5670
To use ``MLX`` with SwiftPM you can add this to your `Package.swift`:

README.xcodeproj.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
See `xcode/MLX.xcodeproj` and [MAINTENANCE.md].
2+
3+
# Cmlx
4+
5+
This is set up to build roughly how Package.swift builds.
6+
7+
- Look at Project -> Cmlx -> Build Phases
8+
- remove all Project headers
9+
- remove all Copy Bundle Resources
10+
- remove any files that should not be built from the Target membership, e.g the items in `exclude`
11+
12+
Public headers are in `include-framework` and this is managed by tools/update-mlx
13+
14+
Settings, including header search paths are in xcode/xcconfig.
15+
16+
## Updating
17+
18+
After updating the mlx/mlx-c version the xcodeproj needs to be brought up to date.
19+
20+
- the headers in Cmlx/include-framework must all be public
21+
- no other headers in the project should be included as resources (public/private/project)
22+
- the easiest way to adjust is look at Project -> Cmlx -> Build Phases and then look at the Headers task
23+
- similarly there should be _no_ Copy Bundle Resources from the same section
24+
- compilation issues in .metal files typically mean they are new to the project and need to be removed from Cmlx target membership
25+
26+
# MLX, etc.
27+
28+
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.

Source/Cmlx/framework/Cmlx.m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// Copyright © 2025 Apple Inc. All rights reserved.
3+
//
4+
5+
#import <Foundation/Foundation.h>
6+
7+
// ObjC class to trigger loading as a NSBundle.allFrameworks
8+
@interface Cmlx: NSObject
9+
@end
10+
11+
@implementation Cmlx
12+
@end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include <Cmlx/mlx-c-mlx.h>
2+
#include <Cmlx/mlx-c-transforms_impl.h>
3+
#include <Cmlx/mlx-c-linalg.h>
4+
#include <Cmlx/mlx-c-fast.h>
5+
6+
#include <Cmlx/mlx-array.h>
7+
#include <Cmlx/mlx-backend-cuda-cuda.h>
8+
#include <Cmlx/mlx-backend-gpu-available.h>
9+
#include <Cmlx/mlx-backend-metal-metal.h>
10+
#include <Cmlx/mlx-compile.h>
11+
#include <Cmlx/mlx-device.h>
12+
#include <Cmlx/mlx-distributed-distributed.h>
13+
#include <Cmlx/mlx-distributed-ops.h>
14+
#include <Cmlx/mlx-einsum.h>
15+
#include <Cmlx/mlx-export.h>
16+
#include <Cmlx/mlx-fast.h>
17+
#include <Cmlx/mlx-fft.h>
18+
#include <Cmlx/mlx-io.h>
19+
#include <Cmlx/mlx-linalg.h>
20+
#include <Cmlx/mlx-memory.h>
21+
#include <Cmlx/mlx-ops.h>
22+
#include <Cmlx/mlx-random.h>
23+
#include <Cmlx/mlx-stream.h>
24+
#include <Cmlx/mlx-transforms.h>
25+
#include <Cmlx/mlx-utils.h>
26+
#include <Cmlx/mlx-version.h>
27+
#include <Cmlx/mlx-allocator.h>
28+
#include <Cmlx/mlx-dtype.h>
29+
#include <Cmlx/mlx-event.h>
30+
#include <Cmlx/mlx-small_vector.h>
31+
#include <Cmlx/mlx-types-complex.h>
32+
#include <Cmlx/mlx-types-half_types.h>
33+
#include <Cmlx/mlx-types-bf16.h>
34+
#include <Cmlx/mlx-io-load.h>
35+
#include <Cmlx/mlx-export_impl.h>
36+
#include <Cmlx/mlx-threadpool.h>
37+
#include <Cmlx/mlx-scheduler.h>
38+
#include <Cmlx/mlx-primitives.h>
39+
#include <Cmlx/mlx-backend-metal-device.h>
40+
#include <Cmlx/mlx-backend-metal-utils.h>
41+
#include <Cmlx/mlx-backend-common-utils.h>
42+
#include <Cmlx/mlx-backend-cpu-encoder.h>
43+
#include <Cmlx/mlx-backend-gpu-eval.h>
44+
#include <Cmlx/Metal.hpp>

0 commit comments

Comments
 (0)